Skip to content

[DSpark] Support pipeline-parallel targets in aggregated serving - #56956

Open
lucifer1004 wants to merge 1 commit into
vllm-project:mainfrom
lucifer1004:pr/dspark-pp-ifb
Open

lucifer1004 wants to merge 1 commit into
vllm-project:mainfrom
lucifer1004:pr/dspark-pp-ifb

Conversation

@lucifer1004

@lucifer1004 lucifer1004 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

What

DSpark on a pipeline-parallel target in aggregated (non-PD) serving. The drafter runs wholly on the last PP stage; this PR makes that work correctly:

  • Draft broadcast across stages: the last stage's speculator proposes drafts, but earlier stages need them for the next verification step. The last rank now broadcasts the fresh drafts on the PP group (PPHandler.broadcast_drafts), and the broadcast is gated out of the no-op second call site when a speculator ran (double-posting misaligned the recv FIFO and hung the pipeline).
  • Warmup: the deferred PP post-update triton kernel never runs during warmup steps on non-last ranks; its first mid-serving compile would deadlock against the in-flight NCCL broadcast. warmup_pp_decode_update compiles it during capture, and the sampled-token broadcast is disabled for the warmup window.
  • Draft embedding under PP: the target's embedding table only exists on the first stage, so DSv4/K3 DSpark drafters load their own copy from the checkpoint (loads_own_embed_under_pp) instead of aliasing.
  • Padded graph batch safety: the DFlash prepare-inputs kernel clears input_ids/positions and sets is_padding on CUDA-graph padding rows, and the DSv4 top-k router zeroes padded-row selections instead of reading uninitialized state.

Not a duplicate

Split from #53577 (reviewer request): this PR is the aggregated-serving half; the PD prefill + KV-transfer half follows separately.

Tests

  • New/extended: tests/v1/worker/test_pp_utils.py, test_spec_decode_embed_sharing_pp.py, tests/v1/spec_decode/test_dflash_prepare_inputs.py, tests/models/kimi_k3/test_eagle3.py, test_dspark_mla.py, tests/kernels/moe/test_topk_softplus_sqrt.py.
  • pytest tests/v1/worker/test_pp_utils.py tests/v1/worker/test_spec_decode_embed_sharing_pp.py tests/models/kimi_k3/test_eagle3.py tests/models/kimi_k3/test_dspark_mla.py tests/v1/spec_decode/test_dflash_prepare_inputs.py tests/v1/worker/test_gpu_warmup_blocks.py tests/v1/worker/test_gpu_model_runner_v2.py tests/kernels/moe/test_topk_softplus_sqrt.py -q → 1744 passed.

Model evaluation

DeepSeek-V4-Flash (0731) DSpark K=5, IFB PP2×TP2, GSM8K strict-match: 0.9545 (matches the target-only arm within noise).

Kimi-K3 DSpark IFB PP additionally needs #51065 (without it, the draft's non-causal flag raises the shared KV group's TritonMLA reorder threshold and misroutes the causal target's verification blocks).

AI assistance was used in preparing this PR.

Draft tokens under PP: the last stage runs the speculator and now
broadcasts the fresh drafts to earlier stages (whose next verification
step would otherwise embed stale buffer contents), with the double-post
on the pp_broadcast group gated out for the speculator-less diffusion
path. Non-last stages JIT-compile the deferred post-update kernel during
warmup so its first compile cannot deadlock the pipeline mid-serving.

Draft embedding under PP: the target's embedding table lives on the
first stage, so DeepSeek-V4/Kimi-K3 DSpark drafters load their own copy
from the checkpoint (loads_own_embed_under_pp) instead of aliasing.

Padded graph batch safety: the DFlash prepare-inputs kernel now clears
input_ids/positions and sets is_padding on CUDA-graph padding rows, and
the DSv4 top-k router zeroes padded-row selections instead of reading
uninitialized state.

Co-authored-by: Kimi Code <noreply@moonshot.cn>
Signed-off-by: Zihua Wu <13583761+lucifer1004@users.noreply.github.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.

Comment on lines +163 to +168
if _target_pp_world_size() > 1:
self.embed_tokens = VocabParallelEmbedding(
self.config.vocab_size,
self.config.hidden_size,
prefix=maybe_prefix(prefix, "embed_tokens"),
)

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.

#50514 added token embedding at pp last stage, I think we don't need this anymore (same for the dsv4 path)

# window and restore it before serving.
pp_handler = getattr(self.model_runner, "pp_handler", None)
if pp_handler is not None:
pp_handler.set_disabled(True)

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.

Could you help me understand how the deadlock happen? If it's about collective running on multiple streams, I'd prefer enforce collective ordering instead of skip warm up here.

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

Labels

deepseek Related to DeepSeek models dflash DSv4 k3 kimi mrv2 Model Runner V2 specific speculative-decoding

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants