Skip to content

[Bugfix] Cover uniform decode sizes under an explicit max_cudagraph_capture_size - #55004

Open
bojiang3 wants to merge 1 commit into
vllm-project:mainfrom
bojiang3:fix/cudagraph-explicit-max-covers-uniform-decode
Open

bojiang3 wants to merge 1 commit into
vllm-project:mainfrom
bojiang3:fix/cudagraph-explicit-max-covers-uniform-decode

Conversation

@bojiang3

@bojiang3 bojiang3 commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Fixes #54933.

When max_cudagraph_capture_size is set explicitly and cudagraph_capture_sizes is
left unset, _set_cudagraph_sizes() only builds the stepped 8/16 token grid. The
uniform decode sizes (request count times decode query length) were computed inside
the max_cudagraph_capture_size is None branch, so with speculation on they were never
appended, the list ended at the last grid entry, and the explicit maximum was
truncated down to it.

Concretely, max_num_seqs=6 with six speculative tokens has a widest uniform decode
batch of 42 tokens. Setting max_cudagraph_capture_size=42 produced
[1, 2, 4, 8, 16, 24, 32, 40], a warning "Truncating max_cudagraph_capture_size to
40", and the 42 token verification step dispatched eager.

Changes

Compute the uniform decode sizes whenever the capture list is being inferred here,
bounded by the (possibly explicit) maximum, instead of only when the maximum is also
inferred. An explicit cudagraph_capture_sizes list is still left exactly as
configured, and the platform default ceiling still applies when no maximum is given.

The hunk in vllm/config/vllm.py looks large because the uniform size block moved
out one nesting level; with whitespace ignored it is a 14 line change.

Reproducer from the issue, before and after, on current main:

before: max_cudagraph_capture_size = 40   sizes = [1, 2, 4, 8, 16, 24, 32, 40]
after:  max_cudagraph_capture_size = 42   sizes = [1, 2, 4, 7, 8, 14, 16, 24, 28, 32, 40, 42]

The extra 7, 14 and 28 entries are the same request count grid the inferred maximum
path already produces, now also present under an explicit maximum.

Test Plan

tests/compile/test_config.py:

  • test_explicit_max_cudagraph_capture_size_covers_uniform_decode, parametrized over
    a maximum equal to, above and below the widest uniform batch.
  • test_explicit_cudagraph_capture_sizes_are_left_as_configured, guarding that an
    explicit list is never extended.

Test Result

New tests pass together with the existing cudagraph sizing tests in that file
(respects_platform_ceiling, keep_all_sizes_bounded, respect_sequence_parallelism,
caps_widest_ngram_decode_batch). Run on a DGX Spark (GB10) against current main.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved CUDA graph capture sizing for workloads using uniform decode batches, ensuring eligible batch shapes are included when they fit within the configured maximum.
    • Preserved explicitly configured capture-size lists without automatically adding additional sizes.
    • Maintained explicitly configured maximum capture limits while improving support for schedulable decode shapes outside the default size increments.

…apture_size

When max_cudagraph_capture_size is set explicitly and cudagraph_capture_sizes
is left unset, _set_cudagraph_sizes() only built the stepped 8/16 token grid.
The uniform decode sizes (request count times decode query length) were
computed inside the `max_cudagraph_capture_size is None` branch, so with
speculation on they were never appended, the inferred list ended at the last
grid entry, and the explicit maximum was truncated down to it.

