Skip to content

[Bugfix][TurboQuant] Fix CUDA graph capture crash with spec-decode + chunked-prefill (#40807) - #43747

Open
oneraghavan wants to merge 1 commit into
vllm-project:mainfrom
oneraghavan:fix/turboquant-cudagraph-tolist-crash-40807
Open

[Bugfix][TurboQuant] Fix CUDA graph capture crash with spec-decode + chunked-prefill (#40807)#43747
oneraghavan wants to merge 1 commit into
vllm-project:mainfrom
oneraghavan:fix/turboquant-cudagraph-tolist-crash-40807

Conversation

@oneraghavan

Copy link
Copy Markdown
Contributor

Purpose

Fixes #40807.

TurboQuant's _prefill_attention continuation branch calls .tolist() on GPU tensors (query_start_loc and seq_lens), which is illegal during CUDA graph capture. This crashes engine initialization when TurboQuant KV cache (turboquant_k8v4, turboquant_4bit_nc, or turboquant_3bit_nc) is combined with --speculative-config method=mtp and --enable-chunked-prefill:

RuntimeError: Cannot copy between CPU and CUDA tensors during CUDA graph capture
unless the CPU tensor is pinned.

The crash occurs at turboquant_attn.py:570 in the continuation-prefill path, which is only entered when max_query_len != max_seq_len — exactly the condition created by spec-decode K+1 verify batches during CUDA graph capture warmup.

Root Cause

  1. _cudagraph_support was set to UNIFORM_BATCH, telling vLLM's compilation framework that TurboQuant supports full CUDA graph capture for multi-token batches (including spec-decode K+1 verify batches).
  2. During capture warmup, spec-decode constructs batches where max_query_len != max_seq_len, falling into the continuation branch that calls .tolist() on GPU tensors — illegal during graph capture.
  3. build_for_cudagraph_capture did not guarantee CPU-resident copies of query_start_loc and seq_lens were populated, so the fallback .tolist() path could be reached.

Fix

Three-layer defense:

  1. Downgrade _cudagraph_support from UNIFORM_BATCH to UNIFORM_SINGLE_TOKEN_DECODE. This tells the compilation framework that TurboQuant only supports full CUDA graph capture for single-token decode batches. When spec-decode is active (uniform_decode_query_len > 1), the framework automatically downgrades to PIECEWISE mode — K+1 verify batches run eager (correct), while 1-token decode retains CUDA graph (fast).

  2. Populate CPU-resident copies in build_for_cudagraph_capture. If seq_lens_cpu or query_start_loc_cpu are None, they are now explicitly created. This ensures the prefill path always has CPU-resident data and never falls through to .tolist() on GPU tensors.

  3. Add is_current_stream_capturing() guard in _prefill_attention continuation branch. Defense-in-depth: if the continuation branch is somehow reached during CUDA graph capture despite fix 1, it returns zeros instead of crashing. Safe because attention outputs during capture are only used for memory profiling, not graph content.

Relation to Other PRs

Related Issues

Test Plan

python -m pytest tests/v1/attention/test_turboquant_cudagraph_safety.py -v

7 tests covering:

  • _cudagraph_support is UNIFORM_SINGLE_TOKEN_DECODE
  • Support level blocks spec-decode full capture
  • CPU copies present/absent behavior
  • .tolist() on CPU tensors is safe
  • is_current_stream_capturing() guard returns zeros (requires CUDA)

Test Result

tests/...::TestCudagraphSupport::test_cudagraph_support_level PASSED
tests/...::TestCudagraphSupport::test_cudagraph_support_blocks_spec_decode_full_capture PASSED
tests/...::TestBuildForCudagraphCaptureCPUCopies::test_cpu_copies_present_when_builder_provides_them PASSED
tests/...::TestBuildForCudagraphCaptureCPUCopies::test_cpu_copies_absent_shows_the_gap PASSED
tests/...::TestBuildForCudagraphCaptureCPUCopies::test_tolist_on_cpu_tensor_is_safe PASSED
tests/...::TestBuildForCudagraphCaptureCPUCopies::test_tolist_on_cpu_seq_lens_is_safe PASSED
tests/...::TestPrefillCaptureGuard::test_capture_guard_returns_zeros SKIPPED (no CUDA)
6 passed, 1 skipped

…chunked-prefill (vllm-project#40807)

TurboQuant's _prefill_attention continuation branch calls .tolist() on GPU
tensors, which is illegal during CUDA graph capture. This crashes engine
initialization when TurboQuant KV cache is combined with speculative
decoding and chunked prefill.

Three-layer fix:
1. Downgrade _cudagraph_support from UNIFORM_BATCH to
   UNIFORM_SINGLE_TOKEN_DECODE so spec-decode K+1 verify batches
   automatically fall to PIECEWISE mode (continuation runs eager).
2. Populate CPU-resident copies of query_start_loc and seq_lens in
   build_for_cudagraph_capture as defense-in-depth.
3. Add is_current_stream_capturing() guard in _prefill_attention
   continuation branch to return zeros safely during capture warmup.

Signed-off-by: raghavan <oneraghavan@gmail.com>
@oneraghavan

Copy link
Copy Markdown
Contributor Author

Hi @LucasWilkinson @MatthewBonanni — could you take a look when you get a chance? This fixes a CUDA graph capture crash in TurboQuant's _prefill_attention when used with spec-decode + chunked-prefill (GPU .tolist() call during capture). Fixes #40807. CI needs the ready label to run. Thanks!

@oneraghavan

Copy link
Copy Markdown
Contributor Author

Friendly ping — this PR is ready for review. Let me know if there are any changes needed or blockers. Happy to address feedback. Thanks!

@oneraghavan

Copy link
Copy Markdown
Contributor Author

@mgoin — Friendly ping for review. This fixes #40807 where TurboQuant KV + spec-decode + chunked-prefill crashes CUDA graph capture at query_start_loc.tolist() in the continuation-prefill path. Would appreciate a look when you get a chance. Thanks!

@mergify

mergify Bot commented Aug 1, 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, @oneraghavan.

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 Aug 1, 2026
justtestingthingsx pushed a commit to meandmyboiclaude/vllm that referenced this pull request Aug 7, 2026
…ec-decode + chunked-prefill)

(cherry picked from commit a35fc54)
(cherry picked from commit 3cdbd2e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working needs-rebase nvidia quantization ready ONLY add when PR is ready to merge/full CI is needed v1

Projects

Status: No status

2 participants