Skip to content

[II] Require decode state for FULL CUDA graph dispatch - #298

Open
voipmonitor wants to merge 1 commit into
local-inference-lab:dev/infernal-invocationfrom
voipmonitor:fix/ii-uniform-decode-prefill-classification-20260812
Open

[II] Require decode state for FULL CUDA graph dispatch#298
voipmonitor wants to merge 1 commit into
local-inference-lab:dev/infernal-invocationfrom
voipmonitor:fix/ii-uniform-decode-prefill-classification-20260812

Conversation

@voipmonitor

@voipmonitor voipmonitor commented Aug 12, 2026

Copy link
Copy Markdown

Behavior

FULL CUDA graph replay is selected only when every scheduled request is decoding and every request has the same query length. Prompt-only batches and mixed prompt/decode batches use the non-FULL dispatch path even when their token-count shape matches speculative decode.

Dummy capture batches retain shape-only classification because the capture input is uniform by construction. Uniform decode remains eligible for FULL replay in the target runner, autoregressive speculator, and multi-module MTP speculator.

Root cause

Model Runner V2 classified uniform decode from token shape alone. A prompt chunk can contain the same K+1 tokens per request as speculative decode, allowing a decode CUDA graph to replay over prompt state.

DeepSeek-V4-Flash-0731 with DSpark K5 exposed the collision at six tokens per request. The failure returned syntactically valid API responses containing repeated, raw-token, or multilingual output; the engine did not necessarily raise an exception.

This change ports the state-aware classification from vLLM commit 0a94d85a, merged through vLLM #51865.

Compatibility

  • Uniform all-decode batches retain FULL CUDA graph replay.
  • Prompt-only and mixed prompt/decode batches use the valid non-FULL graph mode.
  • Input preparation reuses one CPU request-state snapshot, so graph dispatch and tensor construction cannot classify different request states.
  • The commit merges cleanly after all twelve vLLM PR heads used by the Infernal Invocation r3 source composition.

Validation

  • 50 focused unit tests passed across CUDA graph dispatch, request ordering, V2 input batches, autoregressive speculation, multi-module MTP, and acceptance control.
  • The exact Infernal Invocation integration tree passed 36 focused tests.
  • Ruff, formatting, compileall, and staged-diff checks passed.
  • Control image voipmonitor/vllm:infernal-invocation-vllm6c50b0a-b12x1584743-fi1ac6942-cu133-torch213-20260812-r3: two independent TP2/DSpark-K5/C4 runs each produced one corrupt response, at request 159 and request 155 respectively.
  • State-aware build: 160/160 responses passed the same long-running profile; the response-integrity watchdog found no raw-token, replacement-character, or multilingual corruption, and the server log contained no runtime error.
  • Concurrent strict tool-call requests with 150,003 and 300,128 prompt tokens passed with 40 GiB native KV offload enabled. Both returned isolated tool calls and the server remained healthy.
  • Aggregate generation throughput was 115.76 tok/s for the state-aware build versus 116.34 tok/s for the second control run on a different GPU pair (-0.50%).

Summary by CodeRabbit

  • Bug Fixes

    • Improved batch classification for speculative decoding and CUDA graph dispatch.
    • Prevented prompt-prefill batches from incorrectly selecting full CUDA graphs.
    • Corrected prefill detection when requests appear at different positions in a batch.
    • Improved handling of uniform decode batches, dummy batches, and mixed request states.
  • Tests

    • Added regression coverage for speculative decoding, batch ordering, prompt-length collisions, and prefill detection.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@voipmonitor, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9f83f553-4933-4c12-818d-3aaaf4fb7904

📥 Commits

Reviewing files that changed from the base of the PR and between 6602a45d26e9e55c40c258b24b38995da5471dcc and b8d92cb.

