Repository navigation
CUDA: fix CCCL version guard breaking on major version rollover - #29453
Conversation
The guard compared the major and minor components independently:
CCCL_MAJOR_VERSION >= 3 && CCCL_MINOR_VERSION >= 1
Minor resets to 0 whenever a new major series is cut, so on CCCL 4.x
this evaluates as 4 >= 3 && 0 >= 1, i.e. false. STRIDED_ITERATOR_AVAILABLE
stops being defined and argsort silently falls back to the
init_offsets path. Nothing warns and the build still succeeds, so the
regression is a quiet performance loss rather than a compile error.
CCCL already exposes the version as a single packed integer in
MMMmmmpp form, which is what its own version header uses:
CCCL_VERSION = MAJOR * 1000000 + MINOR * 1000 + PATCH
so 3.4.3 is 3004003 and ">= 3.1" is a plain ">= 3001000". One
comparison, with no component arithmetic left to get wrong.
Checked against a hand-written "version >= 3.1" reference over 2.9.9,
3.0.0, 3.1.0, 3.1.99, 3.2.0, 3.4.3, 3.9.9, 3.99.99, 4.0.0, 4.2.7 and
5.0.0: no divergences. The old guard disagreed at 4.0.0 and 5.0.0.
Verified on RTX 4070 (sm_89), CUDA 13.4, CCCL 3.4.3:
- cmake --build build --config Release: exit 0
- test-backend-ops test -o ARGSORT -b CUDA0: 98/98 passed, CUDA0 OK
Note that a passing regression test does not on its own prove the guard
is still taken, since the fallback path passes too. Preprocessing the
real translation unit confirms the strided-iterator branch is the one
compiled in: counting_iterator is present, init_offsets is not.
Signed-off-by: Heitor <heitorgm@outlook.com>
|
Hi @hey-gm, thanks for your contribution! Per our contribution guidelines, the automated PR checker found the following issue(s) that need your attention:
Please note that maintainers reserve the right to make final decisions on PRs. If you believe there is a mistake, please comment below. |
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
Updates the CUDA argsort CCCL version guard to avoid a silent performance regression when CCCL rolls over to a new major version (where the minor resets to 0).
Changes:
- Replace separate
CCCL_MAJOR_VERSION/CCCL_MINOR_VERSIONcomparisons with a single packedCCCL_VERSIONcomparison for theSTRIDED_ITERATOR_AVAILABLEgate. - Add a brief comment documenting CCCL’s packed version format.
| File | Description |
|---|---|
| ggml/src/ggml-cuda/argsort.cu | Fixes CCCL version gating logic so the strided-iterator path remains enabled across major version rollovers. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Upstream brings CUDA top-k/argsort/mmq fixes (PR ggml-org#28713, ggml-org#29953, ggml-org#30147, ggml-org#29453), a DFlash output-head fix (ggml-org#30111) and a UI fix (ggml-org#29668). Conflicts and resolution: - top-k.cu / argsort.cu: upstream reworked the top-k selection and the same radix path the fork added. Take upstream's shape-based dispatch and int64_t fixes, keep the fork workspace cap in the shared ggml_cuda_chunk_nrows (GGML_CUDA_ARGSORT_CHUNK_MB) and the fork benchmark-only GGML_CUDA_TOPK_IMPL selector used by bench-topk.py. - mmq.cu: upstream PR ggml-org#29953 fixes the same mul_mat_id padding over-read the fork patched in 1386ec2, but sizes the padding from the chosen J tile in both branches. Take upstream's version. - test-backend-ops.cpp: keep the fork GGML_TOPK_BENCH shapes and add upstream's chunk-spanning cases. Assisted-by: pi (deepseek-flash)
The 39 upstream commits after halo-box/llama.cpp's final sync. Same rules as the previous merge: strix's side wins where the two collide, upstream's non-conflicting changes stay, and fixes are ported into strix's code. - server: upstream's final ggml-org#26004 (context checkpoints across slot save/restore) replaces strix's earlier port of it, keeping strix's on-device restore flags; test_slot_save.py follows upstream. - cuda: strix's top-k (HIP radix), gated delta net and argsort kernels kept whole; upstream's CCCL major-version guard fix (ggml-org#29453) applied to strix's argsort. MMQ: upstream's out-of-bounds fix and host-side tile choice (ggml-org#29953) with strix's RDNA3.5 tile overrides on top; strix's fused MMQ paths pad src1 for the largest tile instead of the removed get_J_max. strix's 128-column rms_norm fast path and two mmvf calls updated to upstream's new signatures (ggml-org#28175, warp_size). - vulkan: strix's flash_attn_cm2.comp and topk_nary_search.comp kept whole (upstream's sparse cm2 FA ggml-org#30003 stays out with the rest of sparse FA). - llama-context: strix's MTP draft vocabulary next to upstream's MoE cache. - graph: upstream's single recurrent-state gather (ggml-org#29856) is restored and combined with strix's in-place gated delta net: in-place capable consumers keep the full gather and get their state view next to the consumer whether or not the rows are in place, so in-place and gathered ubatches build the same graph; this fixes the realloc aborts under GGML_SCHED_DEBUG_REALLOC in both upstream's shared-seq test and strix's seq cp graph reuse test. - ggml-backend: alloc_buffer_n planning no longer flushes on zero-size tensors, which left views of a tensor larger than max_size uninitialized (caught by strix's test_view_init_after_max_size_split). - SYNC.md: this fork now syncs with ggml-org/llama.cpp directly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-org#29453) * CUDA: fix CCCL version guard breaking on major version rollover The guard compared the major and minor components independently: CCCL_MAJOR_VERSION >= 3 && CCCL_MINOR_VERSION >= 1 Minor resets to 0 whenever a new major series is cut, so on CCCL 4.x this evaluates as 4 >= 3 && 0 >= 1, i.e. false. STRIDED_ITERATOR_AVAILABLE stops being defined and argsort silently falls back to the init_offsets path. Nothing warns and the build still succeeds, so the regression is a quiet performance loss rather than a compile error. CCCL already exposes the version as a single packed integer in MMMmmmpp form, which is what its own version header uses: CCCL_VERSION = MAJOR * 1000000 + MINOR * 1000 + PATCH so 3.4.3 is 3004003 and ">= 3.1" is a plain ">= 3001000". One comparison, with no component arithmetic left to get wrong. Checked against a hand-written "version >= 3.1" reference over 2.9.9, 3.0.0, 3.1.0, 3.1.99, 3.2.0, 3.4.3, 3.9.9, 3.99.99, 4.0.0, 4.2.7 and 5.0.0: no divergences. The old guard disagreed at 4.0.0 and 5.0.0. Verified on RTX 4070 (sm_89), CUDA 13.4, CCCL 3.4.3: - cmake --build build --config Release: exit 0 - test-backend-ops test -o ARGSORT -b CUDA0: 98/98 passed, CUDA0 OK Note that a passing regression test does not on its own prove the guard is still taken, since the fallback path passes too. Preprocessing the real translation unit confirms the strided-iterator branch is the one compiled in: counting_iterator is present, init_offsets is not. Signed-off-by: Heitor <heitorgm@outlook.com> * Update ggml/src/ggml-cuda/argsort.cu * Apply suggestion from @ORippler --------- Signed-off-by: Heitor <heitorgm@outlook.com> Co-authored-by: Oliver Simons <osimons@nvidia.com>

Summary
ggml/src/ggml-cuda/argsort.cugatesSTRIDED_ITERATOR_AVAILABLEon aCCCL version check that compares the major and minor components
independently:
The minor component resets to 0 whenever a new major series is cut. On
CCCL 4.x the condition therefore evaluates as
4 >= 3 && 0 >= 1, whichis false. The macro goes undefined and argsort silently falls back to
the
init_offsetspath. The build still succeeds and nothing warns, sothis lands as a quiet performance regression rather than a build break.
Root cause
Comparing version components separately is only correct within the
current major series. It implicitly assumes the minor component keeps
increasing, which stops being true at every major-version boundary.
CCCL already publishes the version as a single packed integer in
MMMmmmppform, which is what its own version header defines:so 3.4.3 is 3004003, and "at least 3.1" is a plain
>= 3001000. Thatleaves a single comparison with no component arithmetic to get wrong.
The fix
Testing
RTX 4070 (sm_89), CUDA 13.4.92, CCCL 3.4.3, Ubuntu 26.04.
cmake --build build --config Release- exit 0test-backend-ops test -o ARGSORT -b CUDA0- 98/98 passed, CUDA0 OKThe new guard was checked against a hand-written "version >= 3.1"
reference across 2.9.9, 3.0.0, 3.1.0, 3.1.99, 3.2.0, 3.4.3, 3.9.9,
3.99.99, 4.0.0, 4.2.7 and 5.0.0, with no divergences. The previous
guard disagreed at 4.0.0 and 5.0.0.
Worth noting that a green
test-backend-opsrun does not by itself showthe guard is still taken, because the fallback path passes those tests
as well. Preprocessing the real translation unit confirms the
strided-iterator branch is the one being compiled in:
counting_iteratoris present and
init_offsetsis not.Note
ggml/src/ggml-cuda/top-k.cucarries the same defect with a>= 3.2threshold. It is left untouched here to keep this change reviewable on
its own; a follow-up PR for it would be welcome.