Skip to content

[MRv2] FlashAttention PCP support for GQA on MRv2 - #49564

Open
JaredforReal wants to merge 21 commits into
vllm-project:mainfrom
JaredforReal:pcp-gqa
Open

JaredforReal wants to merge 21 commits into
vllm-project:mainfrom
JaredforReal:pcp-gqa

Conversation

@JaredforReal

@JaredforReal JaredforReal commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Hy3-290B-FP8 PCP/DCP Benchmark in 8*H100

Model: tencent/Hy3-FP8 (HYV3ForCausalLM, GQA 64Q/8KV, 192-expert MoE + 1 shared,
80 layers, hidden 4096, 279 GB weights). Hardware: 8×H100 80GB.

All configs use --enforce-eager, --enable-expert-parallel,
--no-enable-flashinfer-autotune (skips the FlashInfer warmup that OOMs under
TP1 where all 64 attention heads land on one GPU), --gpu-memory-utilization 0.82
(headroom for warmup activations; 0.88 OOMs on TP2+PCP4), --max-model-len 32800
(TP1+PCP8 has only 12.4 GiB KV cache; 40960 needs 12.5 GiB), --safetensors-load-strategy prefetch (boot 9 min → 2.5 min), PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True.

Config matrix — all 7 use exactly 8 GPUs

TP × PCP = 8 throughout; DCP == PCP so DCP ranks share PCP ranks (no extra
world size). EP spans TP × PCP = 8 in every config.

# Config TP PCP DCP KV cache
1 tp8 8 1 1 replicated (baseline)
2 tp4_pcp2 4 2 1 replicated
3 tp2_pcp4 2 4 1 replicated
4 tp1_pcp8 1 8 1 replicated (pure PCP)
5 tp4_pcp2_dcp2_sharded 4 2 2 sharded (1/dcp)
6 tp2_pcp4_dcp4_sharded 2 4 4 sharded (1/dcp)
7 tp1_pcp8_dcp8_sharded 1 8 8 sharded (1/dcp)

TPOT — decode latency (mean / P99 ms)

ShareGPT subset, prefix caching on (decode is prefix-insensitive; matches
how the Qwen-30B baselines were taken). Concurrency 1 / 16 / 32.

Config c=1 c=16 c=32 c1→32
TP8 (baseline) 158 / 161 158 / 165 162 / 165 +2.5%
TP4+PCP2 177 / 181 180 / 183 180 / 183 +1.7%
TP2+PCP4 174 / 180 177 / 180 178 / 182 +2.3%
TP1+PCP8 167 / 171 170 / 175 174 / 179 +4.2%
TP4+PCP2+DCP2 205 / 215 213 / 225 213 / 219 +3.9%
TP2+PCP4+DCP4 205 / 208 215 / 220 215 / 220 +4.9%
TP1+PCP8+DCP8 195 / 198 202 / 208 206 / 215 +5.6%

TTFT — prefill latency (median ms)

Random-input probe, prefix caching off + 6 warmup requests discarded,
20 measured.

Config 4K 16K 32K
TP8 (baseline) 256 926 1973
TP4+PCP2 243 875 1858
TP2+PCP4 238 832 1741
TP1+PCP8 226 783 1682
TP4+PCP2+DCP2 244 911 1979
TP2+PCP4+DCP4 233 891 1980
TP1+PCP8+DCP8 228 927 2123

Accuracy & KV capacity

GSM8K 200 questions, 5-shot, greedy, conc 256.

Config GSM8K KV tokens DCP capacity win
TP8 0.885 735,056
TP4+PCP2 0.905 338,288
TP2+PCP4 0.915 139,840
TP1+PCP8 0.940 40,736
TP4+PCP2+DCP2 0.915 676,576 2.0× vs TP4+PCP2
TP2+PCP4+DCP4 0.895 558,814 4.0× vs TP2+PCP4
TP1+PCP8+DCP8 0.910 324,936 8.0× vs TP1+PCP8

GSM8K spread (0.885–0.940) is 200-question sample noise (each question = 0.5%,
so ±2–3 questions = ±1–1.5%), not a regression.


Qwen3-30B-A3B-FP8 PCP/DCP Benchmark in 4xH100

Model: Qwen3-30B-A3B-FP8 (GQA, MoE, 48 layers). Hardware: 4×H100 80GB.

All configs use --enforce-eager, --enable-expert-parallel,
--gpu-memory-utilization 0.88, --max-model-len 40960.

Config matrix — all 5 use 4 GPUs

When dcp == pcp the DCP ranks share the PCP ranks, so the CP world size is
just pcp. Config 4 (PCP2+DCP2) therefore runs on 2 GPUs, not 4.

# Config TP PCP DCP KV cache GPUs
1 tp4 4 1 1 replicated (baseline) 4
2 tp2_pcp2 2 2 1 replicated 4
3 tp1_pcp4 1 4 1 replicated (pure PCP) 4
4 tp1_pcp2_dcp2_sharded 1 2 2 sharded (1/dcp) 2
5 tp1_pcp4_dcp4_sharded 1 4 4 sharded (1/dcp) 4

TPOT — decode latency (mean / P99 ms)

ShareGPT subset: concurrency 1 / 16 / 32.

