dsa(indexer_backward): restore range_constexpr in 8 kernel_gemm epilogue loops - #549
Merged
Merged
Conversation
…gue loops The SM100 DSA indexer backward main kernel (kernel_gemm) regressed 17.5-25.4% in pure-kernel latency across the supported shape matrix when 8 loops in its compute/reduce epilogues were migrated from cutlass.range_constexpr(...) to cutlass.range(..., unroll_full=True). The migration is not visible as a standalone commit in the current history (it is folded into the squashed import 3a9ed3f); the released nvidia-cudnn-frontend 1.26.0 wheel still builds these loops with range_constexpr and does not show the regression. Measured on B200 (sm_100a), driver 590.48.01, CUDA 13.3, nvidia-cutlass-dsl 4.6.1, torch 2.13.0a0, canonical seeded inputs (B=1, H=64, D=128, S_k=4096, S_q=8192, topk=1024), nsys pure-kernel median, N=60 per variant, both variants interleaved per-iteration in ONE profiling session: develop @ 11c16ff (range, unroll_full=True) : 2056.9 us this patch (range_constexpr) : 1688.8 us nvidia-cudnn-frontend 1.26.0 wheel anchor : 1691.8 us (isolated session) develop has 21.8% higher latency than this patch (2056.9 / 1688.8 = 1.218); equivalently this patch has 17.9% lower latency than develop. The same interleaved harness across S_q in {4096, 8192} x topk in {512, 1024, 1536, 2048} measures develop 17.5-25.4% higher at every shape; this patch matches the 1.26.0 wheel anchor within 0.2% at the anchor shape. The one-shot barrier fix from NVIDIA#426 is unaffected and kept. Both forms fully unroll the loop body: range_constexpr unrolls at trace time, while range(..., unroll_full=True) lowers through the DSL structured-control-flow path. In this configuration the migrated form produced the higher latencies above (generated IR/SASS was not compared). An analogous ninth migration site in kernel_score_grad (block reduction over 128 per-thread partials) was measured separately with the same methodology and shows no runtime difference (49.70 us on develop vs 49.73 us reverted at S_q=8192/topk=1024; 16.00 vs 15.94 us at S_q=4096/topk=512), so it is intentionally left unchanged. Tradeoff: range_constexpr increases JIT compile time (the DSL documentation warns that long fully-unrolled trace-time loops can be slow to compile). Time-to-first-call with a cold DSL cache rises from ~3.5 s to ~5.2 s at the anchor shape (one-time per compiled shape); at 368 us saved per call the compile cost amortizes after ~4600 calls. No numerical regression was observed: d_index_q and d_weights are bitwise equal to develop at both tested shapes (S_q=8192/topk=1024, S_q=4096/topk=512). d_index_k is accumulated with fp32 atomicAdd and is nondeterministic run-to-run; the observed cross-build difference (max_abs 6.7e-08, rms_rel 3.9e-07 at the anchor shape) is comparable in scale to same-build rerun differences (develop-develop max_abs 6.7e-08 / rms_rel 3.1e-07, patch-patch 6.0e-08 / 3.3e-07). Signed-off-by: zky <kaiyue.zhou@z.ai>
Contributor
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe SM100 indexer backward kernel replaces eight fully unrolled runtime loops with ChangesSM100 indexer backward
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Collaborator
|
@cudnn-ci-bot run oss |
Anerudhan
approved these changes
Aug 11, 2026
|
🚀 Running mirror pipeline Branch: cudnn-gh/pr-549-a2478b4 |
Merged
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.
Fixes #548 (SM100 DSA indexer backward:
kernel_gemmpure-kernel latency regressed 17.5-25.4% after the
range_constexpr->range(..., unroll_full=True)migration).What
Reverts exactly 8 loops in the
kernel_gemmcompute/reduce epilogues ofpython/cudnn/deepseek_sparse_attention/indexer_backward/indexer_backward_sm100.pyfrom
cutlass.range(..., unroll_full=True)back tocutlass.range_constexpr(...). No other changes; the one-shot barrier fixfrom #426 is untouched. An analogous ninth migration site in
kernel_score_gradwas measured separately and shows no runtime difference(49.70 us vs 49.73 us at the anchor shape), so it is intentionally left
unchanged - see the issue.
Both forms fully unroll the loop body:
range_constexprunrolls at tracetime, while
range(..., unroll_full=True)lowers through the DSLstructured-control-flow path. In this configuration the migrated form
produced the higher latencies in the issue; this PR restores the
pre-migration form for exactly these 8 loops. See the issue for the full
isolation trail (grad-signal-recipe insensitivity, 1.26.0 wheel anchor, and a
single-migration revert probe on the public commit 3fcee36).
Verification (B200 sm_100a, driver 590.48.01, CUDA 13.3, cutlass-dsl 4.6.1)
Performance - canonical seeded harness (B=1, H=64, D=128, S_k=4096), nsys
pure-kernel median, N=60 per variant, both variants interleaved per-iteration
in one profiling session; anchor shape S_q=8192/topk=1024:
Stated in both directions: develop has 21.8% higher latency than this PR;
this PR has 17.9% lower latency than develop. Across S_q {4096, 8192} x
topk {512, 1024, 1536, 2048} the same harness measures develop 17.5-25.4%
higher at every shape (full table with standard deviations in the issue).
Compile-time tradeoff (disclosed):
range_constexprraises time-to-first-callwith a cold DSL JIT cache from ~3.5 s to ~5.2 s at the anchor shape (one-time
per compiled shape); at 368 us saved per call it amortizes after ~4600 calls.
Numerics - no numerical regression observed:
d_index_q,d_weights(kernel_gemm): bitwise identical to develop onthe canonical harness at both S_q=8192/topk=1024 and S_q=4096/topk=512.
d_index_kuses fp32 atomicAdd and is nondeterministic run-to-run: thedevelop-vs-PR difference (max_abs 6.7e-08, rms_rel 3.9e-07 at the anchor
shape) is comparable in scale to same-build rerun differences
(develop-develop max_abs 6.7e-08 / rms_rel 3.1e-07; PR-PR 6.0e-08 /
3.3e-07).
Tests / lint:
test/python/fe_api/dsa/test_DSA_indexer_backward.pyandtest_DSA_dense_indexer_backward.py: 3 passed.fe_api/dsa/: 81 passed, 7 skipped, 2 pre-existing failures intest_DSA_indexer_top_k.pythat reproduce identically on unmodified develop(unrelated module).
pre-commit run(pinned config: black 26.3.1, line-length 160): passed.Summary by CodeRabbit