📒 Files selected for processing (5)
  • tests/v1/worker/test_gpu_batch_ordering.py
  • vllm/v1/worker/gpu/cudagraph_utils.py
  • vllm/v1/worker/gpu/input_batch.py
  • vllm/v1/worker/gpu/model_runner.py
  • vllm/v1/worker/utils.py
📝 Walkthrough

Walkthrough

Changes

The change adds prefill-aware uniform decode classification. GPUModelRunner gathers request state before dispatch, and both speculative-decoding implementations use that state to avoid FULL CUDA graphs for batches containing prefilling requests. Regression tests cover ordering, dummy batches, prompt-shape collisions, and dispatch selection.

Uniform decode dispatch

Layer / File(s) Summary
Decode classification contract
vllm/v1/worker/utils.py, vllm/v1/worker/gpu/cudagraph_utils.py
Uniform query-length checks are centralized. Uniform decode classification now returns a token count only when no request is prefilling.
Batch request state
vllm/v1/worker/gpu/model_runner.py, vllm/v1/worker/gpu/input_batch.py
GPUModelRunner gathers ordered request mappings and prefill metadata before input preparation. InputBatch.has_prefill exposes aggregate prefill state.
Speculative dispatch and regression coverage
vllm/v1/worker/gpu/spec_decode/..., tests/v1/spec_decode/..., tests/v1/worker/...
Speculator dispatch uses the prefill-aware helper. Tests cover uniform decode batches, prefilling batches, request-state indexing, dummy batches, and CUDA-graph selection.

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

Sequence Diagram(s)

sequenceDiagram
  participant GPUModelRunner
  participant InputBatch
  participant Speculator
  GPUModelRunner->>GPUModelRunner: Gather batch request state
  GPUModelRunner->>InputBatch: Pass prefill metadata
  InputBatch-->>Speculator: Expose has_prefill
  Speculator->>Speculator: Compute uniform decode token count
  Speculator-->>GPUModelRunner: Select CUDA graph dispatch
Loading

Possibly related issues

Possibly related PRs

Suggested reviewers: njhill, lukealonso

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 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 change: requiring decode state before FULL CUDA graph dispatch.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 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.

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

🧹 Nitpick comments (1)
vllm/v1/worker/utils.py (1)

604-619: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Google-style docstrings for the new helper APIs.

Add applicable Args: and Returns: sections.

  • vllm/v1/worker/utils.py#L604-L619: Document arguments and return values for both classifiers.
  • vllm/v1/worker/gpu/cudagraph_utils.py#L105-L112: Document arguments and return value for get_uniform_token_count.
  • vllm/v1/worker/gpu/model_runner.py#L1336-L1344: Document arguments and tuple return values for gather_batch_req_state.
  • vllm/v1/worker/gpu/input_batch.py#L115-L118: Add a Returns: section for has_prefill.
  • tests/v1/worker/test_gpu_batch_ordering.py#L50-L79: Document helper arguments and return values.

As per coding guidelines, Python code must use Google-style docstrings with Args:/Returns:/Raises: sections.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vllm/v1/worker/utils.py` around lines 604 - 619, Update the Google-style
docstrings for is_uniform_query_len and get_uniform_decode_token_count in
vllm/v1/worker/utils.py, get_uniform_token_count in
vllm/v1/worker/gpu/cudagraph_utils.py, gather_batch_req_state in
vllm/v1/worker/gpu/model_runner.py, has_prefill in
vllm/v1/worker/gpu/input_batch.py, and the helpers in
tests/v1/worker/test_gpu_batch_ordering.py. Add Args: entries for each parameter
and Returns: entries describing each return value, including
gather_batch_req_state’s tuple components; the input_batch.py site requires only
Returns: if arguments are already documented.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@vllm/v1/worker/utils.py`:
- Around line 604-619: Update the Google-style docstrings for
is_uniform_query_len and get_uniform_decode_token_count in
vllm/v1/worker/utils.py, get_uniform_token_count in
vllm/v1/worker/gpu/cudagraph_utils.py, gather_batch_req_state in
vllm/v1/worker/gpu/model_runner.py, has_prefill in
vllm/v1/worker/gpu/input_batch.py, and the helpers in
tests/v1/worker/test_gpu_batch_ordering.py. Add Args: entries for each parameter
and Returns: entries describing each return value, including
gather_batch_req_state’s tuple components; the input_batch.py site requires only
Returns: if arguments are already documented.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2304580e-066a-4da1-86c1-b430f087e11c