Config c=1 c=16 c=32 c1→32
TP4 (baseline) 60.2 / 64.5 60.9 / 64.1 65.7 / 76.5 +9.1%
TP2+PCP2 73.6 / 78.9 74.7 / 79.1 79.5 / 84.9 +8.0%
TP1+PCP4 68.6 / 70.2 70.2 / 76.1 75.9 / 80.6 +10.6%
TP1+PCP2+DCP2 83.9 / 87.7 89.6 / 95.7 94.6 / 100.8 +12.8%
TP1+PCP4+DCP4 85.6 / 91.7 90.3 / 95.1 96.4 / 105.3 +12.6%

The PCP gain is from decode steps no longer doing a per-layer forward_context
lookup + store, nor building the pcp-wide gathered slot mapping. DCP configs
gain less because their per-step LSE-combine collective dominates what was
removed.

TTFT — prefill latency (median ms)

Random-input probe, prefix caching off + 6 warmup requests discarded,
20 measured.

Config 4K 16K 32K
TP4 (baseline) 96 289 645
TP2+PCP2 116 301 648
TP1+PCP4 110 287 622
TP1+PCP2+DCP2 109 423 1038
TP1+PCP4+DCP4 114 333 771

The three no-DCP configs converge at 32K (622–648 ms — same parallelised
prefill). DCP4 is +126 ms (+20%) over that floor; DCP2 is much worse but runs
on 2 GPUs.

Accuracy & KV capacity

GSM8K 1319 questions, 5-shot, greedy, conc 256.

Config GSM8K KV tokens Max concurrency DCP capacity win
TP4 0.901 2,657,504
TP2+PCP2 0.905 1,302,384
TP1+PCP4 0.886 626,016
TP1+PCP2+DCP2 0.896 1,132,096 1.81× vs TP1+PCP4
TP1+PCP4+DCP4 0.891 2,504,064 61.13× 4.00× vs TP1+PCP4

Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Enables MRv2 Prefill Context Parallelism (PCP) for non-MLA (GQA/MHA) models on the FlashAttention backend, including a sharded PCP+DCP path that supports extend/prefix-caching and mixed prefill+decode batches without desynchronizing collectives.

Changes:

  • Lift MRv2 PCP restriction to MLA-only by moving capability gating to attention-backend opt-in (supports_pcp) + existing compatibility checks.
  • Add PCPManager→ForwardContext plumbing to provide rank-invariant global batch flags and prefill gather/context metadata needed by FlashAttention’s MRv2 PCP+DCP path.
  • Implement FlashAttention MRv2 PCP+DCP execution: prefill Q/K/V all-gather + optional sharded cached-prefix attention + mixed-batch decode overwrite; plus KV-cache update gathering for PCP.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
vllm/v1/worker/gpu/pcp_manager.py Adds global batch flags and forward-context metadata (prefill gather indices + global context metadata) for sharded PCP+DCP attention.
vllm/v1/worker/gpu/model_runner.py Populates PCP forward-context metadata at the start of each forward pass.
vllm/v1/core/sched/scheduler.py Propagates actual pcp_world_size into scheduler/kv-connector setup (was hardcoded to 1).
vllm/v1/attention/backends/flash_attn.py Implements PCP support for GQA/MHA and an MRv2 PCP+DCP sharded-cache path, including mixed-batch handling and PCP-aware KV-cache updates.
vllm/model_executor/layers/attention/pcp.py Adds helpers for PCP prefill QKV gather/slice and for extracting decode subsets from mixed batches.
vllm/config/vllm.py Removes MRv2 PCP “unsupported feature” block for non-MLA; relies on backend opt-in + compatibility checks.
vllm/config/model.py Adjusts DCP validation logic when DCP spans the PCP axis (dcp == pcp) so TP-head sharding constraints aren’t misapplied.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1469 to +1472
q_g, k_g, v_g = gather_prefill_qkv_global(info, query, key, value)
cu_seqlens = global_cu_seqlens.to(device=query.device, dtype=torch.int32)
global_max_seqlen = int(global_cu_seqlens.max().item())
out_g = torch.empty_like(q_g)
Comment on lines +701 to +708
gb = self._global_batch
if (
gb is None
or self._global_ctx_block_tables is None
or self._global_ctx_kv_lens is None
or self._block_tables is None
):
return None
JaredforReal and others added 5 commits July 29, 2026 15:31
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Co-authored-by: Lucas Wilkinson <lwilkins@redhat.com>
…cp-gqa

Co-authored-by: Lucas Wilkinson <lwilkins@redhat.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Co-authored-by: Lucas Wilkinson <lwilkins@redhat.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
@JaredforReal
JaredforReal requested a review from zyongye as a code owner July 30, 2026 06:38
Signed-off-by: JaredforReal <w13431838023@gmail.com>
JaredforReal and others added 5 commits July 31, 2026 03:42
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Co-authored-by: Lucas Wilkinson <lwilkins@redhat.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
@mergify

mergify Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @JaredforReal.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@MatthewBonanni MatthewBonanni left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! A few comments

layer._v_scale,
)

def _forward_with_dcp(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to update FlashAttentionDiffKV too please

Comment on lines -1213 to -1215
if split_dcp_context:
# TODO: Remove this DCP + FA2 mixed decode/prefill workaround once
# FA4 supports this Qwen3.5 shape.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure we can remove this?

self._forward_with_dcp(
query[:num_actual_tokens],
self._forward_dcp(
query,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why get rid of this slice? Are we computing over padding rows now?

fa_kwargs["scheduler_metadata"] = attn_metadata.scheduler_metadata

descale_shape = (cu_q.shape[0] - 1, self.num_kv_heads)
ctx_out, ctx_lse = flash_attn_varlen_func(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the workspace and pass out so we aren't allocating each step

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants