Repository navigation
[Bugfix][Attention] Fix FlashInfer MLA DCP decode on ragged spec-decode batches - #59392
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: zjy0516 <riverclouds.zhu@qq.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: zjy0516 <riverclouds.zhu@qq.com>
|
Thanks for the fix! We validated the Both runs used the same image, model, server flags and environment variables; the only runtime change was this PR’s patch to
Results:
The serving check used synthetic prompts with 1,000 input / 1,000 requested output tokens, concurrency 1 and This validates startup and basic serving for the reported configuration. There was one run per arm, and no accuracy evaluation was performed. Multi-request ragged batches were exercised during warmup; we did not separately target the evenly divisible ragged case described in this PR. Drafted with assistance from Codex (GPT-6). |
|
/ci run |
|
✅ Triggered Buildkite CI #94737 for commit ℹ️ This PR is 815 commits behind upstream |
|
PR looks good to me, thanks for the fix. |
|
@ZJY0516 can you update with main again? |
|
/ci run |
|
✅ Triggered Buildkite CI #97549 for commit |
The FlashInfer MLA DCP fix merged while this job was disabled, so the strict xfail now reports XPASS on all four dcp2 *-dspark cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: khluu <khluu000@gmail.com>
Purpose
Fix #59065
With DCP > 1 and speculative decoding, FlashInfer MLA decode crashes when the decode batch is ragged, i.e. requests carry different numbers of query tokens. That happens whenever a request has fewer drafts than the others, and also during warmup. For example, Kimi-K3 with
-tp 2 -dcp 2and DSpark fails at engine startup:Here a 1+7 request and a 1-token request make 9 decode tokens.
DCP cannot take the compact ragged path (
cum_seq_lens_q), because it needs LSE. So ragged batches fall to the "uneven length" branch. That branch has two problems:qinto one row per token, but it keepsblock_table,seq_lensandcausal_seqlens_kv_globalper request. FlashInfer then rejects the call.num_decode_tokens % num_decodes != 0. A ragged batch whose token count happens to divide evenly (e.g. 8 + 2 tokens) is insteadviewed as a uniform 5 + 5 batch, and each request's rows attend to the wrong KV.Fix
A batch is now treated as ragged when
num_decode_tokens != num_decodes * max_query_len. Ragged causal batches are split into single-token rows:block_tableandseq_lensare expanded per row with the existing_flattened_decode_metadata.T - (tokens of its request after it). FlashInfer definescausal_seqlens_kv_globalas the global exclusive causal bound of each row's newest query token, anddcp_tot_seq_lens(T) already includes all of the request's query tokens.The non-DCP causal path is unchanged; it already goes through
cum_seq_lens_q.Not a duplicate
No open PR touches this branch. #56784 edits the same file, but only for backend selection.
Test Plan
trtllm_batch_decode_with_kv_cache_mlawith the cute-dsl backend,cp_world=2, both ranks, and(T, q_len)in{(301, 8), (97, 8), (130, 4), (64, 1)}:q_lenrows and boundTgives bit-identical output and LSE (max error0.0) toq_lensingle-token rows bounded atT - (q_len - 1 - j).Tgives a max output error of0.26.tests/v1/attention/test_flashinfer_mla_dcp.py:test_flashinfer_mla_forward_uses_native_dcp_apiis extended with a ragged(3, 1)batch. The newragged-causalcase fails without this change and passes with it.Test Result
tests/v1/attention/test_flashinfer_mla_dcp.py+tests/kernels/attention/test_flashinfer_mla_decode.py: 23 passed, 1 skipped (GB200).ragged-causalfails.dcp2-*-dsparkcases in [CI][Kimi-K3] Test prefix cache reuse with KV offload, P/D and DCP #59229 are strict xfails for this bug and will flip once this lands.No output changes for batches that worked before, so no model eval was run.
AI assistance (Claude Code) was used for this change.
🤖 Generated with Claude Code