Skip to content

[BugFix] Reserve the bonus query slot in DFlash scheduling budget - #51256

Merged
jeejeelee merged 7 commits into
vllm-project:mainfrom
HF-001:dflash_fix
Aug 13, 2026
Merged

[BugFix] Reserve the bonus query slot in DFlash scheduling budget#51256
jeejeelee merged 7 commits into
vllm-project:mainfrom
HF-001:dflash_fix

Conversation

@HF-001

@HF-001 HF-001 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Purpose

The existing generic parallel-drafting calculation only reserves K - 1
slots for DFlash, leaving the scheduling budget short by one slot per
request.

For example, with:

max_num_batched_tokens = 2048
max_num_seqs = 256
num_speculative_tokens = 8

the previous calculation allowed:

max_num_scheduled_tokens = 2048 - 7 * 256 = 256

However, a full DFlash batch may require:

256 * (8 + 1) = 2304

query tokens, exceeding max_num_batched_tokens.

DFlash has K + 1 query tokens per request, so its net drafting expansion is K slots rather than the generic parallel-drafting value of K - 1.

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

@mergify mergify Bot added the bug Something isn't working label Aug 6, 2026
Signed-off-by: HF-001 <1670186653@qq.com>
Comment thread vllm/config/speculative.py Outdated
if self.parallel_drafting:
# For parallel drafting, we need one new slot per 'masked' token
slots_per_req = self.num_speculative_tokens - 1
if self.use_dflash():

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: Could we include self.use_dflash() in the existing increment condition below? This keeps the one-slot adjustment in a single place:

if self.uses_draft_model() or self.use_dflash():
     slots_per_req += 1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@dreamer-89 Thank you for your suggestion. The modifications have been completed

Comment thread tests/test_config.py Outdated
assert cfg.scheduler_config.async_scheduling is True


def test_dflash_max_num_new_slots_for_drafting():

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could we parameterize this test to cover both ordinary parallel drafting (K - 1) and DFlash (K) to ensure the fix does not change slot accounting for other parallel drafters.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@dreamer-89 Thank you for your suggestion. have added the p-eagle test case

@dreamer-89

Copy link
Copy Markdown

Thanks @HF-001, currently pre-commit check is failing and it needs a label to run the check. I will let the code owners/folks who have permission to add it.

Error: PR must have the 'verified', 'ready', or 'ready-run-all-tests' label to run pre-commit, or the author must have at least 4 merged PRs (found 1).

@HF-001

HF-001 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @HF-001, currently pre-commit check is failing and it needs a label to run the check. I will let the code owners/folks who have permission to add it.

Error: PR must have the 'verified', 'ready', or 'ready-run-all-tests' label to run pre-commit, or the author must have at least 4 merged PRs (found 1).

@dreamer-89 Thank you

@HF-001

HF-001 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @HF-001, currently pre-commit check is failing and it needs a label to run the check. I will let the code owners/folks who have permission to add it.

Error: PR must have the 'verified', 'ready', or 'ready-run-all-tests' label to run pre-commit, or the author must have at least 4 merged PRs (found 1).

@dreamer-89 Hello, can you help me find someone to label it? Thank you

@dreamer-89

Copy link
Copy Markdown

@mgoin @robertgshaw2-redhat, could one of you add the required verified/ready label, or point us to someone with permission?

@zixi-qi

zixi-qi commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

@HF-001 Thanks for this fix! Would be great if you could update the max_num_new_slots_for_drafting and the test to cover all cases here:
Screenshot 2026-08-11 at 1 59 03 PM

Comment thread tests/test_config.py Outdated
Comment on lines +436 to +437
("eagle3", 7),
("dflash", 8),

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.

By default eagle3 has parallel_drafting=False, only p-eagle has it set to true so will return 7. Could you please add some test to cover all cases?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@zixi-qi Thank you for your feedback. have added a wealth of test cases

Comment thread vllm/config/speculative.py Outdated
Comment on lines 1415 to 1428
# Draft models do not slice the draft tokens, while DFlash adds a
# bonus query before the masked tokens.
slots_per_req += 1
return slots_per_req

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.

I think current max_num_new_slots_for_drafting logic is a bit convoluted, would be good to handle each case separately and add some examples of expected output for each algorithm as comment to make it clearer.

Reference implementation below(not requiring you to copy exactly)

