Skip to content

[Spec Decode][DSpark] Markov sampling in the Gumbel kernel, wider DFlash padding, top-p fix - #64476

Open
zyongye wants to merge 3 commits into
mainfrom
minimax-m31-flash-dspark-sampling
Open

zyongye wants to merge 3 commits into
mainfrom
minimax-m31-flash-dspark-sampling

Conversation

@zyongye

@zyongye zyongye commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Overview

This PR speeds up the DSpark/DFlash draft step under MRV2 and fixes a top-p masking bug. It contains:

  • the Markov bias added inside the Gumbel kernel;
  • wider DFlash input padding;
  • is_padding written by the positions kernel;
  • a fix for the Triton top-k/top-p kernel.

Split out of #63232 (MiniMax-M3.1-Flash). Based on main; it does not depend on the other PRs of that split. Batch-sharded DSpark draft sampling was dropped from this PR; #63886 covers it.

Claims

  • Markov sampling:
    • The Gumbel kernel adds the Markov bias itself and caches the biased logits it samples from, so verification stays lossless.
    • One kernel combines the per-block maxima, replacing argmax + gather.
    • The temperature divide is skipped at 1.0.
    • Draft ids and cached draft logits are bit-identical to adding the bias first.
  • DFlash: prepare_dflash_inputs pads the per-request buffers in 1024-wide blocks. Before, it used BLOCK_SIZE, which is 8 in a decode step, so the padding took thousands of serial iterations.
  • MRV2: with VLLM_MOE_SKIP_PADDING (on by default), the positions kernel writes is_padding, replacing two fill_ launches per step. The result is the same, including after adaptive compaction.
  • Triton top-k/top-p, more than 64 rows (bug fix): a top-p below the fp32 resolution of the kept mass (e.g. 1e-9) could mask every token of a row. The kernel now keeps the max token(s) in that case. It is also warmed up with V2's contiguous FP32 row stride.

Validation

Unit tests on GB300:

pytest tests/v1/spec_decode/test_dspark_markov_sampling.py tests/v1/worker/test_gpu_batch_shard.py \
  tests/v1/worker/test_gpu_gumbel_sample.py tests/v1/spec_decode/test_rejection_sampler_utils.py \
  tests/v1/worker/test_gpu_input_batch_v2.py tests/v1/sample/test_topk_topp_sampler.py \
  tests/v1/spec_decode/test_dflash2.py tests/v1/spec_decode/test_dflash_prepare_inputs.py \
  tests/v1/spec_decode/test_dspark_topk.py tests/v1/worker/test_gpu_model_runner_v2_eplb.py

460 passed, 1 skipped, 0 failed.

New tests:

  • test_dspark_markov_sampling.py::test_markov_sampling_matches_unfused runs the Markov loop with the real LM-head, Markov embedding and Markov bias layers. For greedy and probabilistic drafting, with full and reduced draft vocabularies, it checks that the loop gives the same draft ids and cached draft-logits rows as adding the bias first.
  • test_gpu_gumbel_sample.py::test_gumbel_combine_preserves_first_nan_and_maximum checks that the combine kernel follows torch.argmax: the first NaN wins, otherwise the first maximum.
  • test_rejection_sampler_utils.py::test_block_verification_is_unbiased_across_steps drafts with gumbel_sample over many steps and checks that block verification keeps the target distribution.
  • test_gpu_input_batch_v2.py::test_prepare_positions_preserves_padding_after_compaction checks the is_padding writes.
  • test_topk_topp_sampler.py::test_tiny_p_keeps_max_token fails on main's kernel (2 failed) and passes here.

Performance:

before after measured on
Markov loop, kernels per draft step 7 4 this branch, torch profiler, 1 request, 3 steps: 17 kernels for the loop vs 24 with the bias added outside the kernel; main's 7 also has argmax + gather in place of the combine kernel
DFlash input preparation per draft step 21 us 6 us the internal branch these changes come from, GB300, MiniMax-M3.1 DSpark, 1 request, nsys

