[DeepSeek V4] Correct FlashMLA sparse prefill under DSA context parallel - #27276
Closed
andrewdoro wants to merge 1 commit into
Closed
andrewdoro wants to merge 1 commit into
andrewdoro wants to merge 1 commit into
Conversation
…allel The merged sgl-project#25418 sparse-prefill gate is CP-blind: under --dsa-prefill-cp-mode round-robin-split each rank holds a strided 1/cp_size subset of the chunk's tokens, but _forward_prefill_sparse rebuilt query_start_loc from the full (global) extend_seq_lens and the combine kernel derived each query's SWA position from a contiguous start_pos+token_idx, both false under round-robin -> silent wrong output. Minimal fix (no kernel changes; relies on the v1 topk raw indices sgl-project#25418 already produces): - can_use_sparse_prefill gate: under CP round-robin only run sparse when batch_size==1 and the local row count matches positions_casual, else fall back to the already-CP-correct dense flash_mla path. - thread local_extend_seq_lens (local query rows) + positions (reindexed causal positions) into SparsePrefillChunkCache so query_start_loc and the SWA-window math use per-rank-local geometry while KV gather stays global.
andrewdoro
requested review from
Fridge003,
HaiShaw,
Qiaolin-Yu,
hebiao064,
ispobock and
merrymercy
as code owners
June 4, 2026 13:10
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
Draft
5 tasks
This was referenced Jun 30, 2026
5 tasks
21 tasks
Contributor
|
Thanks @andrewdoro. Closing this because it has had no updates in 99 days. Reopen it if the work is still relevant. Some directories moved recently, so an older branch may need retargeting: |
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.
Summary
Makes the FlashMLA sparse prefill path (
#25418) correct under DSA prefill context parallelism (--dsa-prefill-cp-mode round-robin-split). Today the sparse path is selected by a CP-blind gate and then runs with global, contiguous query geometry, which is wrong once round-robin CP strides each rank's tokens — producing incorrect long-context output (and, on padded chunks, an out-of-bounds index). This is a focused, minimal replacement for the (closed) draft #26215: 3 files, +172/-23, no kernel changes.Background / problem
#25418added_forward_prefill_sparse, gated only by:There is no
cp_size/cp_rankterm. Underround-robin-split, rankrphysically holds the strided subset{r, r+cp_size, ...}of the chunk's tokens (the dense path is corrected for this byapply_cp_reindex), but the sparse path is not:SparsePrefillChunkCache.buildderivesquery_start_locfrom the full (global)extend_seq_lens, whileq_flatonly carries this rank's strided rows.start_pos + token_idx_in_query, which is false under striding.So a CP round-robin prefill chunk that hits the sparse gate computes attention against the wrong positions.
Two concrete failure modes from ceil-align padding
When the global token count isn't a multiple of
cp_size, the batch is ceil-aligned with trailing padding rows (positions = 0, all--1page masks) that survive the round-robin split into each rank'sq_flat:ensure_c128selectslast_q_per_req = query_start_loc[-1] - 1to source the per-request c128 page-index mask. On ranks holding a trailing padding row, that row's mask is all-1;clamp_min(0)collapses it to slot 0, so the request's entire c128 compressed workspace is dequantized from a polluted slot. (The method's own docstring already warns about this all--1hazard for the first-query case; padding reintroduces it via the last row.)pos = 0, so the combine kernel emits exactly one SWA indexswa_base - gather_start; for any continuation/chunked prefill (gather_startlarge) this is a large negative value other than-1, which violatesflash_mla_sparse_fwd's contract (indices must be -1 or >= s_kv) and reads out of bounds on the exactly-sized KV workspace.The fix
Two mechanisms, both confined to the sparse path and gated behind the existing trigger so non-CP behavior is unchanged:
Striding correctness — thread
local_extend_seq_lens(the per-rank local row count) andpositions(the CP-reindexedpositions_casual) intoSparsePrefillChunkCache.build, soquery_start_locand the SWA-window position math use per-rank-local query geometry while the KV gather stays global.Padding safety — a new
can_use_sparse_prefillgate runs sparse under CP only for a single, unpadded request:Multi-request and ceil-align-padded chunks fall back to the already-CP-correct dense
flash_mla_with_kvcache. Becausechunked_prefill_sizeis normally a multiple ofcp_size, full chunks still run sparse; only a ragged final chunk falls back, so the perf impact is negligible.This relies on the request-local
c4_sparse_raw_indicesthat#25418already produces via the v1 topk path, so no indexer/kernel changes are needed.Validation
GPU token-exact comparison on 4×B200, tp=4,
nightly-dev-cu13-20260604-14ed9b44+ this patch, greedy (temperature=0):--enable-dsa-prefill-context-parallel, sparse env off)10/10 prompts produced byte-identical output between the two arms, including two unpadded ~10.6k-token prompts (
%cp_size == 0) that exercise the real sparse path over ~83 c128 blocks, padded prompts that take the dense fallback (no crash), and short coherence prompts. No CUDA errors during inference.Relation to #26215
#26215 bundled this CP support together with the (now-merged)
#25418integration, a separate mixed-chunk feature, and a stale-base divergence, and is closed. This PR is the isolated CP-correctness delta on top of merged#25418.Test plan
python -m py_compileon all touched filesCI States
Latest PR Test (Base): ❌ Run #26953815469
Latest PR Test (Extra): ❌ Run #26953814552