With max_num_seqs=6 and six speculative tokens the widest uniform decode batch
is 42 tokens. Setting max_cudagraph_capture_size=42 produced
[1, 2, 4, 8, 16, 24, 32, 40], the warning "Truncating
max_cudagraph_capture_size to 40", and the 42 token verification step ran
eager (vllm-project#54933).

Compute the uniform decode sizes whenever the capture list is inferred here,
bounded by the possibly explicit maximum, rather than only when the maximum
is also inferred. An explicit cudagraph_capture_sizes list is still left as
configured and the platform default ceiling still applies when no maximum is
given. The large hunk is the uniform size block moving out one nesting level;
with whitespace ignored it is a 14 line change.

Reproducer from the issue on current main, before and after:

    before: max=40  sizes=[1, 2, 4, 8, 16, 24, 32, 40]
    after:  max=42  sizes=[1, 2, 4, 7, 8, 14, 16, 24, 28, 32, 40, 42]

Adds a parametrized regression test for a maximum equal to, above and below
the widest uniform batch, and one guarding that an explicit list is never
extended. Existing cudagraph sizing tests in the file still pass.

Fixes vllm-project#54933

Signed-off-by: bojiang3 <bli314159@gmail.com>

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.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.

@coderabbitai

coderabbitai Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 52836a0e-3fa0-48bf-a08e-8cd1851b122d

📥 Commits

Reviewing files that changed from the base of the PR and between 9b38e3a and 4531ce5.

📒 Files selected for processing (2)
  • tests/compile/test_config.py
  • vllm/config/vllm.py

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

Changes

Uniform decode CUDA graph sizing

Layer / File(s) Summary
Capture size resolution and regression coverage
vllm/config/vllm.py, tests/compile/test_config.py
_set_cudagraph_sizes now includes schedulable uniform decode sizes under an explicit scalar maximum. Explicit capture lists remain unchanged. Tests cover scalar limits of 40, 42, and 48, plus an explicit [8, 16] list.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 4531c

The fix adds missing bounded CUDA-graph sizes for an existing configuration path while preserving explicitly configured lists. No actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: lucaswilkinson, taneem-ibrahim

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix: preserving uniform decode capture sizes under an explicit max_cudagraph_capture_size.
Linked Issues check ✅ Passed The implementation and regression tests satisfy issue #54933 by retaining schedulable uniform decode sizes within an explicit scalar maximum and preserving explicit cudagraph_capture_sizes lists uncha…
Out of Scope Changes check ✅ Passed The changes are limited to _set_cudagraph_sizes and focused regression tests for the linked CUDA graph sizing bug. No unrelated code changes are shown.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 2 files.
Full details: Linked Issues check

Explanation

The implementation and regression tests satisfy issue #54933 by retaining schedulable uniform decode sizes within an explicit scalar maximum and preserving explicit cudagraph_capture_sizes lists unchanged.

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mergify

mergify Bot commented Sep 17, 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, @bojiang3.

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

@mergify mergify Bot added the needs-rebase label Sep 17, 2026
MirkoDeVita98 added a commit to MirkoDeVita98/vllm that referenced this pull request Sep 24, 2026
When `max_cudagraph_capture_size` is set explicitly and
`cudagraph_capture_sizes` is left unset, `_set_cudagraph_sizes()` builds the
stepped 8/16 grid and then truncates the scalar maximum down to the last grid
entry. Decode batches between that entry and the configured maximum have no
captured graph and fall back to eager execution.

  asked  12 -> resolved  8   sizes [1, 2, 4, 8]
  asked  50 -> resolved 48   sizes [1, 2, 4, ..., 40, 48]
  asked 100 -> resolved 96   sizes [1, 2, 4, ..., 88, 96]

This is the non-speculative counterpart of vllm-project#54933. That issue, and vllm-project#55004 which
fixes it, concern `uniform_decode_sizes`, which are only computed when
`decode_query_len > 1`; with plain decode the list still ends on the grid.

Append the maximum to the inferred list when the grid did not reach it, next to
the existing `max_num_batched_tokens` append that preserves the same property.
The value appended is the one already clipped to `max_num_batched_tokens`, so it
cannot exceed the token budget, and an explicit `cudagraph_capture_sizes` list
is still left exactly as configured. Costs one extra captured graph.

Closes: vllm-project#58523

Signed-off-by: MirkoDeVita98 <mirko.devita@icloud.com>

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

Projects

Status: No status
Status: To triage

Development

Successfully merging this pull request may close these issues.

[Bug]: Explicit scalar CUDA graph maximum can drop a required uniform-decode shape

1 participant