mudler / mudler/vllm.cpp

fix(ENG-CUDAGRAPH-BREAK): a batch of one-token prefill chunks dispatches as uniform decode, on both eligibility predicates

Open
#2,694 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
423
Forks
53
Avg merge
20h 26m
Merged PRs (30d)
310

Description

Row: ENG-CUDAGRAPH-BREAK

Found by wave PORTQ-4 (#2680)
re-deriving PORT-NOW entry 146 of 5559679229..e126687a9a, upstream
0a94d85a66 vllm#51865
"[Bugfix][MRV2] Require all requests to be decoding for uniform-decode dispatch".

What is wrong

A batch of N one-token prefill chunks is dispatched as uniform decode, because
neither eligibility predicate tests for prefill.

src/vllm/v1/worker/gpu/cudagraph_dispatch.h:168
  if (!q.has_value() || *q == 1) return q;

GraphEligibleQueryLen (:162-176) returns a uniform-decode answer at q == 1
with no prefill conjunct at all. Its q > 1 arm (:169-174) is stricter than
upstream — it requires every request to be verifying at exactly q-1 drafts — so
only q == 1 is exposed.

The second predicate has the same hole:

src/vllm/v1/worker/gpu/runner.cpp:2603-2604
  const bool pure_decode = attn_meta.num_actual_tokens == num_reqs &&
                           gdn_meta.num_prefill_tokens == 0;

gdn_meta is built only for GDN models (runner.cpp:2475,2479,2534-2538; the
comment at :2475 says "skipped — gdn_meta stays default-empty"), so on every
non-GDN model
the only prefill conjunct is inert, and a batch of N one-token
prefill chunks satisfies num_actual_tokens == num_reqs.

Both values ship to every registered model on ModelForwardInput
(runner.cpp:2715 .pure_decode, :2723 .uniform_query_len; field declared
include/vllm/model_executor/models/model_registry.h:582) and gate the decode-graph
drivers — qwen3_moe_registry.cpp:117, deepseek_v2_registry.cpp:116,
glm4_moe_lite_registry.cpp:135, qwen3.cpp:1176.

Size

A per-step has_prefill boolean threaded into both predicates. The signal already
exists in this tree's vocabulary and needs no new plumbing:
the prefill-row test is
seq_len <= prefill_len (include/vt/cuda/combine_tokens.h:32-34), and both arrays
are already in scope at the dispatch point — input_batch_.prefill_len and
step.seq_lens are used together at runner.cpp:2433 and :2442, upstream of
:2603 in the same function.

Roughly 20-40 product lines across cudagraph_dispatch.h (a has_prefill parameter
on GraphEligibleQueryLen, mirroring upstream's get_uniform_decode_token_count)
and runner.cpp (compute the reduction, add it to pure_decode), plus tests in
tests/vllm/v1/worker/gpu/test_cudagraph_dispatch.cpp, which already exercises the
shape predicates at :32-51,104-109.

What was NOT determined — read this before sizing the severity

No wrong token was demonstrated. Nothing was executed. Two mitigations argue the
blast radius may be narrower here than upstream:

  • combine_tokens already distinguishes prefill rows from decode rows by
    seq_len <= prefill_len independently of this predicate, so input ids are not
    mis-sourced.
  • SpecAsDecodeQueryLen returns 0 at q == 1
    (include/vllm/v1/attention/backend.h:196-205), so the attention-lane
    classification is unaffected.

What remains exposed is the decode-graph capture and replay itself taking a step
that contains prefill rows. Whether that is a correctness fault or a shape mismatch
needs a run. The predicate divergence from upstream is unambiguous either way,
and 0a94d85a66 is post-pin: git show 5559679229:vllm/v1/worker/gpu/cudagraph_utils.py
has get_uniform_token_count at :92 with no has_prefill.

Prior triage, and a record defect it carries

.agents/sync/2026-09-01-cdefd9d.md:1952 already ranks this fourth on the #2524
worked list, and its substance and line number are both correct. Its path is
not:
it cites include/vllm/v1/worker/gpu/cudagraph_dispatch.h:168, and there is
no include/ copy of that file — it lives at
src/vllm/v1/worker/gpu/cudagraph_dispatch.h.

This is the second time that same wrong path has been found in that record.
.agents/sync/2026-09-03-portq3.md:132-133 corrected it for a different entry and
fixed it only inside its own report. This wave annotates the source.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/vllm/v1/worker/gpu/cudagraph_dispatch.h and runner.cpp, especially GraphEligibleQueryLen and the pure_decode calculation around the cited lines. Read the existing predicate cases in tests/vllm/v1/worker/gpu/test_cudagraph_dispatch.cpp, then run those tests and inspect the prefill-row signal used earlier in runner.cpp. Done means prefill-containing batches are excluded by both eligibility predicates and the relevant tests pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
machine-learning
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.