The 4 kernels per step are the Markov embedding, the bias GEMM, the Gumbel kernel and the combine kernel. The fused path removes the bias add and the per-step copy into draft_tokens.

Not covered: no end-to-end benchmark or accuracy eval on this branch.

Details

Credits: qizixi (Markov bias in the Gumbel kernel), plus Dao Le, Taoyu Zhu, Zhewen Li, Zijing Liu and xiaozhoupy, whose DSpark work this comes from, as co-authors in the commit. AI assistance (Claude) was used to port these changes onto main, and to write the port's tests and this description. The submitter reviewed the change and ran the tests above.


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.

🤖 Generated with Claude Code

zyongye and others added 2 commits October 29, 2026 07:24
…g in the Gumbel kernel

- DSpark batch-sharded draft sampling: under batch-sharded sampling each
  TP rank samples the drafts of the requests it verifies, from an
  all-to-all of the vocab-sharded draft logits, instead of every rank
  sampling every request from all-gathered logits. Owners follow
  DraftLogitsCache.assign (batch position % TP), and the draft logits are
  written through its row mapping.
- Markov sampling: add the Markov bias inside the Gumbel kernel and cache
  the biased logits; combine the per-block maxima in one kernel; skip the
  divide at temperature 1.
- DFlash: pad the prepared inputs in wide blocks.
- Scheduler: no draft-slot charge for MRV2 DFlash/DSpark when every
  request's queries fit max_num_batched_tokens.
- MRV2: write is_padding with the positions for VLLM_MOE_SKIP_PADDING.
- Top-k/top-p: keep the max token(s) when a top-p below fp32 resolution
  drops every duplicate; warm the kernels up for V2's contiguous FP32 rows.

Co-authored-by: qizixi <22851944+zixi-qi@users.noreply.github.com>
Co-authored-by: Dao Le <daole@inferact.ai>
Co-authored-by: Taoyu Zhu <zhutaoyu97@gmail.com>
Co-authored-by: Zhewen Li <jerven.vllm@gmail.com>
Co-authored-by: Zijing Liu <liuzijing2014@users.noreply.github.com>
Co-authored-by: xiaozhoupy <peiyuanzhou1994@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yongye Zhu <zyy1102000@gmail.com>
Main already reserves no draft slots for DFlash and DSpark
(SpeculativeConfig.max_num_new_slots_for_drafting returns 0 for both), so
the override was a no-op.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yongye Zhu <zyy1102000@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 repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

@zixi-qi

zixi-qi commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

Current PR overlaps with #63554 and probably needs to be rebased

@TheEpicDolphin

Copy link
Copy Markdown
Member

chatted with @zyongye offline, I'll takeover batch-sharded DSpark sampling in #63886, and this PR will keep the remaining spec decode perf optimizations

#63886 covers batch-sharded DSpark draft sampling, so this PR keeps only
the Markov sampling in the Gumbel kernel. Remove DraftBatchSharder,
compute_draft_logits_local and the drafter's sharding hooks. Without the
sharded path the bias row is the token's own row, so gumbel_sample drops
bias_rows. The fused-vs-unfused Markov test moves to
test_dspark_markov_sampling.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yongye Zhu <zyy1102000@gmail.com>
@zyongye zyongye changed the title [Spec Decode][DSpark] Batch-sharded draft sampling and Markov sampling in the Gumbel kernel [Spec Decode][DSpark] Markov sampling in the Gumbel kernel, wider DFlash padding, top-p fix Oct 29, 2026
@TheEpicDolphin TheEpicDolphin self-assigned this Oct 29, 2026
Comment on lines +236 to +237
idx_map_steps = idx_map.t().contiguous()
draw_pos_steps = (sample_pos.t() - 1).contiguous()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

😠

@mergify

mergify Bot commented Oct 30, 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, @zyongye.

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

This branch has not been deployed

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

Labels

dflash mrv2 Model Runner V2 specific needs-rebase qwen Related to Qwen models speculative-decoding

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

4 participants