From d7c32df05576bc45a1c0581547d33dafe3756c0c Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Mon, 17 Aug 2026 19:19:08 +0100 Subject: [PATCH] Add low-overhead GPU Nsight range profiling Signed-off-by: Joe Isaacs <2413449+joseph-isaacs@users.noreply.github.com> --- benchmarks/compress-bench/Cargo.toml | 2 +- benchmarks/compress-bench/README.md | 4 +++- benchmarks/compress-bench/src/gpu_vortex.rs | 13 ++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/benchmarks/compress-bench/Cargo.toml b/benchmarks/compress-bench/Cargo.toml index 0f233a3a22c..786b3d1724d 100644 --- a/benchmarks/compress-bench/Cargo.toml +++ b/benchmarks/compress-bench/Cargo.toml @@ -21,7 +21,7 @@ arrow-schema = { workspace = true } async-trait = { workspace = true } bytes = { workspace = true } clap = { workspace = true, features = ["derive"] } -cudarc = { workspace = true, optional = true } +cudarc = { workspace = true, features = ["nvtx"], optional = true } futures = { workspace = true } indicatif = { workspace = true } itertools = { workspace = true } diff --git a/benchmarks/compress-bench/README.md b/benchmarks/compress-bench/README.md index 1fb1e87e3fa..ac279cd6ecd 100644 --- a/benchmarks/compress-bench/README.md +++ b/benchmarks/compress-bench/README.md @@ -30,7 +30,9 @@ Set `VORTEX_GPU_PROFILE=wall` to emit one JSON record per decompression with fil decoded rows, batch and field-dispatch counts, host time for open, scan planning, reads, struct and field dispatch, and final synchronization, plus wall time grouped by full encoding tree. Set it to `gpu` to additionally bracket field dispatches with CUDA events and report each encoding group's -device-stream time. Profiling perturbs the measurement; rerun without it for comparison numbers. +device-stream time. `nsys` adds an NVTX range around each field while retaining encoding-tree +metrics; `nsys-ranges` omits tree construction for a lower-overhead Nsight Systems capture. +Profiling perturbs the measurement; rerun without it for comparison numbers. ```bash VORTEX_GPU_PROFILE=gpu cargo run -p compress-bench --profile release_debug \ diff --git a/benchmarks/compress-bench/src/gpu_vortex.rs b/benchmarks/compress-bench/src/gpu_vortex.rs index c86391f8454..64c080b3149 100644 --- a/benchmarks/compress-bench/src/gpu_vortex.rs +++ b/benchmarks/compress-bench/src/gpu_vortex.rs @@ -12,6 +12,7 @@ use anyhow::Result; use async_trait::async_trait; use cudarc::driver::CudaEvent; use cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT; +use cudarc::nvtx::safe::scoped_range; use futures::StreamExt; use serde_json::json; use tempfile::NamedTempFile; @@ -86,8 +87,8 @@ impl Compressor for GpuVortexCompressor { anyhow::ensure!( profile .as_deref() - .is_none_or(|mode| matches!(mode, "wall" | "gpu")), - "VORTEX_GPU_PROFILE must be wall or gpu" + .is_none_or(|mode| matches!(mode, "wall" | "gpu" | "nsys" | "nsys-ranges")), + "VORTEX_GPU_PROFILE must be wall, gpu, nsys, or nsys-ranges" ); if profile.is_none() { let start = Instant::now(); @@ -112,6 +113,8 @@ impl Compressor for GpuVortexCompressor { } let profile_gpu = profile.as_deref() == Some("gpu"); + let profile_nsys = matches!(profile.as_deref(), Some("nsys" | "nsys-ranges")); + let profile_trees = profile.as_deref() != Some("nsys-ranges"); let start = Instant::now(); let open_start = Instant::now(); let open_options = SESSION.open_options().with_cuda(); @@ -163,7 +166,7 @@ impl Compressor for GpuVortexCompressor { batch_count += 1; decoded_rows += record.len(); for field in record.iter_unmasked_fields() { - let metadata = profile.as_ref().map(|_| { + let metadata = profile_trees.then(|| { ( field.encoding_id().to_string(), field @@ -175,9 +178,13 @@ impl Compressor for GpuVortexCompressor { let before = profile_gpu .then(|| cuda_ctx.stream().record_event(Some(CU_EVENT_DEFAULT))) .transpose()?; + let range = profile_nsys.then(|| { + scoped_range(format!("vortex_field encoding={}", field.encoding_id())) + }); let field_start = Instant::now(); black_box(field.clone().execute_cuda(&mut cuda_ctx).await?); let wall = field_start.elapsed(); + drop(range); field_time += wall; let events = if let Some(before) = before { Some((