Skip to content

Add CUDA decompression kernels for OnPair - #8920

Open
robert3005 wants to merge 11 commits into
developfrom
rk/onpairgpu
Open

Add CUDA decompression kernels for OnPair#8920
robert3005 wants to merge 11 commits into
developfrom
rk/onpairgpu

Conversation

@robert3005

Copy link
Copy Markdown
Contributor

They follow the same pattern as FSST where we let users choose varbin/varbinview

@robert3005
robert3005 requested review from 0ax1 and joseph-isaacs July 23, 2026 14:33
Comment thread vortex-cuda/benches/onpair_cuda.rs Outdated
Comment thread vortex-cuda/src/kernel/encodings/onpair.rs Outdated
@codspeed-hq

codspeed-hq Bot commented Jul 23, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

✅ 1885 untouched benchmarks
⏩ 1 skipped benchmark1


Comparing rk/onpairgpu (1732f2a) with develop (c677bb7)

Open in CodSpeed

Footnotes

  1. 1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports.

Comment thread vortex-cuda/cub/src/scan.rs Outdated
Comment thread vortex-cuda/kernels/src/onpair_shmem_4tpt_split8read.cu
Comment thread vortex-cuda/kernels/src/onpair_shmem_4tpt_split8read.cu Outdated
Comment thread vortex-cuda/cub/kernels/filter.cu Outdated
@robert3005

Copy link
Copy Markdown
Contributor Author

I made it use the same machinery like #8921 to avoid triple kernel dispatch

@0ax1 0ax1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm. but worth double checking all index types

Comment thread vortex-cuda/benches/bench_config/mod.rs
Comment thread vortex-cuda/kernels/src/onpair_shmem_4tpt_split8read.cu Outdated
Comment thread vortex-cuda/kernels/src/onpair_shmem_4tpt_split8read.cu Outdated
Comment thread vortex-cuda/kernels/src/onpair.cu Outdated
Comment thread vortex-cuda/kernels/src/onpair.cu Outdated
Comment thread vortex-cuda/src/kernel/encodings/onpair.rs
Comment thread vortex-cuda/src/kernel/encodings/onpair.rs Outdated

@joseph-isaacs joseph-isaacs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nno no

Comment thread vortex-cuda/src/kernel/encodings/onpair.rs Outdated
Comment thread vortex-cuda/src/kernel/encodings/onpair.rs Outdated
@robert3005

Copy link
Copy Markdown
Contributor Author

I am reworking this to make sure all the work happens in one place - there's too many conflation. Will make sure that all non trivial compute is on gpu

Comment thread vortex-cuda/src/kernel/encodings/onpair.rs
Comment thread vortex-cuda/src/kernel/encodings/onpair.rs
Comment thread vortex-cuda/src/kernel/encodings/onpair.rs
@robert3005

Copy link
Copy Markdown
Contributor Author

@joseph-isaacs have another look

@robert3005
robert3005 requested a review from joseph-isaacs July 31, 2026 15:39

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we sort these function by usage a bit

Signed-off-by: Robert Kruszewski <github@robertk.io>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Comment on lines +603 to +629
let Some(decoded) = decode_onpair_bytes(onpair.as_view(), ctx).await? else {
// Zero decoded bytes: all-zero offsets and an empty values heap.
let offsets = ctx.copy_to_device(vec![0i32; len + 1])?.await?;
let allocation = CudaDeviceBuffer::new(ctx.device_alloc::<u8>(1)?);
let values = BufferHandle::new_device(allocation.slice(0..0));
return Ok(DecodedVarBin {
dtype,
len,
offsets,
values,
validity,
});
};

let OnPairDecoded {
bytes,
total_size,
lengths,
} = decoded;

// Build the Arrow i32 offsets from the lengths on device; this also
// rejects windows beyond Arrow's i32 offset range.
let I32Offsets {
buffer: offsets,
total,
} = i32_offsets_from_lengths(lengths, ctx).await?;
ensure_lengths_match(u64::try_from(total)?, total_size)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can these can not be in concurrent?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right here that we could move the device copies and executions to be concurrent but I think we need to let functions call back into the execute method with a different stream?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess per Alex's response we could create new cuda execution context?

Signed-off-by: Robert Kruszewski <github@robertk.io>
Comment on lines +290 to +322
let lengths = onpair
.uncompressed_lengths()
.clone()
.execute_cuda(ctx)
.await?
.into_primitive();

// No codes at all (e.g. every row empty): the child's length is host
// metadata, so this early-out costs no device read.
if onpair.codes().is_empty() {
ensure_zero_lengths(lengths).await?;
return Ok(None);
}

// Decompress the per-row code boundaries on device; the token window is
// resolved from them by a kernel, never by host scalar reads.
let codes_offsets = onpair
.codes_offsets()
.clone()
.execute_cuda(ctx)
.await?
.into_primitive();

// Decompress the codes child on device. The kernels are instantiated for
// the two widths OnPair stores — u16 natively, u8 when the compressor
// narrowed the codes — so no widening pass is needed.
let codes = onpair
.codes()
.clone()
.execute_cuda(ctx)
.await?
.into_primitive();
match codes.ptype() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do these concurrently?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed offline, the kernels will be submitted in sequenced and return once the kernel is submitted to the stream (not launched). We do want overlap / concurrency if the kernel does not occupy all SMs. In that case, we would need to submit the work through diff streams. This is not supported directly as of now by the API through execute. The current approach is that we round robin CUDA streams per CudaExecutionCtx.

As the context holds the session as a field

pub struct CudaExecutionCtx {
    stream: VortexCudaStream,
    ctx: ExecutionCtx,
    cuda_session: CudaSession,
    strategy: Arc<dyn LaunchStrategy>,
    dispatch_mode: CudaDispatchMode,
}

we could do an execute version that hooks into the stream round robin mechanism.

@robert3005

Copy link
Copy Markdown
Contributor Author

I have added a feature to let you spawn work on another stream here #9234. We can then rebase this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/feature A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants