[M3] Improve indexer for long-context decode (sm100) - #48582
Merged
Merged
Conversation
Signed-off-by: Thien Tran <gau.nernst@yahoo.com.sg>
Signed-off-by: Thien Tran <gau.nernst@yahoo.com.sg>
gau-nernst
requested review from
AndreasKaratzas,
WoosukKwon,
mgoin,
tdoublep,
tlrmchlsmth,
tomeras91,
yewentao256 and
zyongye
as code owners
July 14, 2026 07:40
zyongye
approved these changes
Jul 16, 2026
1 task done
1 task done
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 20, 2026
…wiring The MiniMax-M3 decode path currently runs its generation rows through fmha_sm100, which schedules a generation row like a context row. Three kernels ported from vLLM replace that: a CuTe DSL indexer scoring kernel, a Triton sparse block decode kernel and a trtllm-gen dense decode kernel. This lands the kernels, their custom-op registration and their correctness tests. Nothing dispatches to them yet: the MSA backend, indexer and cache manager are untouched, so the decode path is byte-for-byte what it was and the kernels are reachable only from the tests and the microbenchmark. The dispatch is a follow-up, since it rests on the device-side length patching and the fused per-layer cache writes that are still landing on feat/m3_with_msa. Split out of NVIDIA#17268 on feat/m3_with_msa, which carries the same kernels plus that wiring. Two additions differ from it. msa_indexer gains only cutedsl_score_runner and _cutedsl_score, the self-contained entry points the scorer test drives, and not the run_indexer dispatch that calls them. The tests reach fmha_sm100 through a local _flat_page_table helper, because build_kv_page_indices does not take a block table until NVIDIA#16875; the helper feeds it the slot map that block table implies, so the A/B comparisons still run against the production page-table builder rather than a test-local copy. The CuTe DSL indexer decode kernel and its tests were originally contributed to vLLM by Thien Tran (vllm-project/vllm#48582), as were the CuTe utilities (vllm-project/vllm#43273). The Triton sparse decode kernel and its tests were originally contributed to vLLM by Kaichao You (vllm-project/vllm#45381). Thanks to both. No test-list change: l0_b300 already collects unittest/_torch/attention wholesale, so the three new files are picked up there, and each skips itself off SM100/SM103. (cherry picked from commit 727c683) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 20, 2026
…wiring The MiniMax-M3 decode path currently runs its generation rows through fmha_sm100, which schedules a generation row like a context row. Three kernels ported from vLLM replace that: a CuTe DSL indexer scoring kernel, a Triton sparse block decode kernel and a trtllm-gen dense decode kernel. This lands the kernels, their custom-op registration and their correctness tests. Nothing dispatches to them yet: the MSA backend, indexer and cache manager are untouched, so the decode path is byte-for-byte what it was and the kernels are reachable only from the tests and the microbenchmark. The dispatch is a follow-up, since it rests on the device-side length patching and the fused per-layer cache writes that are still landing on feat/m3_with_msa. Split out of NVIDIA#17268 on feat/m3_with_msa, which carries the same kernels plus that wiring. Two additions differ from it. msa_indexer gains only cutedsl_score_runner and _cutedsl_score, the self-contained entry points the scorer test drives, and not the run_indexer dispatch that calls them. The tests reach fmha_sm100 through a local _flat_page_table helper, because build_kv_page_indices does not take a block table until NVIDIA#16875; the helper feeds it the slot map that block table implies, so the A/B comparisons still run against the production page-table builder rather than a test-local copy. The CuTe DSL indexer decode kernel and its tests were originally contributed to vLLM by Thien Tran (vllm-project/vllm#48582), as were the CuTe utilities (vllm-project/vllm#43273). The Triton sparse decode kernel and its tests were originally contributed to vLLM by Kaichao You (vllm-project/vllm#45381). Thanks to both. No test-list change: l0_b300 already collects unittest/_torch/attention wholesale, so the three new files are picked up there, and each skips itself off SM100/SM103. (cherry picked from commit 727c683) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 21, 2026
…wiring The MiniMax-M3 decode path currently runs its generation rows through fmha_sm100, which schedules a generation row like a context row. Three kernels ported from vLLM replace that: a CuTe DSL indexer scoring kernel, a Triton sparse block decode kernel and a trtllm-gen dense decode kernel. This lands the kernels, their custom-op registration and their correctness tests. Nothing dispatches to them yet: the MSA backend, indexer and cache manager are untouched, so the decode path is byte-for-byte what it was and the kernels are reachable only from the tests and the microbenchmark. The dispatch is a follow-up, since it rests on the device-side length patching and the fused per-layer cache writes that are still landing on feat/m3_with_msa. Split out of NVIDIA#17268 on feat/m3_with_msa, which carries the same kernels plus that wiring. Two additions differ from it. msa_indexer gains only cutedsl_score_runner and _cutedsl_score, the self-contained entry points the scorer test drives, and not the run_indexer dispatch that calls them. The tests reach fmha_sm100 through a local _flat_page_table helper, because build_kv_page_indices does not take a block table until NVIDIA#16875; the helper feeds it the slot map that block table implies, so the A/B comparisons still run against the production page-table builder rather than a test-local copy. The CuTe DSL indexer decode kernel and its tests were originally contributed to vLLM by Thien Tran (vllm-project/vllm#48582), as were the CuTe utilities (vllm-project/vllm#43273). The Triton sparse decode kernel and its tests were originally contributed to vLLM by Kaichao You (vllm-project/vllm#45381). Thanks to both. No test-list change: l0_b300 already collects unittest/_torch/attention wholesale, so the three new files are picked up there, and each skips itself off SM100/SM103. (cherry picked from commit 727c683) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 24, 2026
…wiring The MiniMax-M3 decode path currently runs its generation rows through fmha_sm100, which schedules a generation row like a context row. Three kernels ported from vLLM replace that: a CuTe DSL indexer scoring kernel, a Triton sparse block decode kernel and a trtllm-gen dense decode kernel. This lands the kernels, their custom-op registration and their correctness tests. Nothing dispatches to them yet: the MSA backend, indexer and cache manager are untouched, so the decode path is byte-for-byte what it was and the kernels are reachable only from the tests and the microbenchmark. The dispatch is a follow-up, since it rests on the device-side length patching and the fused per-layer cache writes that are still landing on feat/m3_with_msa. Split out of NVIDIA#17268 on feat/m3_with_msa, which carries the same kernels plus that wiring. Two additions differ from it. msa_indexer gains only cutedsl_score_runner and _cutedsl_score, the self-contained entry points the scorer test drives, and not the run_indexer dispatch that calls them. The tests reach fmha_sm100 through a local _flat_page_table helper, because build_kv_page_indices does not take a block table until NVIDIA#16875; the helper feeds it the slot map that block table implies, so the A/B comparisons still run against the production page-table builder rather than a test-local copy. The CuTe DSL indexer decode kernel and its tests were originally contributed to vLLM by Thien Tran (vllm-project/vllm#48582), as were the CuTe utilities (vllm-project/vllm#43273). The Triton sparse decode kernel and its tests were originally contributed to vLLM by Kaichao You (vllm-project/vllm#45381). Thanks to both. No test-list change: l0_b300 already collects unittest/_torch/attention wholesale, so the three new files are picked up there, and each skips itself off SM100/SM103. (cherry picked from commit 727c683) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
brb-nv
added a commit
to brb-nv/TensorRT-LLM
that referenced
this pull request
Aug 24, 2026
…wiring The MiniMax-M3 decode path currently runs its generation rows through fmha_sm100, which schedules a generation row like a context row. Three kernels ported from vLLM replace that: a CuTe DSL indexer scoring kernel, a Triton sparse block decode kernel and a trtllm-gen dense decode kernel. This lands the kernels, their custom-op registration and their correctness tests. Nothing dispatches to them yet: the MSA backend, indexer and cache manager are untouched, so the decode path is byte-for-byte what it was and the kernels are reachable only from the tests and the microbenchmark. The dispatch is a follow-up, since it rests on the device-side length patching and the fused per-layer cache writes that are still landing on feat/m3_with_msa. Split out of NVIDIA#17268 on feat/m3_with_msa, which carries the same kernels plus that wiring. Two additions differ from it. msa_indexer gains only cutedsl_score_runner and _cutedsl_score, the self-contained entry points the scorer test drives, and not the run_indexer dispatch that calls them. The tests reach fmha_sm100 through a local _flat_page_table helper, because build_kv_page_indices does not take a block table until NVIDIA#16875; the helper feeds it the slot map that block table implies, so the A/B comparisons still run against the production page-table builder rather than a test-local copy. The CuTe DSL indexer decode kernel and its tests were originally contributed to vLLM by Thien Tran (vllm-project/vllm#48582), as were the CuTe utilities (vllm-project/vllm#43273). The Triton sparse decode kernel and its tests were originally contributed to vLLM by Kaichao You (vllm-project/vllm#45381). Thanks to both. No test-list change: l0_b300 already collects unittest/_torch/attention wholesale, so the three new files are picked up there, and each skips itself off SM100/SM103. (cherry picked from commit 727c683) Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
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.
Purpose
This PR adds a CuteDSL indexer decode kernel for Minimax M3, optimized for long-context.
mma.syncdesign, instead of tcgen05 as I find saturating memory bandwidth with high occupancy (+ hardware scheduling) is easier than tcgen05 software pipelining, especially when there is context imbalance (different requests have different context lengths)(1 + num_speculative_tokens) * num_idx_heads <= 32. Fallback to Triton otherwiseMicrobenchmarks
#45743 reduces
TARGET_GRIDin Triton kernel from 4096 to 512. Even though this helps for uniform context lengths, it reduces load balancing effect, leading to worse performance for non-uniform context lengths. Hence, to make it a fair comparison, I'm comparing the CuteDSL kernel in this PR with both Triton-512 and Triton-4096 (i.e. using 512 or 4096 target CTAs)Benchmark done on GB300
Microbenchmark script
Uniform context lengths
BF16, TP4, normal decode — DQL1
FP8, TP4, normal decode — DQL1
FP8, TP4, Eagle3-like decode — DQL4
Non-uniform context lengths
BF16, TP4
FP8, TP4
E2E accuracy
MiniMaxAI/MiniMax-M3-MXFP8, with FP8 KV cache and FP8 Indexer cacheAIME25 (4 epochs)
E2E perf benchmarks
TP4, decode-only, 4xGB300, FP8 Indexer cache, FP8 KV cache, concurrency 48, input length 60k-120k
Note: even though the kernel is tuned and validated on sm100 only, it should work well on SM90 and SM120 as well. For SM120, explicit FP8->FP16 dequantization is not necessary. This is left for future PRs.
Essential Elements of an Effective PR Description Checklist
supported_models.mdandexamplesfor a new model.