Repository navigation
fix(cake_sparse_mla): harden the DSv4 sparse-MLA Cake backend for #4671 (padded Q, separate SWA/compressed tables, caller-owned workspace, length offsets) and regenerate the SM100/SM103 programs - #5591
Merged
Conversation
…ata ABI (flashinfer-ai#4671) Rewrite flashinfer/mla/cake_dsv4.py around the regenerated kernel ABI: - Bind kernel arguments by name through the registration arg_plan / program signature (tma_buffer/buffer -> tensors, parameter -> ints, workspace -> descriptor slab, grid -> launch grid). Every variant receives the uniform metadata vocabulary (swa_indices, compressed_indices, sparse_topk_lens, swa_index_stride, compressed_index_stride, sparse_topk_lens_offset, sparse_topk, num_query_tokens); only the names in its plan are passed. Pre-hardening `sparse_indices` binds only for a combined table with offset 0; `completion_base` is rejected. - Resolve metadata like the Cake helper without copies: combined table -> two row-strided views, separate SWA [T,128] + extra [T,topk_c] tables, compressed-only lens => offset 128, explicit sparse_topk_lens_offset. num_query_tokens = metadata rows; query/out are prefix views when they carry more rows. Non-unit column stride / non-int32 tables raise. - Carve ONE caller-owned workspace deterministically: [TMA descriptor slab 1 KiB | split-merge counters 256 KiB | partial_O | partial_lse]. Publish get_cake_dsv4_workspace_bytes(), cake_dsv4_workspace_layout() and cake_dsv4_workspace_reset(). No device allocation on the call path; counter priming is refused during CUDA graph capture with a clear error. Remove the host-side _partition_arrivals generation state and the per-call _padded_sparse_indices copy. - _core.py: backend="cake" accepts extra_sparse_indices, extra_sparse_topk_lens and the new sparse_topk_lens_offset kwarg, and tolerates metadata with fewer rows than the query (padded batches). Docstring documents the cake contract. trtllm-gen/sparse/cute-dsl paths are unchanged. - Tests: CPU binding/workspace/metadata/capture tests in tests/mla/test_cake_dsv4.py (117 passing) and GPU hardening tests in tests/mla/test_cake_dsv4_hardening.py (padded rows, separate tables, lens offset, all -1 rows, CUDA graph replay + memory_allocated) for H in {32,64,128}, BF16/FP8, q_len {1,4}. - csrc/cake_dsv4/README.md: API additions and workspace contract. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…r#4671 P1/P4) - query/out rows beyond the metadata tables (padded DP/MTP batches) are sliced to prefix views on the host; the cubin never reads padded metadata and never writes padded output rows (dense padding must be whole requests). - new multi_ctas_kv_counter_buffer kwarg: a caller-owned, zero-initialized buffer validated against get_trtllm_gen_multi_ctas_kv_counter_bytes; the per-call allocation remains only when nothing is passed. - GPU tests for both behaviours (padded rows dense/ragged, counter reuse over launches, size validation, backend guard, CUDA-graph replay after mutation). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…te tables
With extra_sparse_topk_lens (separate SWA/compressed tables) the public API
validated the compressed lengths through _check_dsv4_sparse_mla_inputs and
then forwarded that checked tensor as sparse_topk_lens *and* the caller's
extra_sparse_topk_lens, so run_cake_dsv4 rejected every separate-table call
("pass either sparse_topk_lens ... or extra_sparse_topk_lens ..., not both").
Forward the combined table only when the caller supplied one.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…BF16 H128 SWA rows (cake backend) - fp8_h128: split the KV range only as far as one wave of 2-CTA clusters needs (min(5, (sm_count // 2) // tokens)); the fixed 5-way split ran 4-5 waves of single-tile work items on 16-64 token MTP rows. - BF16 H128 SWA-only rows with 128+ metadata tokens use the full-V H128 family (bf16_h128_topk128x), ~2x faster than the dedicated SWA producer on 128-512 token rows; shorter rows keep the dedicated producer. Both rules mirror the Cake dispatcher. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Mirror of the Cake producer rule measured on GB300/B200: <= 3 tiles unsplit, 4-5 tiles within 32 clusters, 6+ tiles up to five splits within one wave. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ent bodies Mirror of the Cake dispatcher: FP8/H128 rows with 16+ tokens use the persistent prefill body, BF16/H64 compressed rows with 24+ tokens and width <= 640 use the KV-reuse prefill body; canonical 12-token rows are unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Mirror of the Cake dispatcher: the persistent fp8_h128_prefill_source_persistent body beats the best forced split of the cluster producer on every FP8/H128 row (GB300 canonical 12/12 above trtllm-gen, MTP rows 1.10-1.75x), so the fp8_h128 split route, _fp8_h128_num_splits and the sm_count binding are removed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…P8/H128 route The generated bindings check every pointer buffer for contiguity. The host handed the compressed table of a combined sparse_indices table over as a column-sliced view, which the binding rejected on every combined-table call (46 GPU hardening tests). SparseMetadata.kernel_kwargs() now exposes both tables as contiguous spans with the same base pointer and row stride, no copy. fp8_h128_prefill_source_persistent reads request boundaries from cum_seq_lens_q only; dense queries reached it with no offsets. run_cake_dsv4 synthesizes arange(batch+1) * max_q_len for ragged-only routes from a cached process-lifetime tensor (no per-call allocation, stable pointer for CUDA graphs). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ragged requests The fp8_lowhead_split / fp8_lowhead_h64_split producers index their ``O`` argument as [tokens, heads, splits, 512] (the Cake dispatcher hands them its partial buffer) and the reducer writes the caller's rows. The host bound ``O`` to the caller's output, so the producer overran it by one output's worth and the reducer merged never-written workspace partials: wrong FP8 H32 (both archs) / H64 (SM100) results and memory corruption of neighbouring tensors in the hardening tests. trtllm-gen path: with ragged queries the kernel takes its token count from cum_seq_lens_q, so a padded batch (metadata rows < query rows) still wrote the padded output rows. Cut cum_seq_lens_q/seq_lens at the request boundary that equals the metadata row count; padding must drop whole requests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…roducer Mirrors the Cake seed's FP8_ONE_PARTITION_MAX_TILES = 3: three sparse tiles are owned by one producer partition (final O written directly) instead of the 2 + 1 split plus reducer. Route tests updated; the width-640 case keeps the split path. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…to the persistent body The persistent FP8 body (same kernel as FP8/H128; heads >= num_heads are predicated and the second CTA's OOB Q rows zero-filled) measured GB300 1.23-1.26x / B200 1.15x vs trtllm-gen on the width-640/388 FP8/H64 decode rows where the per-token cluster body sat at 0.95-1.04x (CAKE-624 W5). The rule mirrors the Cake seed (H64_PERSISTENT_MIN_TILES = 3 complete tiles, H64_PERSISTENT_MAX_TOKENS = 12). Width-260 and many-token rows keep the H64 producers. The route test now derives the canonical ragged token count from the contract's linspace rule instead of batch * max_q_len. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… sm_103a too The two-stage split programs (three or four disjoint full-V KV owners plus one LSE reducer) now ship on both Blackwell targets: GB300 width-260/388 rows measured 1.18-1.26x vs trtllm-gen against 0.83-1.05x for the single-owner kernel (CAKE-624 W2). The sm_100a dispatch is unchanged. A recorder test pins the program and split count per width on both targets. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Mirrors the Cake seed rule (CAKE-624 W5 + W10): 12-token rows with >= 3 complete sparse tiles, every many-token compressed row (>= 2 tiles) and SWA-only rows from 128 tokens take the persistent FP8 body already shipped for FP8/H128 (num_heads is a runtime argument there). The per-token cluster producers and the SWA producer sat at 0.19-0.87x vs trtllm-gen on the 64-512 token hardening rows; the persistent body measures 1.02-1.92x on the 16-128 token rows on both targets. Evaluated before the SWA-only test so one-tile many-token rows reach it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…single owner Mirrors the Cake seed's BF16_TOPK128X_SPLIT_MAX_TOKENS (CAKE-624 W12): the split3/split4 two-stage programs keep the 12/16-token rows; width 260-388 rows with more query tokens select bf16_h128_topk128x_row_first (one full-V owner per token whose -1 sparse rows gather the tile's first index). hardening-000025/31 0.45-0.95x -> 1.13-1.65x vs trtllm-gen on both targets. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…stent prefill body Mirrors the Cake dispatcher's BF16_H128_PREFILL_MIN_TOKENS (CAKE-624 W11): the 64-512 token MTP rows leave the per-token owners (0.39-0.91x vs trtllm-gen) for the KV-reuse prefill body (1.00-1.18x); the former SWA -> full-V rule at 128 tokens (0.55-0.73x) is removed. The exported bf16_h128_prefill_v42 program is regenerated with the seed's width guard relaxed to 128..1152 and the QK-warp exit-wait parity fix. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The retained-KV body with the last-arriver split merge beats the dedicated topk4x body on the H32 topk4x rows on both SM100a and SM103a, so both H32 sparse routes select bf16_h32_topk128x_early_v47. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…CTA M64 program Mirrors the Cake seed's H64_M64_MIN_TOKENS: FP8/H64 rows admitted to the persistent body with at least 128 query tokens select fp8_h64_prefill_source_persistent_m64 (one CTA per token, grid = tokens, ragged query offsets synthesized like the FP8/H128 persistent route); the other admitted rows keep fp8_h128_prefill_source_persistent. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tch-derived routes Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…r program Mirrors the Cake seed's LANE_GATHER_MIN_TOKENS: the persistent FP8 body has two exported programs, fp8_h128_prefill_source_persistent_uniform (elected-lane uniform K/V gathers, below 128 query tokens) and fp8_h128_prefill_source_persistent (lane-issued gathers, 128 tokens and up). Same launch block, grid = 2 * tokens, ragged query offsets synthesized. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Export of the hardened DSv4 family on B200 against this branch: 134 shapes (94 canonical + 40 hardening), all gates passed, trtllm-gen default path geomean 1.220x over the 94 canonical rows, source/export agreement 1.009x. Program files no longer referenced by the regenerated registry are removed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Export of the hardened DSv4 family on GB300 against this branch: 134 shapes, correctness and source/export agreement on every row, trtllm-gen default path geomean 1.237x over the 94 canonical rows (prefill-style 089/093 at 0.990x and 0.993x are below parity and documented in the Cake design doc). Program files no longer referenced by the regenerated registry are removed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…8 prefill body for tail-majority rows Mirrors the Cake seed's bf16_h128_prefill_uses_snake_feed (CAKE-624 W17): with C = min(T, SMs // 2) clusters, the striped feed leaves a short heavy prefix to the few regular clusters when the tail clusters are the majority, so rows such as hardening-000037 (512 tokens, width 640) launch bf16_h128_prefill_v42_snake instead of bf16_h128_prefill_v42. One-tile items and regular-majority rows keep the striped program. Predicate and program-selection tests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds the boustrophedon work-feed program of the BF16/H128 prefill body (bf16_h128_prefill_v42_snake, family 63f33aae) generated from Cake 20baf19a41e on B200; removes 14 sm_100a family bindings that no registry entry has referenced since the SM100/SM103 regeneration. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds the boustrophedon work-feed program of the BF16/H128 prefill body (bf16_h128_prefill_v42_snake, family f7339c08) generated from Cake 20baf19a41e on GB300; removes the sm_103a source files that no registry entry references (the pre-generation SM103 implementation files and family bindings from flashinfer-ai#4573, superseded by the generated programs). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…exact program Host route fp8_h8_h16_source_exact (same shape lock as the BF16 source-exact route) and its launch shape; route tests updated, two off-profile cases keep the one-partition producer. Programs are regenerated in the export commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds the FP8 H8/H16 SwapsAb source-exact program (fp8_h8_h16_source_exact, family 28ebcdf2) and regenerates the boustrophedon work-feed program of the BF16/H128 prefill body from the K-reuse body (bf16_h128_prefill_v42_snake, family d9a2424a; the striped program is byte-identical), generated from Cake 69bc58ee5ed on B200; removes the superseded snake family 63f33aae and the one-partition program files no registry entry references. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds the FP8 H8/H16 SwapsAb source-exact program (fp8_h8_h16_source_exact, family 6950f2bb) and regenerates the boustrophedon work-feed program of the BF16/H128 prefill body from the K-reuse body (bf16_h128_prefill_v42_snake, family 1d469eb5; the striped program is byte-identical), generated from Cake 69bc58ee5ed on GB300; removes the superseded snake family f7339c08 and the one-partition program files no registry entry references. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Regenerates the BF16/H128 persistent prefill program (32-byte epilogue O stores) and the FP8/H128 persistent programs (lazy O rescale, variant 4620) from Cake 421f1a5671a on B200; removes the superseded program files no registry entry references. Paired vs the default trtllm-gen path on B200: 94/94 canonical rows > 1.0 (geomean 1.226x). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Regenerates the BF16/H128 persistent prefill program (32-byte epilogue O stores) and the FP8/H128 persistent programs (lazy O rescale, variant 4620) from Cake 421f1a5671a on GB300; removes the superseded program files no registry entry references. Paired vs the default trtllm-gen path on GB300: 94/94 canonical rows > 1.0 (geomean 1.237x; prefill-style-000089 1.018x, 000093 1.006x). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Collaborator
Collaborator
|
[SUCCESS] Pipeline #70026981: 25/25 executed test jobs passed |
yzh119
approved these changes
Sep 27, 2026
yyihuang
pushed a commit
to yyihuang/flashinfer
that referenced
this pull request
Sep 27, 2026
…grams (warp-uniform FP8/H128 gathers, 32-byte epilogue stores in the K-reuse prefill program) Regenerated from Cake db0609184cd against 8589d49 with the same export pipeline as flashinfer-ai#5591 (134 shapes per architecture: 94 canonical + 40 hardening; correctness, source/export agreement and the trtllm-gen baseline gates all pass on B200 and GB300). - FP8/H128 persistent prefill program: the K/V loader warps issue their TMA gather4 from one elected lane with warp-uniform coordinates (shfl broadcast) instead of one lane-divergent gather per lane; the persistent seed compiles with --register-usage-level=10 so the exported build keeps the production softmax schedule. prefill-style rows 089/093: GB300 1.02x -> 1.24x/1.21x, B200 1.05x -> 1.19x/1.18x vs the trtllm-gen default path. - BF16/H128 K-reuse (snake) prefill program: 32-byte epilogue O stores. hardening rows 27/37: GB300 1.175x -> 1.19x, 1.016x -> 1.107x; B200 1.172x -> 1.173x, 1.028x -> 1.100x. - All other programs are byte-identical regenerations (renamed for the new producer revision); 94/94 canonical rows > 1.0 on both architectures (geomean GB300 1.243x, B200 1.232x). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
yyihuang
added a commit
that referenced
this pull request
Sep 27, 2026
…epilogue stores in the DSv4 sparse-MLA Cake programs (SM100/SM103) (#5610) ## Summary Round-2 performance of the `backend="cake"` DeepSeek-V4 sparse-MLA decode path of `trtllm_batch_decode_sparse_mla_dsv4` (SM100a / SM103a), regenerated from the same producer pipeline as #5591: - **FP8/H128 persistent prefill program (prefill-style rows with 128+ query tokens, batch 2-48 items x 16 KV tiles):** the two K and two V loader warps issued their TMA `gather4` with lane-divergent coordinates, so ptxas serialised every gather into a 32-iteration per-lane loop and the loaders spent ~1.0 us of every 1.12-us KV tile issuing. They now issue from one elected lane with warp-uniform coordinates (`shfl.sync` broadcast, one unrolled 16-quartet site per warp with the KV descriptor selected per tile), the same form the default trtllm-gen kernels use. Same barriers, pipeline depth and data movement; only the issuing lane changes. The loop is now paced by the tensor pipe (16 QK + 8 PV MMAs per tile, ~0.8 us). prefill-style-000089 / 000093: GB300 1.02x / 1.01x -> **1.24x / 1.21x**, B200 1.05x / 1.06x -> **1.19x / 1.18x** vs the default path. The persistent seed compiles with `-Xptxas=--register-usage-level=10` so the exported build keeps the softmax schedule of the source build (without it ptxas re-orders the exp2/convert chains across the P-publication fence: 3-5 % slower on these rows). - **BF16/H128 K-reuse (snake) prefill program (`bf16_h128_prefill_v42_snake`, hardening rows 27 / 37):** the epilogue drains O with 32-byte stores like the striped program already did. hardening-000037: GB300 1.016x -> **1.107x**, B200 1.028x -> **1.100x**; hardening-000027: 1.175x -> 1.190x, 1.172x -> 1.173x. - Every other program is a byte-identical regeneration (renamed for the new producer revision). - New CPU test: registered programs build with public nvcc/ptxas options only, and the FP8/H128 persistent variants pin the register-usage level. The one-KV-tile SWA-only work items of the BF16/H128 persistent prefill body (hardening rows 23 / 29 / 35) were re-attributed and left unchanged: the item is a per-SM chain bound by the SM's L2<->SM port (256 KB per CTA per item at the measured ~66 GB/s = the measured 3.9 / 4.1 us period); the byte levers (K-reuse body, four issuing warps, DSM exchange of the V halves) measured negative or closed by arithmetic. Those rows stay at 1.03-1.16x. ## Validation Export r11 (Cake `db0609184cd`, this branch at 8589d49 + the regenerated programs), same-session paired CUPTI (active-union median, 500 warmup / 3000 calls per arm, cold L2) against the default trtllm-gen path at the same revision: | | GB300 (sm_103a) | B200 (sm_100a) | |---|---|---| | 94 canonical + 40 hardening shapes correct (BF16 atol=rtol=1e-2, FP8 0.1; padded / separate-table / offset axes) | 134/134 | 134/134 | | **94 canonical rows faster than the default path** | **94/94, geomean 1.243x, min 1.054x** (#5591: 1.237x, min 1.006x) | **94/94, geomean 1.232x, min 1.041x** (#5591: 1.226x, min 1.013x) | | 40 hardening rows faster than the default path | **40/40, geomean 1.30x, min 1.058x** (#5591: 1.28x, min 1.016x) | **40/40, geomean 1.25x, min 1.037x** (#5591: 1.25x, min 1.029x) | | exported program vs Cake source build (agreement gate, 134 rows) | geomean 1.002x, every row within 3 % | geomean 1.004x, every row within 3 % | | compute-sanitizer synccheck + memcheck on the two changed kernels | 0 errors | 0 errors | | `tests/mla/test_cake_dsv4*.py` (GPU, on the exported programs) | 292 passed | 292 passed | | `tests/mla/test_cake_dsv4*.py` (CPU, this host) | 210 passed | 210 passed | ## Baselines and their source PRs - **trtllm-gen default path** = `trtllm_batch_decode_sparse_mla_dsv4(...)` without `backend="cake"` (the TRTLLM-GEN DSv4 sparse-MLA kernels plus the framework launches it needs for equal semantics: padded-Q masking, separate-table merge, workspace/counter handling). Origin PRs: #3269 (9c76c99, 2026-05-21, `flashinfer/decode.py`, `flashinfer/mla/_core.py`, DSv4 TRTLLM-GEN kernels); SM120 kernels #3395 (f954694, 2026-06-15); DSv4.1 unification #5197 (eb5f05b, 2026-09-18). - **Cake backend under test** = `backend="cake"` from #4573 (13db2cf, 2026-09-16) as hardened and regenerated by #5591 (8589d49, 2026-09-27), regenerated again by this PR. - **Test oracle** = the PyTorch reference of `tests/mla/test_cake_dsv4.py` / `test_cake_dsv4_hardening.py` (DSv4 RopeQuant exposure #4918, 27d5b02, 2026-09-07). - **Branch base** = upstream `main` 8589d49 (the #5591 merge); no upstream commits in between. ## CI `tests/mla/test_cake_dsv4.py` and `tests/mla/test_cake_dsv4_hardening.py` (CPU and GPU parametrizations). 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Improved correctness of CAKE DSV4 attention kernels by refining shared-memory synchronization, sparse gather operations, and pipeline phase handling. - Updated output processing to use more efficient vectorized stores in selected kernels. - Corrected kernel registration and dispatch across supported GPU architectures, including updates to available variants and compile settings. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Yingyi Huang <averyh@nvidia.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
yyihuang
added a commit
that referenced
this pull request
Sep 28, 2026
…nel (redundant p_full barrier removed) (#5627) Developed by the **CAKE team**, the kernels in this PR **outperform** the relevant **SOTA baselines at the time of merge** on the **vast majority of performance benchmark shapes**, matching them otherwise. ## Summary Regenerates the Cake-generated `backend="cake"` Kimi-K3 MLA FP8 paged attention route (#5552; r52 programs in #5602) for the **r54 kernel** on SM100 (B200) and SM103 (B300 / GB300). The host side is unchanged from #5602 (same planner, grids and kernel arguments); this PR moves only the generated programs of both architectures, every file written by the exporter from the same producer tree, and the two architectures' exports agree byte-for-byte (`csrc` and the registry). What r54 changes against the r52 programs (`698a96197`): - **The redundant `p_full` mbarrier is removed from the wide two-CTA kernel.** Since r52 the softmax / correction warps arrive `o_ready` (tile parity, 4 warps x 2 CTAs, cluster arrive to CTA 0) right after the P store's `fence.proxy.async` at the same site where they arrived `p_full`, and the MMA warp waited both barriers at the same point before PV(t) and before the drain; `p_full` therefore carried no ordering of its own. PV(t) is now gated by `o_ready` alone: one fewer cluster arrive per warp per tile, one fewer wait per tile in the MMA warp, 45 (was 47) mbarriers. Outputs are unchanged (same FP32-reference max_abs on every checked row). - Measured against the r52 kernel of record on the same nodes (paired, arm-alternated, 3 rounds, CUDA-graph cold-L2 CUPTI timing, cute-dsl anchor): **neutral within the session noise floor on both GPUs** (B300 0.994-1.006 of the record over the 11 wide and prefill rows, noise floor 0.24 % median / 1.56 % max; B200 0.991-1.019, noise floor 0.26 % / 3.60 %). The change ships as the simpler canonical form, not as a speed-up. - The round's other candidate, pacing the row-tile clusters of one request so they share K tiles in L2, was measured as a loss in four configurations (+30 % to +156 % on mtp_h96_b8_q4) and does not ship; hardware counters show the re-read it targeted is intermittent and off the critical path of that row. ## Performance (same-session CUPTI cold-L2, CUDA-graph replay, 3 alternating rounds; Cake vs the fastest existing FlashInfer route) | row | B200 Cake us | B200 best FI (route) | B200 speedup | B300 Cake us | B300 best FI (route) | B300 speedup | |---|---:|---:|---:|---:|---:|---:| | trace_h12_b1_q1_kv76800 | 21.2 | 24.7 (cute-dsl) | 1.166x | 20.9 | 23.6 (cute-dsl) | 1.128x | | trace_h12_b2_q1_kv77699 | 29.3 | 31.0 (cute-dsl) | 1.060x | 28.9 | 30.7 (cute-dsl) | 1.060x | | trace_h12_b3_q1_kv261120 | 89.7 | 93.1 (cute-dsl) | 1.039x | 90.3 | 92.6 (cute-dsl) | 1.026x | | trace_h12_b4_q1_kv268800 | 112.9 | 123.4 (cute-dsl) | 1.093x | 113.6 | 119.9 (cute-dsl) | 1.056x | | trace_h12_b5_q1_kv276480 | 138.4 | 149.0 (trtllm-gen) | 1.076x | 139.7 | 150.4 (trtllm-gen) | 1.077x | | trace_h12_b6_q1_kv467751 | 254.0 | 272.6 (trtllm-gen) | 1.073x | 257.1 | 274.1 (trtllm-gen) | 1.066x | | trace_h12_b7_q1_kv299613 | 195.4 | 208.6 (trtllm-gen) | 1.068x | 197.8 | 210.6 (trtllm-gen) | 1.064x | | trace_h12_b8_q1_kv342305 | 246.5 | 266.0 (trtllm-gen) | 1.079x | 249.4 | 267.1 (trtllm-gen) | 1.071x | | trace_h12_b9_q1_kv348705 | 279.0 | 301.8 (trtllm-gen) | 1.082x | 280.3 | 300.3 (trtllm-gen) | 1.071x | | trace_h12_b10_q1_kv474166 | 412.0 | 446.7 (trtllm-gen) | 1.084x | 411.9 | 442.9 (trtllm-gen) | 1.075x | | trace_h12_b11_q1_kv474405 | 451.9 | 485.7 (trtllm-gen) | 1.075x | 450.5 | 482.2 (trtllm-gen) | 1.070x | | mirror_h96_b1_q1_kv76800 | 23.4 | 27.6 (cute-dsl) | 1.178x | 23.0 | 26.2 (cute-dsl) | 1.136x | | mirror_h96_b2_q1_kv77699 | 33.2 | 34.2 (cute-dsl) | 1.030x | 33.1 | 33.6 (cute-dsl) | 1.016x | | mirror_h96_b6_q1_kv467751 | 324.4 | 340.8 (cute-dsl) | 1.050x | 315.5 | 330.3 (cute-dsl) | 1.047x | | mirror_h96_b7_q1_kv299613 | 246.1 | 259.5 (cute-dsl) | 1.055x | 236.2 | 246.1 (cute-dsl) | 1.042x | | mirror_h96_b8_q1_kv342305 | 318.5 | 332.6 (cute-dsl) | 1.044x | 308.8 | 322.0 (cute-dsl) | 1.043x | | mtp_h12_b8_q2_kv342305 | 256.4 | 311.9 (cute-dsl) | 1.217x | 252.8 | 300.7 (cute-dsl) | 1.189x | | mtp_h12_b8_q4_kv342305 | 284.0 | 316.4 (cute-dsl) | 1.114x | 262.3 | 312.4 (cute-dsl) | 1.191x | | mtp_h12_b8_q8_kv342305 | 316.7 | 331.6 (cute-dsl) | 1.047x | 307.8 | 321.9 (cute-dsl) | 1.046x | | mtp_h96_b8_q2_kv342305 | 611.3 | 685.7 (cute-dsl) | 1.122x | 597.0 | 644.7 (cute-dsl) | 1.080x | | mtp_h96_b8_q4_kv342305 | 915.6 | 984.6 (cute-dsl) | 1.075x | 894.5 | 928.3 (cute-dsl) | 1.038x | | mtp_h96_b8_q8_kv342305 | 1756.1 | 2149.4 (cute-dsl) | 1.224x | 1751.5 | 2026.2 (cute-dsl) | 1.157x | | prefill_h12_b1_q2048_kv131072 | 2485.0 | 2746.1 (cute-dsl) | 1.105x | 2487.4 | 2617.8 (cute-dsl) | 1.052x | | prefill_h12_b2_q512_kv32768 | 323.7 | 389.8 (cute-dsl) | 1.204x | 319.9 | 363.3 (cute-dsl) | 1.136x | | prefill_h12_b4_q1024_kv8192 | 330.8 | 360.4 (cute-dsl) | 1.090x | 312.2 | 348.5 (cute-dsl) | 1.116x | | prefill_h96_b1_q2048_kv131072 | 19914.1 | 20985.0 (cute-dsl) | 1.054x | 20103.1 | 20862.9 (cute-dsl) | 1.038x | | prefill_h96_b2_q512_kv32768 | 2479.5 | 2619.9 (cute-dsl) | 1.057x | 2470.4 | 2613.7 (cute-dsl) | 1.058x | Every row on both GPUs is faster than the best existing FlashInfer route (minimum 1.016x, `mirror_h96_b2` on B300; the same thinnest row as in #5602). Columns: median of three alternating rounds; `best FI` is whichever of trtllm-gen / cute-dsl was faster on that row and GPU (trtllm-gen has no H96 MLA decode kernel, so `auto` resolves to cute-dsl there). ## Baselines and their source PRs The `vs best FI` column compares against the two existing FlashInfer routes of the same public entry points, resolved at this branch's upstream merge-base `f4d45edf1` (2026-09-27, #5596): - **trtllm-gen** (`backend="trtllm-gen"`, also what `backend="auto"` selects for H12): `trtllm_batch_decode_with_kv_cache_mla` / `trtllm_prefill_with_kv_cache_mla` in `flashinfer/mla/_core.py` launching the prebuilt TRT-LLM-gen FMHA cubins pinned in `flashinfer/artifacts.py` (`TRTLLM_GEN_FMHA = 2d6a5a02…/fmha/trtllm-gen/`; pin set by #4654 `857bc3a11`, 2026-08-26). Test oracle: `tests/attention/test_trtllm_gen_mla.py`. - **cute-dsl** (`backend="cute-dsl"`, what `auto` selects for H96): the CuTe-DSL MLA decode family under `flashinfer/cute_dsl/attention/` — `mla_decode_fp8.py`, `mla_config.py`, `wrappers/batch_mla.py` (#2805, `00ac5053d`, 2026-04-13; H64/H96 configs #3235 `2d0e0efac` 2026-05-11; SM107 reland #4280 `5b1af9724` 2026-07-30), `mla_dispatch.py` + `monolithic/mla_decode.py` (#3296 `e91ac8f15` 2026-05-21; LSE base semantics #4650 `d7a7447cb` 2026-09-21), reached through `flashinfer/mla/_core.py` (cute-dsl MLA op #2743 `31b63bc3d` 2026-03-27). Test oracle: `tests/attention/test_trtllm_gen_mla.py` / the CuTe-DSL MLA tests of those PRs. Since the previous merge-base `7b8f6129c` (the #5602 comparison) no upstream commit touched the `cute-dsl` MLA kernels (`git log 7b8f612..f4d45ed -- flashinfer/cute_dsl/attention` is empty), the `TRTLLM_GEN_FMHA` pin is unchanged, and `flashinfer/mla/_core.py` changed only by the sparse-MLA backend hardening of #5591. The Cake route in this PR is compared against exactly those implementations. ## Unsupported (rejected explicitly) Unchanged from #5552 / #5602: sparse top-k MLA, attention sinks, LSE output, DCP, skip-softmax, FP16 softmax, PDL as a caller option (`enable_pdl`: the attention kernel is an ordinary launch on the caller's stream; internally the route launches its split-KV merge as a programmatic dependent of the attention kernel), NVFP4 / uint8 caches, `multi_ctas_kv_counter_buffer`. Requests with > 64 packed rows whose longest KV is below 8192 tokens run the 96-row tiles. ## Tests - `tests/mla/test_cake_kimi_k3_mla.py` (30 cases): **30 passed on B200, 30 passed on B300** on the generated programs of this PR head; the dispatch slice 18 passed (B200) / 12 passed + 6 skipped (B300). Upstream pre-commit hooks pass on the changed files (the only diff they propose is a pre-existing ruff re-wrap of an untouched host line, identical to the one reported in #5602). - Export receipts (exporter's own source-vs-export timing, `source/export` = the Cake launcher over the FlashInfer program, per row and GPU): <details><summary>export receipts, 29 rows x 2 GPUs</summary> | row | route | B200 source us | B200 export us | src/exp | verdict | B300 source us | B300 export us | src/exp | verdict | |---|---|---:|---:|---:|---|---:|---:|---:|---| | mtp_h12_fixed_q5 | main_rt64_reduce_w2 | 302.0 | 302.0 | 1.0002 | PASS | 266.7 | 266.6 | 1.0004 | PASS | | mtp_h96_fixed_q8_kv8000 | main_rt96_reduce_w1 | 139.3 | 139.3 | 1.0000 | PASS | 125.5 | 125.5 | 1.0000 | PASS | | trace_h12_b1_q1_kv76800 | main_rt16_reduce_cta | 21.7 | 21.4 | 1.0135 | PASS | 21.3 | 21.0 | 1.0122 | PASS | | trace_h12_b2_q1_kv77699 | main_rt16_reduce_cta | 29.2 | 29.2 | 0.9989 | PASS | 28.9 | 28.9 | 1.0000 | PASS | | trace_h12_b3_q1_kv261120 | main_rt16_reduce_cta | 89.9 | 89.9 | 0.9996 | PASS | 90.1 | 90.4 | 0.9975 | PASS | | trace_h12_b4_q1_kv268800 | main_rt16_reduce_cta | 112.1 | 112.0 | 1.0006 | PASS | 113.3 | 113.3 | 1.0006 | PASS | | trace_h12_b5_q1_kv276480 | main_rt16_reduce_w4 | 139.2 | 139.5 | 0.9979 | PASS | 140.0 | 140.4 | 0.9973 | PASS | | trace_h12_b6_q1_kv467751 | main_rt16_reduce_w4 | 254.4 | 254.5 | 0.9995 | PASS | 254.5 | 254.7 | 0.9995 | PASS | | trace_h12_b7_q1_kv299613 | main_rt16_reduce_w4 | 196.5 | 196.4 | 1.0010 | PASS | 197.2 | 197.1 | 1.0010 | PASS | | trace_h12_b8_q1_kv342305 | main_rt16_reduce_w4 | 249.7 | 249.9 | 0.9994 | PASS | 248.4 | 248.5 | 0.9995 | PASS | | trace_h12_b9_q1_kv348705 | main_rt16_reduce_w4 | 281.9 | 282.2 | 0.9990 | PASS | 279.7 | 280.0 | 0.9991 | PASS | | trace_h12_b10_q1_kv474166 | main_rt16_reduce_w4 | 428.1 | 428.0 | 1.0002 | PASS | 412.5 | 412.5 | 1.0000 | PASS | | trace_h12_b11_q1_kv474405 | main_rt16_reduce_w4 | 473.8 | 474.0 | 0.9995 | PASS | 448.8 | 449.0 | 0.9996 | PASS | | mirror_h96_b1_q1_kv76800 | main_wide_reduce_cta | — | — | — | FAIL: failed gates: directional_disagreement | 23.0 | 22.9 | 1.0056 | PASS | | mirror_h96_b2_q1_kv77699 | main_wide_reduce_cta | — | — | — | FAIL: failed gates: directional_disagreement | 33.3 | 32.8 | 1.0146 | PASS | | mirror_h96_b6_q1_kv467751 | main_wide_reduce_w2 | 365.0 | 364.4 | 1.0018 | PASS | 318.6 | 318.3 | 1.0009 | PASS | | mirror_h96_b7_q1_kv299613 | main_wide_reduce_w2 | 269.7 | 269.5 | 1.0007 | PASS | 235.5 | 235.1 | 1.0016 | PASS | | mirror_h96_b8_q1_kv342305 | main_wide_reduce_w2 | 357.3 | 357.0 | 1.0011 | PASS | 310.9 | 310.5 | 1.0012 | PASS | | mtp_h12_b8_q2_kv342305 | main_rt32_reduce_w4 | 263.2 | 263.5 | 0.9989 | PASS | 253.0 | 253.2 | 0.9992 | PASS | | mtp_h12_b8_q4_kv342305 | main_rt48_reduce_w2 | 291.0 | 291.3 | 0.9991 | PASS | 262.3 | 262.2 | 1.0002 | PASS | | mtp_h12_b8_q8_kv342305 | main_wide_reduce_w2 | 356.7 | 356.4 | 1.0010 | PASS | 311.9 | 311.5 | 1.0013 | PASS | | mtp_h96_b8_q2_kv342305 | main_wide_reduce_w1 | 669.3 | 669.0 | 1.0006 | PASS | 600.3 | 599.9 | 1.0006 | PASS | | mtp_h96_b8_q4_kv342305 | main_wide_reduce_w1 | 1030.9 | 1030.3 | 1.0006 | PASS | 910.2 | 909.7 | 1.0005 | PASS | | mtp_h96_b8_q8_kv342305 | main_wide_reduce_w1 | 1886.4 | 1886.1 | 1.0002 | PASS | 1779.6 | 1778.7 | 1.0005 | PASS | | prefill_h12_b1_q2048_kv131072 | main_wide_reduce_w1 | 2611.1 | 2611.3 | 0.9999 | PASS | 2488.5 | 2488.1 | 1.0002 | PASS | | prefill_h12_b2_q512_kv32768 | main_wide_reduce_w1 | 336.5 | 336.3 | 1.0009 | PASS | 316.9 | 316.6 | 1.0010 | PASS | | prefill_h12_b4_q1024_kv8192 | main_wide_reduce_w1 | 339.6 | 339.2 | 1.0011 | PASS | 308.6 | 308.3 | 1.0010 | PASS | | prefill_h96_b1_q2048_kv131072 | main_wide_reduce_w1 | — | — | — | FAIL: InterleavedTimingError: reportable loaded SM clock 1222/1965 MHz is below t | — | — | — | FAIL: InterleavedTimingError: reportable loaded SM clock 1215/2032 MHz is below t | | prefill_h96_b2_q512_kv32768 | main_wide_reduce_w1 | 2634.6 | 2633.7 | 1.0004 | PASS | 2490.4 | 2490.0 | 1.0001 | PASS | sm_100a: passed 26/29, perf geomean source/export 1.0007 (n=26) sm_103a: passed 28/29, perf geomean source/export 1.0013 (n=26) </details> ## Baselines-free numerics evidence carried over from the kernel rounds Every route was measured against the FP32 reference on the producer tree of this PR: the routed kernel passes all functional rows at 0.01 / 0.02 on both GPUs (forced-wide and routed plans, 8 rows each), compute-sanitizer synccheck + memcheck and the registered synccheck gate pass, and the 20 unchecked perf rows pass on both GPUs (20 / 20 rows on each GPU, 0 mismatches, max_abs 0.00586 on `prefill_h96_b1` against atol 0.01 / rtol 0.02). The kernel change removes a barrier only; numerics are bitwise those of r52. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Updated FP8 paged attention execution for supported SM100A and SM103A GPUs. Existing inputs, launch settings, and user-facing configuration remain unchanged. The update changes how synchronization is handled during attention processing; no user-facing API changes are included. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Yingyi Huang <averyh@nvidia.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This was referenced Sep 28, 2026
yyihuang
added a commit
that referenced
this pull request
Sep 28, 2026
…03 (persistent-item epilogue, index ring, retained-KV decode body, SwapsAb V alias, routing) (#5630) ## Summary Round-3 performance of the `backend="cake"` DeepSeek-V4 sparse-MLA decode path of `trtllm_batch_decode_sparse_mla_dsv4` (SM100a / SM103a), regenerated from the same producer pipeline as #5610: - **FP8/H128 persistent prefill program (128+ query-token rows):** the steady KV tile already runs at the tensor-pipe floor; the per-item epilogue drained the 64x256 fp32 accumulator with 16-byte stores (4096 half-sector transactions per CTA per item). It now uses 32-byte stores. prefill-style-000089 / 000093: GB300 1.24x / 1.23x -> **1.33x / 1.31x**, B200 1.17x / 1.18x -> **1.25x / 1.25x** vs the default path. - **Sub-128-token FP8/H128 uniform-gather program:** compiled without `--register-usage-level=10` (kept on the lane-gather program): -5.8 % SASS, GB300 decode rows 007/010/031/034 1.24x -> **1.26x**. - **BF16/H128 striped prefill program:** the sparse-index block of the next work item is staged during the current item (two-slot ring) and loaded batched. prefill-style-000088 / 000092: GB300 1.23x -> **1.34x / 1.35x**, B200 1.13x -> **1.21x / 1.22x**; hardening rows 21-37 all faster. - **BF16/H32 retained-KV decode program (rows 73/74/76/77):** hoisted scale loads, one epilogue release fence, eight warps issue the gathers: GB300 1.08-1.10x -> **1.30-1.34x**, B200 1.09-1.12x -> **1.32-1.33x**. - **BF16/FP8 H8/H16 decode programs (16 rows):** PV reads the V quarter from the staged K tile instead of re-gathering it: GB300 FP8 rows 1.36x -> **1.47x** (geomean), BF16 1.23x -> **1.31x**; B200 1.39x -> **1.52x**, 1.26x -> **1.35x**. - **Routing:** width-260 BF16/H128 topk128x rows run the four-owner two-stage program (GB300 1.23x -> **1.44x**, B200 1.11x -> **1.29x**); dense (not ragged) BF16/H64 rows follow the ragged rules (fixed-Q guard row: GB300 1.03x -> **1.21x**, B200 1.03x -> **1.11x**); the three-owner topk128x program and the fixed-Q programs are no longer reachable and leave the registry. - Every other program is a byte-identical regeneration (renamed for the new producer revision). ## Validation Export r12 (this branch: host and tests at `84b04ff02`, regenerated programs as published here), same-session paired CUPTI (active-union median, 500 warmup / 3000 calls per arm, cold L2) against the default trtllm-gen path at the same revision: | | GB300 (sm_103a) | B200 (sm_100a) | |---|---|---| | 94 canonical + 40 hardening shapes correct (BF16 atol=rtol=1e-2, FP8 0.1; padded / separate-table / offset axes) | 134/134 | 134/134 | | **94 canonical rows faster than the default path** | 94/94, geomean **1.300x**, min 1.098x (#5610: 1.243x, min 1.054x) | 94/94, geomean **1.280x**, min 1.027x (#5610: 1.232x, min 1.041x) | | 40 hardening rows faster than the default path | 40/40, geomean 1.330x, min 1.071x (#5610: 1.30x, min 1.058x) | 40/40, geomean 1.307x, min 1.065x (#5610: 1.25x, min 1.037x) | | exported program vs source build (agreement gate, 134 rows) | 134/134, geomean 1.0018 | 134/134, geomean 1.0026 | | compute-sanitizer synccheck + memcheck on the changed kernels | 0 errors | 0 errors | | `tests/mla/test_cake_dsv4*.py` (GPU, fresh clone of this commit) | 296 passed | 296 passed | | `tests/mla/test_cake_dsv4*.py` (CPU, this host) | 212 passed, 84 skipped | 212 passed, 84 skipped | ## Baselines and their source PRs - **trtllm-gen default path** = `trtllm_batch_decode_sparse_mla_dsv4(...)` without `backend="cake"` (the TRTLLM-GEN DSv4 sparse-MLA kernels plus the framework launches it needs for equal semantics: padded-Q masking, separate-table merge, workspace/counter handling). Origin PRs: #3269 (9c76c99, 2026-05-21); SM120 kernels #3395 (f954694, 2026-06-15); DSv4.1 unification #5197 (eb5f05b, 2026-09-18). - **Cake backend under test** = `backend="cake"` from #4573 (13db2cf, 2026-09-16), hardened by #5591 (8589d49), round 2 #5610 (4b8167e, 2026-09-27), regenerated again by this PR. - **Test oracle** = the PyTorch reference of `tests/mla/test_cake_dsv4.py` / `test_cake_dsv4_hardening.py`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Updated CAKE DSv4 routing across supported GPU variants, including revised handling for dense BF16/H64 queries and selected BF16/H128 input widths. * Expanded coverage for sparse-index staging and attention processing across value-head groups. * **Performance** * Optimized output packing and stores, and adjusted kernel staging and memory allocation for updated execution paths. * **Compatibility** * Removed obsolete kernel variants and registrations; workloads that previously used those routes may now follow different supported routes. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Yingyi Huang <averyh@nvidia.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
yyihuang
added a commit
that referenced
this pull request
Sep 28, 2026
…0/SM103 (stacked on #5630) (#5644) ## Summary Round-4 performance of the `backend="cake"` DeepSeek-V4 sparse-MLA decode path of `trtllm_batch_decode_sparse_mla_dsv4` (SM100a / SM103a), regenerated from the same producer pipeline as #5630 (this PR is stacked on #5630; host and tests unchanged): - **BF16/FP8 H8/H16 decode programs (16 rows):** the FP8 body issues its K gathers back-to-back after hoisting the page-offset loads and runs an 8-slot K ring; both bodies get a deeper K/V alias ring so a 3-tile item's second tile no longer waits for the first PV. GB300 FP8 rows 1.40x -> **1.70x** (geomean), B200 1.52x -> **1.73x**; 3-tile BF16 rows -0.2..-0.5 us (GB300 decode-000062 1.50x -> 1.64x). - **BF16/H128 persistent prefill programs (128+ query-token rows and the K-reuse rows):** FA4-style lazy softmax rescale (a row keeps its running max until the true max grows by more than 2^8; the deferred factor is applied then). prefill-style-000088: GB300 1.34x -> **1.47x**, B200 1.22x -> **1.37x**; 000092 1.35x -> **1.41x** / 1.22x -> **1.33x**. - **BF16 one-tile SWA decode programs (18 rows):** the sparse-index load is issued before the Q TMA (statement order only; bit-identical output): -0.1..-0.26 us per row. - Every other program is a byte-identical regeneration (renamed for the new producer revision). ## Validation Export r13 (regenerated programs as published here; host and tests at #5630's `76d586ff6`), same-session paired CUPTI (active-union median, cold L2) against the default trtllm-gen path at the same revision: | | GB300 (sm_103a) | B200 (sm_100a) | |---|---|---| | 94 canonical + 40 hardening shapes correct (BF16 atol=rtol=1e-2, FP8 0.1; padded / separate-table / offset axes) | 134/134 | 134/134 | | **94 canonical rows faster than the default path** | 94/94, geomean **1.343x**, min 1.130x (#5630: 1.300x, min 1.098x) | 94/94, geomean **1.319x**, min 1.048x (#5630: 1.280x, min 1.027x) | | 40 hardening rows faster than the default path | 40/40, geomean **1.353x**, min 1.085x (#5630: 1.330x, min 1.071x) | 40/40, geomean **1.310x**, min 1.069x (#5630: 1.307x, min 1.065x) | | compute-sanitizer synccheck + memcheck on the changed kernels | 0 errors | 0 errors | | `tests/mla/test_cake_dsv4*.py` (GPU, fresh clone of this commit) | 296 passed | 296 passed | ## Baselines and their source PRs - **trtllm-gen default path** = `trtllm_batch_decode_sparse_mla_dsv4(...)` without `backend="cake"` (the TRTLLM-GEN DSv4 sparse-MLA kernels plus the framework launches it needs for equal semantics: padded-Q masking, separate-table merge, workspace/counter handling). Origin PRs: #3269 (9c76c99, 2026-05-21); SM120 kernels #3395 (f954694, 2026-06-15); DSv4.1 unification #5197 (eb5f05b, 2026-09-18). - **Cake backend under test** = `backend="cake"` from #4573 (13db2cf, 2026-09-16), hardened by #5591 (8589d49), round 2 #5610 (4b8167e), round 3 #5630 (76d586f), regenerated again by this PR. - **Test oracle** = the PyTorch reference of `tests/mla/test_cake_dsv4.py` / `test_cake_dsv4_hardening.py`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Performance Improvements** * Updated attention processing to handle more key/value data stages per pipeline, potentially improving throughput. * Sparse-index lookups now occur earlier in the loading process, helping streamline attention data preparation. * **Numerical Improvements** * Refined softmax accumulation to avoid unnecessary correction for small score changes while preserving correction for larger changes. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Yingyi Huang <averyh@nvidia.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
yyihuang
added a commit
that referenced
this pull request
Sep 29, 2026
…0/SM103 (exact numerics; stacked on #5644) (#5686) ## Summary Round-5 performance of the `backend="cake"` DeepSeek-V4 sparse-MLA decode path of `trtllm_batch_decode_sparse_mla_dsv4` (SM100a / SM103a), regenerated from the same producer pipeline as #5644, plus one host-side binding line. Every regenerated program computes bit-identical output to its #5644 predecessor: this round only re-times data movement and epilogues, with no change to the arithmetic. - **BF16 H8/H16 decode programs (16 rows):** eight warps issue the K gathers (both arches); the FP8 H8/H16 programs do the same on SM100a. - **BF16/H128 persistent prefill programs (SM103a):** the O epilogue loads the next tile's TMEM accumulator ahead of the store (−1.5..−4.3 %). - **BF16/H64 split-K decode programs (9 rows):** owner-CTA form with hoisted partial select, zero-fill and 256-bit stores: −1.7..−2.9 us per row (GB300 class geomean 1.25x -> **1.51x**, B200 1.18x -> **1.45x**). - **FP8/H128 persistent prefill programs:** TMA-store O epilogue (−0.5..−0.6 us on the 9-tile rows, −7.3 % on prefill-style-000093). - **BF16/H32 retained-KV decode programs (4 rows):** the softmax publishes P before the row-sum exchange (separate stats barrier), −0.3..−1.2 %. - Every other program is a byte-identical regeneration (renamed for the new producer revision). - **Host (`flashinfer/mla/cake_dsv4.py`, first commit of this branch):** the FP8 persistent bodies now store O through a TMA descriptor (`tmap_o`); `_TMA_SOURCE_ALIASES` binds it to the same `[tokens, heads, 512]` output rows the plain `O` argument sees. Without it every FP8 launch on those routes raised "argument 'tmap_o' (tma_buffer) has no host value" (28 failures in the hardening tests on the regenerated programs alone). `test_registered_arg_plans_use_known_names` now also requires every TMA descriptor to alias a tensor the host actually places in its value table, so a vocabulary-only match cannot pass again. ## Validation Exports of the regenerated programs as published here (B200: export r15 against #5644's `6d479bea1`; GB300: export r16 against this branch's host-fix commit `fd2131236`), same-session paired CUPTI (active-union median, cold L2) against the default trtllm-gen path at the same revision: | | GB300 (sm_103a) | B200 (sm_100a) | |---|---|---| | 94 canonical + 40 hardening shapes correct (BF16 atol=rtol=1e-2, FP8 0.1; padded / separate-table / offset axes) | 134/134 correct; 133/134 export gates (row 085: baseline-arm order sensitivity, see doc § Round-over-round) | 134/134 | | **94 canonical rows faster than the default path** | 94/94 > 1, geomean **1.370x**, min 1.129x (#5644: 1.343x, min 1.130x) | 94/94, geomean **1.356x**, min 1.103x (#5644: 1.319x, min 1.048x) | | 40 hardening rows faster than the default path | 40/40 > 1, geomean **1.385x**, min 1.096x (#5644: 1.353x, min 1.085x) | 40/40 > 1, geomean **1.333x**, min 1.045x (#5644: 1.310x, min 1.069x) | | output bit-identical to the #5644 programs on every changed row | yes | yes | | compute-sanitizer synccheck + memcheck on the changed kernels | 0 errors | 0 errors | | `tests/mla/test_cake_dsv4*.py` (GPU, fresh clone of this commit) | 296 passed, 0 failed | 296 passed, 0 failed | ## Baselines and their source PRs - **trtllm-gen default path** = `trtllm_batch_decode_sparse_mla_dsv4(...)` without `backend="cake"` (the TRTLLM-GEN DSv4 sparse-MLA kernels plus the framework launches it needs for equal semantics: padded-Q masking, separate-table merge, workspace/counter handling). Origin PRs: #3269 (9c76c99, 2026-05-21); SM120 kernels #3395 (f954694, 2026-06-15); DSv4.1 unification #5197 (eb5f05b, 2026-09-18). - **Cake backend under test** = `backend="cake"` from #4573 (13db2cf, 2026-09-16), hardened by #5591 (8589d49), round 2 #5610 (4b8167e), round 3 #5630 (ebe0efb), round 4 #5644 (6d479be), regenerated again by this PR. - **Test oracle** = the PyTorch reference of `tests/mla/test_cake_dsv4.py` / `test_cake_dsv4_hardening.py`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added output tensor-map support for selected CAKE DSV4 attention paths, enabling outputs to be staged and transferred through optimized tensor operations. * Updated selected kernels to process larger output groups and adjust work distribution for supported GPU architectures. * Refreshed kernel-family registration and dispatch across supported architectures. * **Bug Fixes** * Improved handling of invalid key/value indices and synchronization of output statistics and transfers. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Yingyi Huang <averyh@nvidia.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
yyihuang
added a commit
that referenced
this pull request
Sep 30, 2026
…0/SM103 (exact numerics; stacked on #5686) (#5700) ## Summary Round-6 performance of the `backend="cake"` DeepSeek-V4 sparse-MLA decode path of `trtllm_batch_decode_sparse_mla_dsv4` (SM100a / SM103a), regenerated from the same producer pipeline as #5686. No host change. Every regenerated program computes bit-identical output to its #5686 predecessor: this round only re-times data movement, store widths, pipeline depths and the kernel ABI, with no change to the arithmetic. - **BF16/H128 split-K programs, classes E / F / B / C (18 rows):** reducer family — 256-bit partial stores, batched partial loads, and a leaner 5-split reducer on SM103a; class E additionally gets a per-arch owner (SM100a: 4-stage K ring; SM103a: new 8-slot K/PV ring body). E rows −2.7..−3.7 us (GB300) / −2.3..−2.5 us (B200); F rows −0.4..−0.5 us; B S=3 rows −0.65..−0.70 us. - **FP8/H64 single-CTA SWA programs, class K1 (11 rows):** 256-bit O stores in the lane-per-row epilogue, −0.06..−0.27 us. - **BF16 one-tile SWA programs, classes A / D / G (17 rows) + the H32 retained-KV and H8/H16 guards decode programs (SM103a):** tensor maps passed by value (`__grid_constant__`) instead of through a pointer, −0.26..−1.03 us per row (−4.6..−9.0 % on A/D/G). - **FP8/H64 wide one-partition programs, class K4 (2 rows):** third 32 KiB K stage, −0.06..−0.16 us. - **FP8/H128 persistent programs, classes K2 / L (33 rows, SM103a):** epilogue TMEM load-ahead of 4, −0.6..−3.3 % on the H128 rows. - **BF16/H128 striped prefill programs, class M (7 rows):** V rows issued ahead (LDS order only), −1.5..−4.7 % (B200), −0.3..−1.6 % (GB300). - **BF16 H8/H16 decode programs, class H (8 rows, SM100a):** the never-read padded gather rows of the last item are skipped, −0.45..−1.02 us on the padded rows. - Every other program is a byte-identical regeneration (renamed for the new producer revision). ## Validation Exports of the regenerated programs as published here (B200: export r16; GB300: export r17, both from Cake tree `939659882ba` against a fresh clone of #5686's `10c80d75b`), same-session paired CUPTI (active-union median, cold L2) against the default trtllm-gen path at the same revision: | | GB300 (sm_103a) | B200 (sm_100a) | |---|---|---| | 94 canonical + 40 hardening shapes correct (BF16 atol=rtol=1e-2, FP8 0.1; padded / separate-table / offset axes) | 134/134 correct; 134/134 export gates | 134/134 correct; 134/134 export gates (decode-000002 and hardening-000036 in a second measurement round, see doc § Gate table) | | **94 canonical rows faster than the default path** | 94/94 > 1, geomean **1.411x**, min 1.116x (#5686: 1.370x, min 1.129x) | 94/94 > 1, geomean **1.352x**, min 1.075x (#5686: 1.356x, min 1.103x) | | 40 hardening rows faster than the default path | 40/40 > 1, geomean **1.390x**, min 1.092x (#5686: 1.385x, min 1.096x) | 40/40 > 1, geomean **1.354x**, min 1.085x (#5686: 1.333x, min 1.045x) | | output bit-identical to the #5686 programs on every changed row | yes (92 changed rows) | yes (48 changed rows) | | compute-sanitizer synccheck + memcheck on the changed kernels | 0 errors | 0 errors | | `tests/mla/test_cake_dsv4*.py` (GPU, fresh clone of this commit) | 296 passed, 0 failed | 296 passed, 0 failed | ## Baselines and their source PRs - **trtllm-gen default path** = `trtllm_batch_decode_sparse_mla_dsv4(...)` without `backend="cake"` (the TRTLLM-GEN DSv4 sparse-MLA kernels plus the framework launches it needs for equal semantics: padded-Q masking, separate-table merge, workspace/counter handling). Origin PRs: #3269 (9c76c99, 2026-05-21); SM120 kernels #3395 (f954694, 2026-06-15); DSv4.1 unification #5197 (eb5f05b, 2026-09-18). - **Cake backend under test** = `backend="cake"` from #4573 (13db2cf, 2026-09-16), hardened by #5591 (8589d49), round 2 #5610 (4b8167e), round 3 #5630 (ebe0efb), round 4 #5644 (6d479be), round 5 #5686 (10c80d7), regenerated again by this PR. - **Test oracle** = the PyTorch reference of `tests/mla/test_cake_dsv4.py` / `test_cake_dsv4_hardening.py`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added optimized attention-kernel variants for newer NVIDIA GPU architectures, including improved handling of split outputs and KV data. * Removed the need for callers to provide a separate tensor-map workspace for several kernel variants. * **Performance Improvements** * Optimized data loading, pipelining, and output conversion across multiple GPU variants. * Added a specialized path for combining three partial outputs. * **Bug Fixes** * Improved bounds handling for gathered KV rows, including out-of-range indices. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Yingyi Huang <averyh@nvidia.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
7 tasks
3 tasks done
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.
Developed by the CAKE team, the kernels in this PR outperform the relevant SOTA baselines at the time of merge on the vast majority of performance benchmark shapes, matching them otherwise.
Summary
Hardens the
backend="cake"DeepSeek-V4 sparse-MLA decode path oftrtllm_batch_decode_sparse_mla_dsv4(SM100a / SM103a) for the asks in #4671 and re-exports the generated programs:
num_tokens,-1neverdereferenced, padded output rows untouched);
extra_sparse_indices,extra_sparse_topk_lens) are consumed in-kernel,the combined table keeps working;
get_cake_dsv4_workspace_bytes(...), no device allocation on any call path (MTP, CUDA graphcapture), split counters self-reset;
sparse_topk_lens_offset;rows use the persistent prefill body from 64 tokens (
_BF16_H128_PREFILL_MIN_TOKENS), BF16/H128 topk128x width260/388 rows above 16 tokens use the row-first single-owner program (
_BF16_TOPK128X_SPLIT_MAX_TOKENS);FP8/H64 rows admitted to the persistent body with >= 128 tokens use the H64-specific single-CTA M64 program
(
fp8_h64_prefill_source_persistent_m64,_FP8_H64_M64_MIN_TOKENS); BF16/H32 topk4x rows share the retained-KVtopk128x program (
bf16_h32_topk128x_early_v47, last-arriver split merge);of the prefill body (
bf16_h128_prefill_v42_snake,_bf16_h128_prefill_uses_snake_feed);bf16_h128_prefill_v42_snakeis regenerated from a K-reuse body (the PV operand is served from thegathered K tile, 25 % fewer L2 bytes per KV tile); the striped program is byte-identical to the previous export;
than 8 in the exp2 domain, so most tiles skip the TMEM rescale on the serial PV chain; P stays inside e4m3, O / sum unchanged);
1-CTA SwapsAb body (
fp8_h8_h16_source_exact, heads on the MMA N side), 1.24-1.49x vs the default path on both arches;FP8/H64 rows with >= 3 complete sparse tiles -> the persistent FP8 body, BF16/H128 topk128x width 260/388 -> the
two-stage split3/split4 programs on both targets.
Also hardens the default trtllm-gen host path (#4671 P1/P4, see
flashinfer/mla/_core.py).Validation
Export r9 (Cake 421f1a5671a, this branch at f63041c + the regenerated programs), same-session paired CUPTI (active-union
median, 500 warmup / 3000 calls per arm, cold L2) against the default trtllm-gen path at the same revision:
tests/mla/test_cake_dsv4*.py(GPU, on the exported programs)tests/mla/test_cake_dsv4*.py(CPU, this host)The default trtllm-gen path itself is hardened for #4671 P1/P4 in
flashinfer/mla/_core.py.Baselines and their source PRs
trtllm_batch_decode_sparse_mla_dsv4(...)withoutbackend="cake"(the TRTLLM-GEN DSv4sparse-MLA kernels plus the framework launches it needs for equal semantics: padded-Q masking, separate-table merge,
workspace/counter handling). Origin PRs: Add DeepSeek V4 sparse MLA TRTLLM-GEN kernels #3269 (9c76c99, 2026-05-21,
flashinfer/decode.py,flashinfer/mla/_core.py,DSv4 TRTLLM-GEN kernels); SM120 kernels feat(attention): add SM120 sparse MLA kernels #3395 (f954694, 2026-06-15); DSv4.1 unification refactor(sparse-mla): unify SM120 execution, calibration and DSv4.1 support #5197 (eb5f05b, 2026-09-18).
backend="cake"from feat(cake_sparse_mla): support SM100 and SM103 #4573 (13db2cf, 2026-09-16,flashinfer/mla/cake_dsv4.py,flashinfer/jit/cake_dsv4.py,csrc/cake_dsv4/), regenerated by this PR.tests/mla/test_cake_dsv4.py/test_cake_dsv4_hardening.py(DSv4 RopeQuantexposure feat(mla): expose DSv4 TRTLLM-GEN RopeQuant #4918, 27d5b02, 2026-09-07).
mainat measurement: d3af75a. The branch has since merged upstreammainc0ea2a1; of the upstream commits in between, the only ones touching
flashinfer/mla/_core.py(feat(cake_mla): add generated Blackwell TRT-LLM MLA decode backend for SM100 and SM103 #4557, feat(cake_kimi_k3_mla): Cake-generated Kimi-K3 MLA FP8 paged attention backend for SM100/SM103 (backend="cake") #5552, feat(cake_mla_varq_dcp_decode): Cake MLA variable-query decode with DCP for SM100 / SM103 #5577) change_trtllm_batch_decode_with_kv_cache_mla_impl(otherbackend="cake"MLA decode paths) and leave the DSv4 default path andtrtllm_batch_decode_sparse_mla_dsv4unchanged, so the comparison above still describes the merged head.CI
tests/mla/test_cake_dsv4.pyandtests/mla/test_cake_dsv4_hardening.py(CPU and GPU parametrizations).🤖 Generated with Claude Code
References
The shared reference corpus for CAKE kernel development includes the following projects, documentation, and existing CAKE work:
These are corpus-level references. PR-specific implementation details, changes, and benchmark references are documented above.