[CP] Migrate MLA prefill CP (DeepSeek V3) to CP-v2 zigzag strategy - #31619
Merged
Merged
Conversation
Contributor
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
Route MLA prefill context parallelism (DeepSeek V3/R1) through the layers/cp ZigzagCPStrategy abstraction, mirroring the GQA path from #28421. DeepSeek V3 is added to CP_V2_DEFAULT_MODEL_CLASSES so CP-v2 is the default for it (as with Qwen3Moe); the legacy cp_utils v1 path stays intact and reachable via SGLANG_ENABLE_CP_V2=0. Under v2 the eager runner owns the entry shard (cp_split_before_forward) and exit gather (cp_gather_after_forward) and drives DeepseekV2Model.forward directly, so: - deepseek_v2.py / deepseek_nextn.py: gate the in-model CP entry split and exit gather to the v1-only path (`and not is_cp_v2_active`). - flashattention_backend.py: MLA CP attention dispatches through cp_strategy.run_attention under v2, else the v1 cp_attn_forward_extend. The MLA latent all-gather (rebuild_cp_kv_cache) stays upstream in forward_absorb_prepare for both paths; zigzag metadata is field-compatible with the v1 ContextParallelMetadata, so no KV-write change is needed. Pure-MLA arch only: DSA archs (DeepseekV32/DeepseekV4) are excluded (CP-v2 does not yet cover DSA), and Kimi K2.5 needs separate wiring for its .language_model wrapper. The existing test_deepseek_v3_cp_single_node.py (tp8 dp2 attn-cp4) now exercises CP-v2 via the default-class enablement. Part of the CP refactor roadmap (#27252) / context parallelism roadmap (#21788). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
kpham-sgl
force-pushed
the
cp-v2-mla-prefill
branch
from
July 18, 2026 00:05
83c9bfa to
9c1d125
Compare
Decision A — move the MLA latent all-gather into the CP strategy for v2: - forward_mla.py: skip the upstream rebuild_cp_kv_cache under CP-v2 (k_nope/k_pe stay rank-local through forward_absorb_core). - flashattention_backend.py: the MLA KV write dispatches to cp_strategy.materialize_full_mla_kv under v2 (gather rank-local latent to full, then set_mla_kv_buffer); v1 keeps the upstream-rebuilt full write. - zigzag.py: add materialize_full_mla_kv (fuse compressed-KV + rope, one all-gather via gather_kv_cache, split back for the paged write). Kimi K2.5 wiring: - eager_runner.py: drive resolve_cp_forward_model(model) instead of the raw model, so multimodal wrappers expose their inner CausalLM for the CP-v2 path. - kimi_k25.py: KimiK25ForConditionalGeneration.get_cp_model() returns language_model. - cp/utils.py: add resolve_cp_forward_model + KimiK25ForConditionalGeneration to CP_V2_DEFAULT_MODEL_CLASSES. The seq_lens_k padding flagged on #28421 is already handled (zigzag build_metadata bakes pad_len; the FA backend widens page_table by pad_delta); Decision A's gather preserves the same padded length. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
kpham-sgl
commented
Jul 18, 2026
deepseek_v2.py: compute use_cp_v1 once and reuse it for the entry split and exit gather instead of repeating the (dsa/mla prefill CP) and not is_cp_v2_active condition. deepseek_nextn.py: rename use_cp -> use_cp_v1 to match. Pure refactor, no behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the bespoke get_cp_model() hook with the standard multimodal get_language_model() accessor (already implemented by Kimi's siblings: pixtral/voxtral/deepseek_ocr/...). resolve_cp_forward_model now unwraps via get_language_model when present, else returns the model itself. Behavior is identical for flat CausalLMs (DeepseekV3/Qwen3 have no get_language_model -> resolve to self); Kimi gains the standard accessor it was missing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove the resolve_cp_forward_model helper and inline the standard get_language_model unwrap at its single call site in the eager runner, matching the getattr-for-optional-capability style already used there. Flat CausalLMs resolve to themselves (no get_language_model); multimodal wrappers (Kimi) unwrap to their inner CausalLM. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the scattered CP-v2 prep/shard/gather/logits out of _execute_extend into a single self-contained _execute_extend_cp_v2 method, so the main dispatch is just `elif cp_v2_active: ret = self._execute_extend_cp_v2(...)` with no leaked forward_positions / cp_model. Drop the multimodal language-model resolution (and Kimi from CP_V2_DEFAULT_MODEL_CLASSES) — deferred to a follow-up PR; this PR targets DeepSeek V3 only. Validated: test_deepseek_v3_cp_single_node.py GSM8k 0.964. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
I will defer Kimi changes to another PR. Need to come up with a clean way for MM models |
kpham-sgl
marked this pull request as ready for review
July 18, 2026 03:56
kpham-sgl
requested review from
BBuf,
Edwardf0t1,
Fridge003,
HaiShaw,
Qiaolin-Yu,
Ying1123,
ch-wan,
fzyzcjy,
hebiao064,
hnyls2002,
ispobock and
merrymercy
as code owners
July 18, 2026 03:56
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fridge003
approved these changes
Jul 18, 2026
Collaborator
|
MLA/DSA tests passed here |
19 tasks
Zhylkaaa
pushed a commit
to Zhylkaaa/sglang
that referenced
this pull request
Jul 29, 2026
…gl-project#31619) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Chronostasys
pushed a commit
to MindLab-Research/sglang
that referenced
this pull request
Aug 24, 2026
…gl-project#31619) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.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.
Motivation
Part of the Prefill CP refactor roadmap (#27252) and the Context Parallelism roadmap (#21788). #28421 landed the CP-v2
ZigzagCPStrategyfor GQA/MHA (Qwen3) and the model-agnostic eager-runner boundary. This PR ports MLA prefill CP for DeepSeek V3/R1 (originally #23292) onto that abstraction and makes the strategy own the MLA latent all-gather.DeepseekV3ForCausalLMis added toCP_V2_DEFAULT_MODEL_CLASSES, so CP-v2 is its default (likeQwen3MoeForCausalLM). The legacy cp_utils v1 path stays intact and reachable viaSGLANG_ENABLE_CP_V2=0.Modifications
Boundary migration (v1↔v2 coexist):
layers/cp/utils.py— addDeepseekV3ForCausalLMtoCP_V2_DEFAULT_MODEL_CLASSES.models/deepseek_v2.py/models/deepseek_nextn.py— gate the in-model CP entry split + exit gather to v1-only (use_cp_v1); the eager runner owns them under v2.layers/attention/flashattention_backend.py— MLA CP attention dispatches throughcp_strategy.run_attentionunder v2, else the v1cp_attn_forward_extend.model_executor/runner/eager_runner.py— CP-v2 extend is a single self-contained_execute_extend_cp_v2(shard at the boundary, run the body on the rank-local slice, gather before logits).Decision A — strategy owns the MLA latent all-gather (v2):
models/.../forward_mla.py— skip the upstreamrebuild_cp_kv_cacheunder v2 (k_nope/k_pe stay rank-local).flashattention_backend.py— the MLA KV write dispatches tocp_strategy.materialize_full_mla_kvunder v2 (gather rank-local latent → full, thenset_mla_kv_buffer); v1 keeps the upstream-rebuilt full write.layers/cp/zigzag.py— addmaterialize_full_mla_kv(fuse compressed-KV + rope, one all-gather viagather_kv_cache, split back for the paged write).Already handled (no change needed): the
seq_lens_kpadding flagged on #28421 — zigzagbuild_metadatabakespad_len(#28421) and the FA backend widenspage_tablebypad_delta(#23292). Decision A's gather preserves the same padded length.Accuracy Tests
Existing
test/registered/cp/test_deepseek_v3_cp_single_node.py(tp=8, dp=2, attn-cp=4, DeepSeek-V3-0324, GSM8k ≥ 0.935) now runs CP-v2 via the default-class enablement. Verified on 8×H200:SGLANG_ENABLE_CP_V2=0)Non-regression: v1 MLA CP unchanged (0.966); NSA/DSA and MHA CP paths are no-ops under default
SGLANG_ENABLE_CP_V2=0.Out of scope (follow-ups)
language_model) is deferred to a follow-up PR.use_cp_v1gates make v2 a no-op there).Checklist
CI States
Latest PR Test (Base): ❌ Run #29629808219
Latest PR Test (Extra): ❌ Run #29629808052