📥 Commits

Reviewing files that changed from the base of the PR and between ce5f50f and 6602a45d26e9e55c40c258b24b38995da5471dcc.

📒 Files selected for processing (9)
  • tests/v1/spec_decode/test_dynamic_sd_cug.py
  • tests/v1/worker/test_gpu_batch_ordering.py
  • tests/v1/worker/test_gpu_input_batch_v2.py
  • vllm/v1/worker/gpu/cudagraph_utils.py
  • vllm/v1/worker/gpu/input_batch.py
  • vllm/v1/worker/gpu/model_runner.py
  • vllm/v1/worker/gpu/spec_decode/autoregressive/speculator.py
  • vllm/v1/worker/gpu/spec_decode/multi_module_mtp/speculator.py
  • vllm/v1/worker/utils.py

Classify scheduled batches with per-request prefill state before selecting a FULL decode graph. A prompt chunk can contain the same K+1 token count as speculative decode, so token shape alone is not a valid decode invariant. Dummy capture batches remain shape-classified because they are uniform by construction.

Uniform all-decode batches retain FULL graph replay. Mixed prefill/decode batches and prompt-only batches use the non-FULL dispatch path. The target runner, autoregressive speculator, and multi-module MTP speculator share the state-aware predicate.

Validation: 50 focused tests passed across CUDA graph dispatch, request ordering, V2 input batches, autoregressive speculation, multi-module MTP, and acceptance control. The exact Infernal Invocation integration stack passed 36 focused tests and accepted this commit after all twelve release PR heads without a merge conflict. Ruff, formatting, compileall, and staged diff checks passed.

DeepSeek-V4-Flash-0731 with TP2, DSpark K5, concurrency four, and FULL CUDA graphs produced one corrupt response in each of two independent 160-request control runs. The state-aware build completed 160/160 correctly with no response-integrity findings or runtime errors. Concurrent 150,003-token and 300,128-token strict tool-call requests passed with 40 GiB native KV offload enabled, and the server remained healthy.

Ported from vLLM commit 0a94d85.
@voipmonitor

Copy link
Copy Markdown
Author

Release-composition qualification

Status: qualified. Commit b8d92cb5d26e1c6fc4c5ad513b806dae961a4afd is included in voipmonitor/vllm:infernal-invocation-vllm3226eb7-b12x1584743-fi1ac6942-cu133-torch213-20260812-r4 (sha256:21f048058375ccf00ea555f37addad326a7ee33bc2b4699ae53370f25af4ecb6).

Conditions: DeepSeek-V4-Flash-0731 revision 9e165c30e2704aec5d9d593cce3eebd58bbef1cb, TP2/DCP1, B12X W4A8, fixed probabilistic DSpark K5, FP8 compressed MLA KV, native KV offload, CUDA 13.3, and PyTorch 2.13.0.

  • 160/160 concurrent C4 requests completed without response-integrity violations. The two baseline failures occurred at requests 155 and 159 under the same workload.
  • Concurrent strict-tool requests with 150,003 and 300,128 prompt tokens returned separate valid tool calls and left the engine healthy.
  • 50 focused classifier and dispatch tests passed. The Docker release contract and 27 repository tests also passed.
  • TP4 fixed K5 retained FULL CUDA graphs (8 target, 8 DSpark, and 9 context-KV graph sizes), reached 905.68 tok/s at C8, and reached 16,444 / 16,011 prefill tok/s at 8,191 / 63,984 prompt tokens.

Artifacts:

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants