Skip to content

[Perf][DSpark][DSv4.1] Fuse the Markov sampling loop on NVIDIA by inverse CDF - #64442

Merged
khluu merged 5 commits into
vllm-project:mainfrom
Juntian777:juntianl/dsv41-dspark-dep-fused-markov
Nov 3, 2026
Merged

khluu merged 5 commits into
vllm-project:mainfrom
Juntian777:juntianl/dsv41-dspark-dep-fused-markov

Conversation

@Juntian777

@Juntian777 Juntian777 commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Overview

Runs DSpark's sequential Markov sampling for DeepSeek-V4.1 on NVIDIA as the existing bias GEMM plus two Triton kernels per draft step, through the draft model's sample_sequential hook (as the ROCm model does). Sampled draft tokens are drawn by inverse CDF of the cached draft logits instead of Gumbel-max. Production code changes only under vllm/models/deepseek_v41/nvidia/ (+223). It is opt-in: --additional-config '{"dspark_fused_markov": true}' enables it, and the speculator's loop stays the default.

Claims

  • DSpark Markov sampling (5 draft steps, GB200, CUDA graph): 1.6x at 1 request per rank, 2.7x to 3.9x at 16 to 253 requests per rank.
  • DEP4 decode serving with AgentX KV: step time -1.7% at 64 requests x 131K context per rank, -3.2% at 128 x 32K.
  • GSM8K and DSpark acceptance length unchanged at DEP4 and TEP4 (TP4 + EP).

Validation

