Repository navigation
Conversation
…2/TP4 steps FlashMLA's mega-attention decode kernel takes 64 or 128 query heads. At TP2 and TP4 a rank holds 32 and 16 live heads of the 64-head model, so on small decode, verify and draft steps half or three quarters of the kernel's MMA work goes to padding heads. Add SwapABDecodeKernel, a CuTe DSL kernel adapted from SGLang's swap-AB DSv4 decode attention (Apache-2.0), in vllm/models/deepseek_v41/nvidia/ops/swapab_decode_attn.py. It puts the KV slots on the tcgen05 MMA's M side and the live heads on N. One CTA takes a 64-slot tile of a token's SWA list or a 128-slot tile of its compressed list: it gathers and dequantizes the V4.1 records (fp8 528 B, NVFP4 288 B) into SMEM, RoPEs Q and computes S = KV Q^T and O = KV^T P, with P split into bf16 hi and lo parts. A token's tiles form one thread-block cluster that merges the partials and the attention sink over DSMEM in a fixed order, applies the inverse RoPE and writes the MXFP8 output the mega kernel writes, for the live heads' groups only. It is a single PDL launch with no workspace and no host sync, CUDA-graph safe and deterministic. _forward_decode_mega takes the kernel automatically, with no new flag, when all of these hold: the GPU is SM10x; the layer has a compressed cache and 16 or 32 live heads; a token's tiles fit one portable cluster (ceil(window / 64) + ceil(index_topk / 128) <= 8); the CuTe DSL imports and is built with CUDA 13.2+, as the direct fp8 / fp4 -> bf16x2 conversions need PTX ISA 9.2; VLLM_BATCH_INVARIANT is off; the step has at most 16 decode tokens; and its SWA list is the window, which DSpark's non-causal draft steps widen. Every other step, layer and TP size keeps the mega kernel; prefill and other platforms are unchanged. The compile key holds the compressed page size, which is final only once the KV cache is allocated. So kv-source layers register it in bind_kv_cache, which runs while the runner's JIT warmup registry is active, and kernel_warmup compiles it before CUDA graph capture. The output is not bit-identical to the mega kernel's, whose fp32 sums are ordered differently. Its error against an fp64 reference is held to at most 1.1x the mega kernel's. tests/kernels/test_dsv41_swapab_decode.py checks the kernel against an fp64 reference and the mega kernel on caches written by V4.1's insert kernels; checks that padding heads' output is untouched and that eager calls and a CUDA graph replay agree bit for bit; and checks the dispatch rule and that the warmup key is the launched key. benchmarks/kernels/benchmark_dsv41_mega_attn.py gains a swap-AB arm. Signed-off-by: bofengl <bofengl@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve the import conflict with vllm-project#60118 in flash_mla_mega_attn.py: keep main's `cdiv` import next to this PR's `has_cutedsl` import. Signed-off-by: bofengl <bofengl@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every field of the compile key is fixed when the layer is built: the compressed cache is read in the mega backend's 128-token kernel blocks, so its page is 128 // compress_ratio slots whatever the manager block size is. Registering it next to the layer's other JIT warmups removes the bind_kv_cache override. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: bofengl <bofengl@nvidia.com>
Signed-off-by: bofengl <bofengl@nvidia.com>
Move tests/kernels/test_dsv41_swapab_decode.py to tests/models/deepseek_v41/nvidia/test_swapab_decode.py and run it in a single-GPU B200 step. test_warmup_key_matches_launch now checks the key registered at construction against the key a decode step launches on a compressed cache shaped by MLAAttentionSpec.get_num_kernel_states. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: bofengl <bofengl@nvidia.com>
…llm-project#64833) Signed-off-by: Andreas Karatzas <akaratza@amd.com> Co-authored-by: Claude <noreply@anthropic.com>
vllm-project#63426) Signed-off-by: Andreas Karatzas <AndreasKaratzas@users.noreply.github.com> Signed-off-by: Eddie Zhou <edward.zhou@amd.com> Signed-off-by: Andreas Karatzas <akaratza@amd.com> Co-authored-by: Andreas Karatzas <AndreasKaratzas@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Eddie Zhou <edward.zhou@amd.com> Co-authored-by: vllm-agent <claw@inferact.ai>
…ject#59999) Signed-off-by: hyunnnchoi <hyunmok.choi@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: vllm-agent <claw@inferact.ai>
…lace (vllm-project#65178) Signed-off-by: Mickael Seznec <mickael@mistral.ai> Co-authored-by: Summer Yang <girasoleyang@gmail.com>
…ject#64657) Signed-off-by: CharlesWu <Charles.Wu@amd.com> Signed-off-by: Andreas Karatzas <akaratza@amd.com> Co-authored-by: CharlesWu <Charles.Wu@amd.com> Co-authored-by: Codex <noreply@openai.com> Co-authored-by: vllm-agent <claw@inferact.ai> Co-authored-by: Claude <noreply@anthropic.com>
… builds (vllm-project#64839) Signed-off-by: Andreas Karatzas <akaratza@amd.com> Co-authored-by: Claude <noreply@anthropic.com>
…oject#62623) Signed-off-by: Chaojun Zhang <chaojun.zhang@intel.com> Co-authored-by: vllm-agent <claw@inferact.ai>
…chunks (vllm-project#64806) Signed-off-by: Bo Pang <bopang314@gmail.com> Co-authored-by: Codex <noreply@openai.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Woosuk Kwon <woosuk@inferact.ai>
…rding (vllm-project#64174) Signed-off-by: Thang Nguyen <thangnguyenvn647@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Thang Nguyen <thangnguyenvn647@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…utomatic sharding (vllm-project#64788) Signed-off-by: Thang Nguyen <thangnguyenvn647@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Thang Nguyen <thangnguyenvn647@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…nested connectors (vllm-project#65060) Signed-off-by: Yifei Wang <yifei.w@inferact.ai> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Nandana Dileep <110280757+nandanadileep@users.noreply.github.com>
…ngineCore (vllm-project#62966) Signed-off-by: Suvigya Vijay <suvigya.vijay@cohere.com> Co-authored-by: Simon Veitner <sveitner@redhat.com> Co-authored-by: Flora Feng <4florafeng@gmail.com>
…llm-project#64417) Signed-off-by: Yang Xu <yanxu@nvidia.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Wei Zhao <51183510+wzhao18@users.noreply.github.com>
vllm-project#63123) Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com> Co-authored-by: Claude <claude@anthropic.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
… adaptive verification (vllm-project#65041) Signed-off-by: Bo Pang <bopang@inferact.ai> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Woosuk Kwon <woosuk@inferact.ai>
…ck count (vllm-project#65225) Signed-off-by: Nick Hill <nickhill123@gmail.com> Co-authored-by: Vegetog <110553275+Vegetog@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: vllm-agent <claw@inferact.ai>
Signed-off-by: Alex-Wengg <hanweng9@gmail.com> Co-authored-by: vllm-agent <claw@inferact.ai>
Signed-off-by: Flora Feng <4florafeng@gmail.com>
…1971 vllm-project#61971 moved the mega attention layer to int64 RoPE positions and dropped positions_int32, so the swap-AB call merged in from main named a variable that no longer exists. The kernel now reads int64 positions like the mega kernel (it only uses them as an int64 row offset), and the benchmark and tests pass int64 positions. The CPU tests build the layer with object.__new__; initialize its nn.Module bookkeeping so monkeypatch can undo instance attributes on current torch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: bofengl <bofengl@nvidia.com>
…63420) Signed-off-by: Wei Zhao <weizha@nvidia.com> Signed-off-by: Yifan Qiao <yifanqiao@inferact.ai> Signed-off-by: wzhao18 <wzhao18.sz@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Yifan Qiao <yifanqiao@inferact.ai> Co-authored-by: Codex <noreply@openai.com>
…1b (FlyDSL, TP8, DCP1/DCP8) (vllm-project#61435) Signed-off-by: seungrokj <seungrok.jung@amd.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: vllm-agent <claw@inferact.ai>
…llm-project#60339) Signed-off-by: Nishant Revur <kumrfni@amazon.com> Signed-off-by: Nick Hill <nickhill123@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Nick Hill <nickhill123@gmail.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
…project#61795) Signed-off-by: CharlesWu <Charles.Wu@amd.com> Co-authored-by: Yichao Zhu <Yichao.Zhu@amd.com> Co-authored-by: Codex <noreply@openai.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: zhenwei-intel <zhenwei.liu@intel.com> Co-authored-by: vllm-agent <claw@inferact.ai>
…m-project#61609) Signed-off-by: David Isztl <isztld@cscs.ch> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: msimberg <mikael.simberg@iki.fi> Co-authored-by: Woosuk Kwon <woosuk@inferact.ai> Co-authored-by: vllm-agent <claw@inferact.ai>
Signed-off-by: yeh-sudo <yehchanshen@gmail.com> Signed-off-by: Thien Tran <gau.nernst@yahoo.com.sg> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Thien Tran <gau.nernst@yahoo.com.sg> Co-authored-by: Kimi <noreply@moonshot.ai> Co-authored-by: vllm-agent <claw@inferact.ai>
vllm-project#65051) Signed-off-by: Chaojun Zhang <chaojun.zhang@intel.com>
vllm-agent
requested review from
benchislett,
vadiklyutiy and
wzhao18
as code owners
November 3, 2026 03:23
…lm-project#61755) Signed-off-by: Hanjun Cho <gkswns0531@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: vllm-agent <claw@inferact.ai> Co-authored-by: Thien Tran <gau.nernst@yahoo.com.sg>
…L weight transfer docs (vllm-project#65292) Signed-off-by: Ao Shen <aoshen524@gmail.com> Co-authored-by: Ao Shen <aoshen524@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…64728) Signed-off-by: bzsuni <bingzhe.sun@daocloud.io>
…m-project#65093) Signed-off-by: Anh Tran <anhtra@nvidia.com> Co-authored-by: vllm-agent <claw@inferact.ai>
…othing (vllm-project#63076) Signed-off-by: Yang, Chenyi <chenyyan@amd.com> Signed-off-by: chennyiiis <chenyyan@amd.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Shanshan Shen <467638484@qq.com>
…utputs in vllm-bench chat (vllm-project#64626) Signed-off-by: Dilber P Shakir <dilbersha@gmail.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Roy Wang <jasonailu87@gmail.com>
…d usage (vllm-project#65036) Signed-off-by: subin9 <101092510+subin9@users.noreply.github.com>
…he_spec (vllm-project#56996) Signed-off-by: Zheng Gong <zgong@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…lm-project#57519) Signed-off-by: Tevin Shi <tevinshi2015@gmail.com>
…ds (vllm-project#65245) Signed-off-by: Dilber P Shakir <dilbersha@gmail.com>
Fold the single-GPU swap-AB step into the 4xB200 specialized-decode step and rename it to "DeepSeek-V4.1 NVIDIA Kernels", per review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: bofengl <bofengl@nvidia.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.
Overview
Makes DeepSeek-V4.1's per-layer decode attention step 1.6-2.15x faster for decode steps of up to 16 tokens at TP2 / TP4, by adding a swap-AB CuTe DSL decode attention kernel to the FlashMLA mega-attention layer (vllm-project#56935) on SM10x. Steps of up to 16
tokens with 16 or 32 live heads per rank (TP4 / TP2 of the 64-head model) now take it instead of the mega kernel, which pads the heads to 64.
Part of vllm-project#57448; it reads the interleaved V4.1 KV records from vllm-project#61371. Related work that this PR does not duplicate (see Details): vllm-project#59418, vllm-project#61615, vllm-project#57711, vllm-project#61868.
Claims
query heads to the MMA's M dimension, which is at least 64, so at TP2 and TP4 half or three quarters of its MMA work goes to padding heads; swap-AB puts the KV slots on M and only the live heads on N.
and adds no host sync.
Validation
Performance. This PR adds a swap-AB arm to the existing
benchmarks/kernels/benchmark_dsv41_mega_attn.py. Each arm's per-step ops (Q pad + KV insert + attention) are timed as a CUDA graph replay, the same harness that produced the mega vs split-KVtable in
flash_mla_mega_attn.py.Speedup = mega step time / swap-AB step time (median of two runs, which differ by at most 9% per cell):
At 32 tokens swap-AB still wins with 16 heads (1.22-1.25x) but only breaks even with 32 (0.98-1.02x), and at 64 it loses with both, so
_SWAPAB_MAX_TOKENS = 16is the largest step size where it wins for both head counts. As in the existing harness,every replay reuses the same buffers, so the KV reads hit a warm L2 for both kernels; timed alone with the L2 flushed before every call, the attention kernel is 1.6-2.3x faster than the mega kernel over 48 shapes with 1-16 tokens (geomean 1.94x).
Correctness: unit tests. The kernel tests skip unless the GPU is SM10x and the CuTe DSL is built with CUDA 13.2+.
.venv/bin/python -m pytest -v tests/kernels/test_dsv41_swapab_decode.py .venv/bin/python -m pytest -v "tests/kernels/test_compressor_kv_cache.py::test_v41_cache_writers_match_flashmla_decode"test_matches_reference(64)test_untouched_padding(2)test_cuda_graph_and_determinism(12)test_dispatch_rule(9, CPU)test_warmup_key_matches_launch(4, CPU)bind_kv_cacheregisters is the key a decode step launchestest_v41_cache_writers_match_flashmla_decode(3, existing)Details
Motivation. Mega attention is the default DeepSeek V4.1 decode path on SM10x. Its FP8 decode kernel takes 64 or 128 query heads, so at TP2 and TP4 half or three quarters of its MMA work goes to padding heads. The mega vs split-KV note in
flash_mla_mega_attn.pyalready records that this padded-head cost dominates small decode steps. Small steps are what low-concurrency decode and spec-decode verify and draft steps run.Why a separate kernel, not a FlashMLA change. FlashMLA's decode maps query heads to the MMA's M dimension, which is at least 64. Serving 16 or 32 heads without padding needs the opposite mapping, with KV slots on M and heads on N. That is a
different kernel, not a smaller tile. In FlashMLA it would be CUDA C++ shipped through a vllm-project/FlashMLA release and a vLLM bump, as vllm-project#61371 was. The CuTe DSL kernel instead compiles from Python at JIT warmup, needs no build change, and lives next
to its only caller in the DSv4.1 model package. It is adapted from SGLang's swap-AB DSv4 decode attention (Apache-2.0, attribution in the file header).
Kernel design
SwapABDecodeKernel(vllm/models/deepseek_v41/nvidia/ops/swapab_decode_attn.py) puts the KV slots on the tcgen05 MMA's M side (128 rows) and the live heads on N (16 or 32).inverse RoPE and writes MXFP8 with the mega kernel's rounding rule into the o-fused buffers
wo_areads, for the live heads' groups only.register the key in
bind_kv_cache, which both model runners call while the JIT warmup registry is active, andkernel_warmupcompiles it before CUDA graph capture. V4.1-Flash needs two keys, one per compressed page size.Dispatch.
DeepseekV4MegaAttnAttention._forward_decode_megatakes the swap-AB kernel only when all of these hold:ceil(window / 64) + ceil(index_topk / 128) <= 8;VLLM_BATCH_INVARIANTis off;_SWAPAB_MAX_TOKENS). Under CUDA graphs this is the padded count, so each captured graph holds exactly one of the two kernels;The first six conditions are fixed when the layer is built. The last two are host-side shape checks on each step. If any condition fails, the step runs the mega kernel exactly as before.
Complexity. The change adds about 1,260 lines of kernel code (about 400 of them are 23 small inline-PTX wrappers) and about 100 lines in the layer. Nothing changes in the model runner, the scheduler, FlashMLA or shared attention code. At runtime the
kernel module is imported only by SM10x layers with a compressed cache, 16 or 32 heads and an importable CuTe DSL. Most of the maintenance cost is the inline PTX and the SMEM / TMEM layout math. Both are documented next to the code, and the tests pin
them to an fp64 reference and to the mega kernel.
Tradeoffs and limitations.
least 1.6x faster at every step size up to 16 tokens.
Compatibility.
DeepseekV4MegaAttnAttentionchanges. The FlashMLA sparse layer, FlashInfer sparse MLA, and the SM90, SM120 and ROCm paths are untouched. TP1 (64 heads) and TP8 (8 heads) keep the mega kernel.CI. The new tests run in "(B200) Miscellaneous Kernels". The kernel tests need SM10x, the FlashMLA mega ops and a CuTe DSL built with CUDA 13.2+, and skip otherwise; with vLLM's pinned
nvidia-cutlass-dsl[cu13]==4.8.0they run. The optional "(B200)LM Eval Spec Decode" step runs the V4.1-Flash NVFP4 DSpark TP4 GSM8K config. It runs at full concurrency, where few steps are small enough for swap-AB.
Not a duplicate. On 2026-10-18 I searched GitHub (open PRs plus PRs since 2026-08-15) for "swap-AB", "swapab", "small-head decode", "heads padded 64 decode", "mega attention DSv4.1" and "V4.1 decode attention". No PR adds an SM10x small-head decode
kernel for the mega-attention path. Related work:
fp8_ds_mlarecords used off SM10x. This PR targets SM10x tcgen05 and 16 or 32 headsin the mega-attention layer, which reads the V4.1 records and fuses the inverse RoPE and MXFP8 output.
VLLM_DSV41_MEGA_SPLITKVenv flags and blocked on Add split-KV to the fused mega decode kernel vllm-project/FlashMLA#25. That kernel still pads the heads to 64. This PR leavesFlashMLA alone, removes the padded-head work and adds no flags.
trtllm_batch_decode_sparse_mla_dsv4. That is a separate opt-in path; this PR changes the default mega-attention path.AI assistance. This PR was prepared with AI assistance (Claude Code, Claude Opus 5.5). It drafted the port of the kernel onto main, the tests, the benchmark arm, the
/pr-checklistpass and this description. The submitter reviewed every changedline and ran the validation above.
Pull Request Checklist
I used vLLM's
/pr-checklistskill. (Mandatory for agents, optional for humans).AI assistance was used during the creation of this PR.
Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.
Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.
Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.
Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.
Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.