Repository navigation
feat(btrblocks): allow string dictionaries in the CUDA compression preset - #10917
Merged
Merged
Conversation
Codes under null positions may hold any value, and so may corrupt input. The CUDA dictionary gathers read values[code] for every row, so such a code read outside the dictionary. Every gather now checks the code against the dictionary length and writes a zero value for a code outside it. Adds tests for out-of-range codes under nulls for string, primitive, decimal and bool values (with host-resident and device-resident codes), the dictionary the GPU fuzzer crashed on, all-null codes, codes sliced across 1024/2048 boundaries, full-range u16 and beyond-u16 dictionaries, the 12-byte inline boundary, values longer than 4 KiB and non-UTF-8 binary values. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Tanish Gudise <[email protected]>
The GPU fuzz target only generated dictionaries with primitive values. It now also generates dictionaries with UTF-8 or binary values, dictionaries whose nullable codes hold arbitrary values under null positions, and string arrays compressed with the CUDA preset. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Tanish Gudise <[email protected]>
…host CanonicalCudaExt::into_host executed a child that CUDA execution left encoded on the host, with its buffers still on the device. A run-end encoded validity mask is such a child, and so is a nullable dictionary's validity, a lazy take of the values' validity through the device-resident codes. Both panicked on a host-buffer read: compress-bench --gpu-verify fails this way on CMSprovider and Euro2016 with the current CUDA preset. The child's buffers are now copied to the host before it is executed there. Children that are already canonical take the existing path, the copies run concurrently, and an array's buffers are replaced only when one of them moves. Adds tests that copy to the host a primitive array whose validity is a run-end or sparse encoded mask on the device, and string and primitive dictionaries with nullable values and device-resident codes. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Tanish Gudise <[email protected]>
The CUDA dictionary gather decodes Dict<Utf8> into views over the decoded values, so the CUDA preset no longer needs to exclude StringDictScheme. Binary dictionaries stay excluded. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Tanish Gudise <[email protected]>
Merging this PR will not alter performance2 warnings
Comparing Footnotes
|
Contributor
Author
|
A note on the red checks here, in case it saves you a look:
|
Replace the `in_dictionary` helper with the comparison it wrapped at its two call sites, so the check reads directly in each kernel. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Tanish Gudise <[email protected]>
The string-dictionary and CUDA-preset string generators in the GPU fuzz target aren't part of the bounds fix, so they move to a separate change. The fuzz target keeps the dictionaries with arbitrary codes under null positions, which exercise the bounds check, and the regression test now describes the dictionary the fuzzer found without quoting input bytes that no longer reproduce it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Tanish Gudise <[email protected]>
Signed-off-by: Tanish Gudise <[email protected]>
Signed-off-by: Tanish Gudise <[email protected]>
0ax1
self-requested a review
November 10, 2026 11:37
0ax1
approved these changes
Nov 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CompressionMode::CudaexcludesStringDictScheme, butexecute_dict_varbinviewalready decodes string dictionaries on the GPU. Keeping the scheme makes GPU-mode files 16.0% smaller across compress-bench's 17-dataset GPU suite (3,351.3 → 2,813.9 MB). Per-dataset gains: CMSprovider 45.7%, Food 52.9%, HashTags 33.2%, both TPC-H l_comment variants 12.2%, Euro2016 10.7%. The issue has the full table.Changes
vortex-btrblocks/src/builder.rs: dropsStringDictSchemefrom the Cuda exclusions and updates the comment. A new test checks that the preset keeps string dictionaries but not binary ones. This is the only change to CPU-compressor code.Evidence with this branch (A40, CUDA 13.0):
--gpu-verifypasses on all 17 datasets. develop plus only this line fails 5: taxi, CMSprovider, Euro2016, Food, HashTags.vortex-cudalib suite on this branch: 723 passed, 0 failed.compress_gpufuzz (CI flags, ASAN): 100,000 runs in 256 s, 0 crashes.Benchmarks
Setup:
compress-bench --gpu-decompress --iterations 5, a fresh process per run,taskset -c 2-7, 3 ABBA rounds.The nine datasets whose files don't change got one AB/BA round each. Eight came out at 1.01-1.18×, and one (wide table cols=1000 chunks=50) at 0.91×, inside the A/A floor. The measurements are from an A40 (GA102); the repo's GPU benchmarks run on A10G.
API changes
only_cuda_compatible(), and thereforecuda_write_strategy, can now emit string dictionaries.ArrowDeviceArrayStreamwith the defaultDictionaryExport::Preserverejects a batch whose Arrow schema differs from the first.DictionaryExport::Decode, which the FFI scan uses, are unaffected.Overlap: #10425 adds a line next to the removed one, so whichever merges second needs a one-line rebase. #9762 changes dictionary selection, so the sizes are as of a59294e.
AI assistance
Developed with Claude Code (Claude Opus 5.5), which wrote most of the code, tests and this description under my direction. I reviewed the diff and the measurements.
🤖 Generated with Claude Code