Repository navigation
Conversation
luoyuctl
force-pushed
the
feature/sm90-small-head-sparse-decode
branch
2 times, most recently
from
October 1, 2026 08:41
a5bf4da to
eddfa5e
Compare
luoyuctl
marked this pull request as ready for review
October 1, 2026 08:48
luoyuctl
requested review from
AndreasKaratzas,
Harry-Chen,
WoosukKwon,
khluu,
mgoin,
tlrmchlsmth,
yewentao256 and
zyongye
as code owners
October 1, 2026 08:48
positive666
added a commit
to positive666/vllm
that referenced
this pull request
Oct 6, 2026
Adapt the decoder from luoyuctl's PR vllm-project#59418 at eddfa5ed50c16a632b8fae2e523ad54e504f3e0b as the shared dependency for the independent native-head backend. Specialize the three page-size parameters as tl.constexpr; otherwise keep the decoder unchanged. Keep this shared contribution separate from backend integration and query-pairing changes. Co-authored-by: zack <51604064+luoyuctl@users.noreply.github.com> Co-authored-by: OpenAI Codex <noreply@openai.com> Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Cheng Rui <286040359@qq.com>
positive666
added a commit
to positive666/vllm
that referenced
this pull request
Oct 6, 2026
Address vllm-project#57673 review with centralized opt-in selection and independent Triton prefill/decode. Share exact sparse KV unions across eligible verification-query pairs; preserve per-forward and CUDA Graph lifetimes. Add startup warmup, correctness and compatibility coverage, H100 CI, and backend usage documentation. Default backend selection is unchanged. The paired decoder derives its KV loader and split softmax from vllm-project#59418; query-union prior art is vllm-project#55372. Co-authored-by: zack <51604064+luoyuctl@users.noreply.github.com> Co-authored-by: OpenAI Codex <noreply@openai.com> Signed-off-by: Cheng Rui <286040359@qq.com>
6 tasks done
Co-authored-by: OpenAI Codex <noreply@openai.com> Signed-off-by: zack <51604064+luoyuctl@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: zack <51604064+luoyuctl@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: zack <51604064+luoyuctl@users.noreply.github.com>
luoyuctl
force-pushed
the
feature/sm90-small-head-sparse-decode
branch
from
October 6, 2026 11:37
eddfa5e to
1dfa1f7
Compare
Route both small-head launches through triton_kernel_dispatcher_with_warmup and register every split config, HAS_EXTRA variant and DSpark SWA width the layer can dispatch, so no Triton compile happens on the serving path. Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: zack <51604064+luoyuctl@users.noreply.github.com>
Contributor
|
I also noticed this issue before, but I was exploring whether we could support it in FlashMLA: vllm-project/FlashMLA#26 |
Contributor
Author
|
@chaunceyjiang we can have a quick discussion, should this kernel move into vllm-project/FlashMLA? I wrote it as a Triton kernel in vLLM because it carries scheduling logic: a token-count and key-width gate, plus a split table ( |
This was referenced Oct 19, 2026
Closed
4 of 9 tasks
Contributor
|
This pull request has merge conflicts that must be resolved before it can be |
…head-sparse-decode Signed-off-by: zack <51604064+luoyuctl@users.noreply.github.com>
Contributor
|
This pull request has merge conflicts that must be resolved before it can be |
…head-sparse-decode Signed-off-by: zack <51604064+luoyuctl@users.noreply.github.com>
Merged
2 tasks
Signed-off-by: zack <51604064+luoyuctl@users.noreply.github.com>
6 tasks
This branch has not been deployed
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
On SM90, FlashMLA's sparse decode tiles query heads by 64 (the WGMMA M dimension). A DeepSeek V4.1 TP8 rank owns only 8 heads (16 at TP4), so it pads them to 64 and spends most of the tensor-core work on padding. This adds a Triton sparse decode kernel that tiles heads by 16 with
tl.dot(mma.sync), reads the existing packed FP8 MLA cache directly, and recovers parallelism by splitting the key set across programs, merging the partial results with log-sum-exp.Why it is faster at small batches. At a few decode tokens per step, FlashMLA launches roughly one CTA per token and each CTA does 64-head work for 8 real heads. This kernel launches
tokens × splitsprograms, each doing 16-head work over its share of keys. The best split count depends on both token count and key width: 32 splits at ≤3 tokens fills the GPU, but by 8 tokens 8 splits wins because the merge cost and per-program gather overhead dominate._pick_configencodes this measured table. At larger batches the step becomes gather/dequant-bound rather than MMA-bound, so removing the padding no longer helps and FlashMLA is kept.Dispatch (automatic, no flag): SM90, 8 or 16 local heads, decode only, and
index_topk=512)The gate is decode tokens per rank per step (≈ batch × (1 + spec tokens)), so the gain is limited to low-concurrency decode. It does not depend on context length, since sparse attention reads a fixed number of keys per token. Prefill always uses FlashMLA.
JIT warmup: both launches register every split config,
HAS_EXTRAvariant and DSpark SWA width with the startup JIT warmup, so no Triton compile happens on the serving path.Related to #48168.
Not a duplicate: I checked the issue discussion and open PRs for #48168 and for small-head sparse decode; none implements this SM90 decode path. #57673 has since been reworked into an opt-in backend that reuses this PR's decoder (with attribution) but does not add the automatic FlashMLA dispatch. #55866 targets FA4 sparse MQA on Blackwell, #51403 targets ROCm.
Test Plan
End-to-end on 8× H20 (one node), TP8, DSpark K=2, same flags as our production deployment except
--max-model-len 32768. Both arms ran on the same node and the same image, back-to-back:vllm bench serve --backend openai-chat --dataset-name random \ --random-input-len 1024 --random-output-len 1024 --ignore-eos --seed 42 \ --max-concurrency {1,2,4,8,16,32} lm_eval --model local-chat-completions --tasks gsm8k --num_fewshot 5 \ --apply_chat_template --fewshot_as_multiturn --gen_kwargs temperature=0Test Result
End-to-end (8× H20, TP8)
Median ITL is per decode step; concurrency 1–4 falls inside the gate (≤12 tokens/step with K=2).
Throughput also reflects DSpark acceptance length, which varied by run (2.06–2.23 stock vs 2.14–2.31 this PR), so ITL is the cleaner signal.
GSM8K (full 1319, 5-shot chat, greedy, flexible extract): stock 89.99% (1187), this PR 89.92% (1186), stderr ±0.83%. Per question, 19 flip to correct and 20 flip to wrong, consistent with split-K reduction order changing near-tie greedy tokens.
Operator benchmark (1× H20)
108 configurations (tokens 1–16/24/32 × heads 8/16 × top-k 0/64/512), CUDA graphs, cold-L2 input rotation, median of 3 alternating rounds, CUDA-event timing. Every configuration inside the gate is faster than FlashMLA; none regresses.
JIT warmup (8× H20, TP8, DSpark K=2): with
--jit-monitor-mode warn, 92 requests at concurrency 1–8 all succeeded with zero small-head kernel compiles after startup; warmup compiles 8 decode + 3 merge variants in 2.3 s on one GPU.Correctness: 44 focused tests pass on H20 (FP32 reference and FlashMLA comparisons, 64/128-token pages, 8/16 heads, non-contiguous views, invalid/empty rows, CUDA graph replay, dispatch at the gate boundary). Pre-commit passes.
AI assistance: OpenAI Codex and Claude were used to implement, tune, benchmark, and validate this change. I reviewed every changed line and ran the tests above.