• @property
  def max_num_new_slots_for_drafting(self) -> int:
      """Return the maximum additional drafting slots per request.

      Let K be ``num_speculative_tokens``. For the standard configurations:

          Algorithm    method         parallel_drafting    return
          EAGLE3       eagle3         False                 0
          P-EAGLE      eagle3         True                  K - 1
          DFlash       dflash         True                  K
          DSpark       dspark         True                  K - 1
          MTP          mtp            False                 0
          N-gram       ngram          False                 0
          Draft model  draft_model    False                 1

      The scheduler already reserves one slot for the request's next token.
      """
      num_draft_tokens = self.num_speculative_tokens

      if self.use_dflash():
          # DFlash uses one bonus query followed by K mask queries.
          return num_draft_tokens

      if self.parallel_drafting:
          # P-EAGLE and default DSpark use K total query positions.
          if self.uses_draft_model():
              # Parallel draft-model inputs retain an additional unsliced token.
              return num_draft_tokens
          return num_draft_tokens - 1

      if self.uses_draft_model():
          # Serial draft-model inputs retain one unsliced token.
          return 1

      return 0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@zixi-qi Thank you, have optimized according to your suggestion

HF-001 added 2 commits August 12, 2026 14:20
Signed-off-by: HF-001 <1670186653@qq.com>
Signed-off-by: HF-001 <1670186653@qq.com>
@HF-001

HF-001 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

@HF-001 Thanks for this fix! Would be great if you could update the max_num_new_slots_for_drafting and the test to cover all cases here: Screenshot 2026-08-11 at 1 59 03 PM

@zixi-qi Thanks for your detailed suggestions. The relevant modifications have been completed

@zixi-qi zixi-qi added the ready ONLY add when PR is ready to merge/full CI is needed label Aug 12, 2026
@github-actions

Copy link
Copy Markdown

@HF-001, CI is now available for this PR.

  • /ci run starts a CI build.
  • /ci retry retries failed jobs in the CI build for the current PR head. If the current head has no CI build, it starts a new CI build for the current head containing only jobs that failed in the latest earlier CI build for this PR.
  • /ci cancel cancels scheduled or running CI builds for this PR branch.

@zixi-qi

zixi-qi commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #83565 for commit 96d40d056443.

@HF-001

HF-001 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #83632 for commit c5a6d38a7e0d.

@HF-001

HF-001 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

/ci retry

@github-actions

Copy link
Copy Markdown

✅ Queued 1 failed job(s) for retry in Buildkite CI #83632.

@jeejeelee
jeejeelee enabled auto-merge (squash) August 13, 2026 02:24
@jeejeelee
jeejeelee merged commit 2ac1f68 into vllm-project:main Aug 13, 2026
95 checks passed
jasl added a commit to jasl/vllm that referenced this pull request Aug 13, 2026
test_dspark_sequential_sampling_writes_persistent_draft_logits called
DSparkSpeculator.clear_runtime_draft_logits, which no longer exists, and the
fixture missed enable_adaptive_verification because object.__new__ skips
__init__.

The missing method is not a lost fix -- I first read it that way and was wrong.
fbbc8e7 added a reuse-and-clear scheme (assign base_logits into draft_logits,
clear it afterwards); 7d9970d replaced that six days later with a persistent
preallocated buffer, because DSpark drafting is CUDA-graph replayed and a
Python-side reassignment does not run per replay. The clearing call became a
`pass` and was later deleted. Restoring it would reintroduce something removed
for cause.

So the invariant is still worth asserting -- the draft-logits buffer must never
be replaced -- but it has to be checked against something that still exists. The
test now runs a second sampling pass and asserts buffer identity across it.

Both this and the three test_mtp failures were red at 67f5de5 as well as at
the merge head, so neither came from the 08-13 merge. What the merge did was
move this one's failure to a later line, which is what made it visible.

Remaining in tests/v1/spec_decode: test_dflash_drafter_window_reserves_bonus_token,
whose fix is upstream vllm-project#51256 -- in the sixteen commits not yet merged.
jasl added a commit to jasl/vllm that referenced this pull request Aug 13, 2026
test_dflash_drafter_window_reserves_bonus_token is upstream's, byte-identical to
theirs, and it builds SimpleNamespace runner stubs carrying exactly the fields
upstream's _input_fits_in_drafter reads.

This fork's version reads two more: self.parallel_config, for the per-rank
gate-off sentinel added with the TP drafter-gate work, and
self._drafter_gate_off_logged, its log counter. So our production change broke
their mock -- AttributeError from a stub that is correct for upstream and
incomplete for us. Their test, our behaviour, our stub update.

I expected upstream vllm-project#51256 (Reserve the bonus query slot in DFlash scheduling
budget) to fix this, because the PR title matches the test name. It did not and
could not: the failure was never upstream's. Verified after merging it -- same
AttributeError at the same line.

All five tests/v1/spec_decode failures identified earlier are now green:
3 x test_mtp (propose() signature drift), test_dspark_config (assertion on a
method we deliberately removed), and this one.
zyp2014 pushed a commit to zyp2014/vllm that referenced this pull request Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ready ONLY add when PR is ready to merge/full CI is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants