[MRv2] Share PCP/DCP query-gather and LSE-combine between MLA and GQA - #1
LucasWilkinson wants to merge 3 commits into
Conversation
The PCP/DCP topology rule was spelled out at five call sites across three files (dcp_shares_pcp_ranks in config/model.py, the FA metadata builder, and FlashAttentionImpl), with MLA carrying its own copy inline. Factor the rule into vllm/model_executor/layers/attention/pcp.py: maybe_all_gather_q_for_dcp() gather Q heads for DCP context attention maybe_all_gather_split_q_for_dcp() same, for MLA's split (nope, pe) query dcp_q_gather_size() resulting head-shard count, for AOT sizing cp_context_combine_fn() matching LSE-combine (a2a / all-reduce / RS) cp_reconcile_heads() was finalize_mla_pcp_decode; not MLA-specific DCP groups span the PCP axis before TP, so DCP only splits query heads when it reaches past PCP; there Q is head-sharded across TP and must be gathered over the TP group. MLA already did this; the GQA path gathered over the DCP group, which would duplicate the PCP-replicated heads when dcp == tp*pcp. Behaviour is unchanged for every reachable topology. dcp_shares_pcp_ranks is gone; config/model.py guards its TP-head asserts on dcp > pcp, which is the same predicate spelled arithmetically. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Lucas Wilkinson <wilkinson.lucas@gmail.com> Signed-off-by: Lucas Wilkinson <lwilkins@redhat.com>
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Once the PR is approved and ready to go, your PR reviewer(s) can run CI to test the changes comprehensively before merging. To run CI, PR reviewers can either: Add If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
Folds the dcp_comm_backend == "a2a" check into the resolver so neither backend has to compute it. MLA drops self.dcp_a2a (its only consumer was the combine selection) and now resolves the combine once at construction like the FA impl. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Lucas Wilkinson <wilkinson.lucas@gmail.com> Signed-off-by: Lucas Wilkinson <lwilkins@redhat.com>
A value-restricted TypeVar resolves the return type per call site, so the tuple-accepting form no longer needs a separate function: GQA passes a tensor and gets a tensor back, MLA passes its split (nope, pe) query and keeps it split when no gather happens. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Lucas Wilkinson <wilkinson.lucas@gmail.com> Signed-off-by: Lucas Wilkinson <lwilkins@redhat.com>
229779a to
e52c173
Compare
|
Closing — this is absorbed by 019fcdb ("apply mla & gqa sharing PCP/DCP query-gather and LSE-combine"). Verified against the current head: Two things worth recording from the investigation. The Q gather can't just be deleted. I tried, and it fails two ways. Two bugs that reproduced on the pre-rework base — both may already be fixed by the row-plan change, I haven't re-tested against the new head yet:
Testing caveat on the MLA side. GQA was verified: pure-PCP byte-identical to Written with Claude Code; the diff was reviewed by me. |
Draft suggestion against vllm-project#49564, not a replacement for it. Targets
JaredforReal:pcp-gqaso it can be merged into that branch if you like it.What this does
The PCP/DCP topology rule — does the DCP group reach past the PCP axis onto TP? — was spelled out at five call sites across three files, plus a sixth copy inline in MLA:
config/model.pydcp_shares_pcp_rankslocalFlashAttentionMetadataBuilder.__init__self.dcp_shares_pcp_ranksFlashAttentionImpl.__init__self.dcp_shares_pcp_ranks_forward_with_dcpschedule()num_heads_qmultiply + anum_heads_q=parametermla_attention.py:875-919if use_pcp / if dcp > pcpThis factors it into
vllm/model_executor/layers/attention/pcp.py, next to the KV-cache gather the two backends already share:maybe_all_gather_q_for_dcp()— gather Q heads for the DCP context attentionmaybe_all_gather_split_q_for_dcp()— same, for MLA's split(nope, pe)query; concatenates the halves only when a gather actually happens, so the split form survives when it candcp_q_gather_size()— the resulting head-shard count, for FA's AOT scheduler metadata (needed before the gather happens)cp_context_combine_fn()— the matching LSE-combine (a2a / all-reduce / reduce-scatter)cp_reconcile_heads()— renamed fromfinalize_mla_pcp_decode; it was never MLA-specific, it's just "reconcile the head dim tonum_headsby gather-or-slice"dcp_shares_pcp_ranksis gone.config/model.pyguards its TP-head asserts ondcp > pcp, which is the same predicate spelled arithmetically — verified equivalent for all four(pcp, dcp)combinationsParallelConfigpermits.One latent bug fixed
The GQA path gathered Q over the DCP group:
When
dcp == tp*pcpthe DCP group spans both axes, so that duplicates the PCP-replicated heads — onlytpof thetp*pcpshards are distinct. MLA already gets this right by gathering over the TP group (mla_attention.py:877). Sharing the helper gives GQA the correct behaviour.Not reachable today:
dcp == tp*pcpfor non-MLA dies onassert dcp <= tp // num_kv_heads, which can never hold forpcp > 1. So this is a latent fix, not a live one — but it's the kind of thing the duplication was hiding.What this deliberately does not do
_forward_dcp_mrv2is untouched. I think there's a case that the global Q/K/V gather isn't needed —4cd1e73a2replaced a cache-based prefill path with it, and MLA runs a DCP-sharded cache under the same topology with no PCP-specific prefill code at all — but that's a question for you, not a refactor to land blind. Happy to discuss separately.Testing
pre-commit run --all-fileson the touched files: passes, includingmypy-3.10Suggested before merge: GSM8K on TP1+PCP4+DCP4 (0.890 in your table) to cover GQA, and any DeepSeek PCP config to cover the MLA changes.
pcp == 1paths should be bit-identical.AI assistance
Written with Claude Code. I reviewed the diff; it has not been run on hardware. Not duplicating another PR — it's a suggestion against an existing one.