Kernel time, DSparkSpeculator._sample_sequential (main's loop) vs this PR, CUPTI under a CUDA graph, one GB200, V = 129280, rank 256, 5 draft steps, 3 runs each (spread under 1% except 1 request):

Requests per rank main loop (us), T=1 This PR (us), T=1 Speedup main loop (us), T=0/0.6/1 mixed This PR (us), mixed Speedup
1 111.9 71.6 1.56x 107.7 64.5 1.67x
16 237.6 89.3 2.66x 233.6 88.7 2.63x
32 269.9 96.2 2.80x 256.7 95.9 2.68x
64 411.4 144.3 2.85x 385.2 144.7 2.66x
128 658.3 194.9 3.38x 601.2 196.5 3.06x
253 1158.5 298.9 3.88x 1039.9 298.4 3.48x

Re-checked on main 51c6dfd8c8 with this revision, same benchmark, one GPU, median of 3 alternating rounds (worst spread 9.0% at 1 request, 3.8% or less from 16 to 253 requests at T=1, 7.1% or less for mixed):

Requests per rank main loop (us), T=1 This PR (us), T=1 Speedup main loop (us), mixed This PR (us), mixed Speedup
1 112.9 71.0 1.59x 107.1 65.7 1.63x
16 238.0 89.3 2.66x 231.3 87.7 2.64x
64 411.6 144.4 2.85x 384.5 144.2 2.67x
128 658.7 196.2 3.36x 600.7 197.3 3.05x
253 1158.7 301.3 3.85x 1042.5 299.9 3.48x

DEP4 decode serving, DeepSeek-V4.1-Flash on one GB200 node, DSpark K=5 probabilistic drafting, synthetic acceptance length 3.51, FULL_DECODE_ONLY graphs, MegaAttn + MegaMoE, --max-num-seqs 128. The client fills the KV with AgentX token streams, then runs 6 rounds of 4096 forced output tokens with exactly the given requests on every rank (no logits processing, as AgentX); step time is the median of the last 3 rounds, measured only over windows of pure decode:

Requests x context per rank main (ms/step) This PR (ms/step) Change
64 x 131K 25.26 24.84 -1.7%
128 x 32K 34.17 33.08 -3.2%

Accuracy (vllm serve, DSpark K=5, probabilistic drafting, standard rejection sampling; GSM8K is lm_eval 5-shot, greedy, max 1024 tokens, concurrency 32; acceptance length from the server's spec-decode metrics over the GSM8K run):

GSM8K strict-match Acceptance length
DEP4, reference (#62359's run, same flags) 0.9265 3.451
DEP4, this PR 0.9280 3.448
TEP4 (TP4 + EP), this PR 0.9257 3.463

These evals and the DEP4 decode serving numbers ran on an earlier base (66875d3127, 259 commits behind 51c6dfd8c8) and were not rerun. Since then this PR's kernels have not changed and the only production additions are the opt-in dspark_fused_markov check and one inlined local. All "This PR" numbers are the fused path, which now needs that flag. The speculator changed on main; I checked its sample_sequential contract by reading the code, and on the merged tree ran the test below and the kernel benchmark above.

The DEP4 eval ran with --jit-monitor-verbose: the new kernels compile only during warmup. The TEP4 eval ran with VLLM_GPU_SYNC_CHECK=error.

.venv/bin/python -m pytest tests/models/deepseek_v41/nvidia/test_fused_markov.py -v  # 2 passed on main 51c6dfd8c8

The test runs the speculator's loop and the fused path on the same inputs: temperature-0 tokens and every cached logit of temperature-0 requests (and step 0 of all requests) match bit for bit, and sampled tokens follow softmax(cached logits / temperature).

Details


Pull Request Checklist
  • I used vLLM's /pr-checklist skill. (Mandatory for agents, optional for humans).

  • AI assistance was used during the creation of this PR.

  • Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.

  • Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.

  • Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.

  • Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.

…erse CDF

Run DSpark's sequential Markov sampling for DeepSeek-V4.1 on NVIDIA as the
bias GEMM plus two Triton kernels per draft step, through the draft model's
sample_sequential hook. Sampled draft tokens are drawn by inverse CDF of the
cached draft logits; temperature-0 tokens are the loop's argmax.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Juntian Liu <Juntianl777@gmail.com>
@mergify mergify Bot added ci/build deepseek Related to DeepSeek models DSv4.1 Related to DeepSeek-V4.1 models nvidia dflash labels Oct 29, 2026
@Aminous-001

Copy link
Copy Markdown

+++

@mergify

mergify Bot commented Oct 31, 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, @Juntian777.

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

additional_config={"dspark_fused_markov": false} keeps the speculator's
loop instead of the fused kernels; they stay on by default. Inline a
single-use local and drop the redundant T=1 distribution test case. The
kernels are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Signed-off-by: Juntian Liu <Juntianl777@gmail.com>
…rk-dep-fused-markov

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Signed-off-by: Juntian Liu <Juntianl777@gmail.com>
@mergify mergify Bot removed the needs-rebase label Nov 2, 2026
@ivanium
ivanium enabled auto-merge (squash) November 3, 2026 01:25
@github-actions github-actions Bot added the ready ONLY add when PR is ready to merge/full CI is needed label Nov 3, 2026
The speculator's loop is now the default. Set
additional_config={"dspark_fused_markov": true} to use the fused kernels.
The kernels are unchanged.

Signed-off-by: Juntian Liu <Juntianl777@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
auto-merge was automatically disabled November 3, 2026 01:30

Head branch was pushed to by a user without write access

@Juntian777

Copy link
Copy Markdown
Contributor Author

/ci run

@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #99415 for commit b195a3bc7abd.

@TheEpicDolphin TheEpicDolphin 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.

LGTM

@TheEpicDolphin
TheEpicDolphin enabled auto-merge (squash) November 3, 2026 03:52
@github-project-automation github-project-automation Bot moved this to Ready in NVIDIA Nov 3, 2026
@khluu
khluu merged commit 3d18166 into vllm-project:main Nov 3, 2026
107 checks passed
@github-project-automation github-project-automation Bot moved this from Ready to Done in NVIDIA Nov 3, 2026
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Sprint - DFlash Nov 3, 2026
yaoyaoding added a commit to yaoyaoding/vllm that referenced this pull request Nov 3, 2026
Resolve two conflicts under vllm/models/deepseek_v41/nvidia/:

- dspark.py: keep main's dspark_fused_markov opt-in (vllm-project#64442) beside the
  draft executor's registration, and main's compute_draft_logits_local.
- moe/routed_expert_gemm.py: take current_cu_stream from main's shared
  moe_tail_fusion primitives (vllm-project#64974) and keep the finalize kernel.

Signed-off-by: Yaoyao Ding <yaoyaod@nvidia.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
yaoyaoding added a commit to yaoyaoding/vllm that referenced this pull request Nov 3, 2026
With decode_backend=latency_specialized, the DSpark draft model now
samples through the model hook that DSparkSpeculator._sample_sequential
already asks first, so the speculator itself is unchanged:

- The specialized decode implies dspark_fused_markov: the fused loop of
  ops/fused_markov.py (vllm-project#64442), under the same conditions.
- Once the draft's executor is built, batches of up to 8 request rows
  (4 at 8 ranks) take the vocabulary-sharded Markov chain instead
  (ShardedMarkovSampling in specialized_decode/sampling/). Its set-up
  is agreed over the TP group, as before.

The layers test checks the hook with the switch on and off.

Signed-off-by: Yaoyao Ding <yaoyaod@nvidia.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/build deepseek Related to DeepSeek models dflash DSv4.1 Related to DeepSeek-V4.1 models nvidia ready ONLY add when PR is ready to merge/full CI is needed

Projects

Status: Done
Status: Done

Development

Successfully merging this pull request may close these issues.

6 participants