Conversation
…rop the speculative back-off Align-mode states materialize only at chunk ends, so a quiet prefill leaves one deep mid-prompt state: siblings sharing less than that position get zero reuse even on an idle server, and exactly block-aligned prompts get zero on identical repeats (the only state sits above the num_tokens - 1 lookup cap). On top of that, the speculative one-block back-off - sized for 16-token attention blocks - forfeits an entire 544-2128 token align block for the whole use_eagle() family (measured on GB10: half the reusable prefix on aligned prompts, one extra cold pass, ~9x warm prefill). Stop every chunk at its next block boundary when internal prefill checkpoints are unavailable, so a reusable state materializes at every crossed boundary, and remove the back-off: with a state at every boundary, a lookup whose last block is pruned falls back one block instead of missing. The checkpoint path (vllm-project#52789) keeps deep chunks - mid-block states are recoverable there and need no boundary stops. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm6Q54FRX5t8uDLx2Jbrh5 Signed-off-by: Kam Basra <kameldipbasra@gmail.com>
|
👋 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. 🚀 |
|
Ran this on the GB10 rig as asked. Both changes are provably active — a log line inside Caveat that may be the whole story: our build predates #52789, so there is no Happy to re-run against your branch on a build that has #52789 if that is the more useful test. Disclosure: AI-assisted analysis (Claude Code); I reviewed the arithmetic and code paths myself. |
|
Thank you for running it — and your numbers are more informative than "no movement" suggests: both are exactly what the model predicts for that probe geometry. Walking it through for your build (FA block = mamba block, identical repeats, lookup-side Eagle drop of one block):
Two things follow:
Base has a single state at 4,800, above both siblings' reach; this PR has states at every boundary. If pair A moves 0 → 1,600 and pair B moves 0 → 3,200, that's the sparse-state fix visible end-to-end on your hardware — and it's the case that matters for "a fifth of an ~8k agent prompt given up per request", since agent traffic shares partially far more often than exactly. And yes please to the offer: a re-run against the branch verbatim on a #52789-inclusive build would additionally exercise the checkpoint-path conditioning (deep chunks preserved where internal checkpoints exist), which your backport necessarily approximated. Disclosure: AI-assisted analysis (Claude Code); I reviewed the arithmetic and code paths myself. |
|
Ran the two sibling pairs. Neither prediction holds on this build — parent 6 400 tokens, sibling
So the sibling that should gain does not move, and the one that should start at zero already hits One trap worth naming: my first attempt shared one parent across both pairs, which lets pair A's Caveat unchanged: this build predates #52789, so the PR is applied as its intent for the Disclosure: AI-assisted analysis (Claude Code); I reviewed the arithmetic and code paths myself. |
|
Root-caused, with your table reproducing rather than argued away — and the miss was mine, twice over, in an instructive way. First: my predictions modeled a single prefill of the parent, but your protocol sends each prompt three times — and your own staircase discovery is exactly what that changes. Second: Base arm — your table reproduces cell for cell. Send 1 carves PR arm — five of six cells match; the one divergence points at the port. Applying the change to And your protocol clarifies what this PR actually buys on your workload: on base, reaching that state set took the full three-send staircase — the "one extra cold pass before anything is reusable" you priced. On the branch, send 1 alone publishes every boundary: a second user (not a third send) already hits. The discriminating end-to-end number on your rig is "hits on request 2", base vs branch, for a fresh prefix — no staircase required. Thank you for the falsification pressure — the three-send subtlety is now part of the model because you measured it first. Disclosure: AI-assisted analysis (Claude Code); I reviewed the reconstruction and arithmetic myself. |
|
Hypothesis 1 is ruled out — the stop does recur per chunk in the port. Journal timestamps from a Send 1 carves So your discriminating number is already in the data: hits on request 2 are 0 on both arms, base The verbatim run on a #52789-inclusive build stands; sibling A at 3 400 shared remains the cell to |
|
Agreed on the narrowing, and your journal moves it further than you claim: with the carve proven correct, I have to downgrade my own hypothesis 2 rather than lean on it. I tried to reproduce your request-2 zero on One sharpening from re-reading both traces: your base request-2 zero needs no deferral story at all — base send 1 leaves states at {4,800, 6,400}, both above request 2's drop-capped reach of 3,200, so 0 is the correct output of ordinary mechanics (and send 3 hits 3,200 because send 2's carve published it). The genuine anomaly is exactly one cell: branch arm, request 2 — states carved at every boundary, none reachable. On the harness that cell is 3,200; on your rig it is 0. A named candidate at the right layer, though — the filing side, not the carving side. On If you have appetite for one more probe before the verbatim run, this one separates "publication lagged" from "publication never happens" on your runtime: parent sent once (branch arm), then sibling B (5,000 shared) immediately — no repeats. Harness says 3,200. If your rig says 0, then prefill-time boundary states are never being published under live MTP on that runtime — every hit you've ever measured came from later requests' carves — and that would be a live-engine publication bug independent of this PR (its benefit would then be gated on that bug's fix, which is worth knowing before merge, and worth filing regardless). The verbatim #52789-build run remains the settle-everything test; sibling A at 3,400 stays the watched cell there, and this parent×1 probe would tell us in advance what to expect from it. Disclosure: AI-assisted analysis (Claude Code); I ran the reconstructions and reviewed the traces myself. |
|
Your candidate is ruled out, and it flips the direction: Branch arm, send 1. The filings land on every boundary for both groups, and the Mamba manager So it is not "publication never happens" — it is published and not findable. Your separation One lead, not a result: my counter says all four blocks carry Disclosure: AI-assisted analysis (Claude Code); I ran the reconstructions and reviewed the traces myself. |
|
Found what gates it here, and it is not a defect in this PR — it is a default.
That is why the carve is provably right here and the hits do not move: this PR creates a state at Measured, production code, no PR applied, only the interval changed:
So the default costs one cold pass on unaligned prompts, and it caps what any store-side change can Disclosure: AI-assisted analysis (Claude Code); I ran the reconstructions and reviewed the traces myself. |
`prefix_cache_retention_interval` defaults to 0, which retains only semantic
checkpoints: on a model with sliding-window or Mamba groups, every other
boundary state is filed and then never hashed, so it cannot serve a hit. The
prefix-cache hit-rate metric still reports non-zero, so the effect is invisible
from outside.
Nothing said so. The value is not logged anywhere in the tree, and the only
related message is the deprecation warning that fires when the env var is set --
you are told once you have changed it, never while the default is costing you.
The neighbouring derived default is already announced ("Mamba cache mode is set
to 'align' ... by default when prefix caching is enabled"), and the validator
here already inspects exactly the model shape needed: it raises a detailed error
for the harmless case, a value set where it has no effect, and returns silently
for the harmful one. This adds the missing half.
Logs once at startup, only when prefix caching is on and the model actually has
a sparse group, and names the knob that changes it.
Reported in vllm-project#53595; found while measuring vllm-project#53479, whose store-side states are
discarded by this default on a stock install.
Signed-off-by: Jürgen Schmied <mail@juergenschmied.de>
Assisted-by: Claude Opus 5 (Claude Code)
…PR #53479 Read-only prep for porting vllm-project/vllm#53479 (Mamba align partial- prefix-hit fix) onto frontier-pastnative-20260816. Two docs: - f1-partial-prefix-port-hunk-drift-notes.md: the PR changed substantially since docs/f1-partial-prefix-hits-research.md was written (2026-08-24) -- scope grew from 1 file/2 hunks to 3 files (kv_cache_coordinator.py, scheduler.py, single_type_kv_cache_manager.py) with new eagle_reach_margin/ retention-aware-stops machinery. Also corrects a stale claim in the F-1 plan digest: the feat-retention-interval prerequisite (upstream #45845, dense default) has ALREADY landed on this branch (commit 283936f / merge 04dd3f7), just under different hashes than originally cited, almost certainly due to the intervening v0.1.17 rebase. Plan-digest risk #2 (sequencing/inert-without-retention-interval) is resolved on this branch. - f1-partial-prefix-port-correspondence.md: file:line mapping of every upstream hunk (current diff, not the stale research-doc description) to our tree, with adaptation proposals for the senior agent to evaluate -- none applied to vllm/ source. Flags the classmethod-vs-instance-method mismatch in reachable_block_mask, the missing enable_partial_hash_hits/ supports_fine_grained_hash_lookup concepts behind eagle_reach_margin, and which pre-existing upstream stops (tail_boundary, shared_prefix_boundary) are out of scope for this fix on our tree. No vllm/ source touched. Analysis only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
This pull request has merge conflicts that must be resolved before it can be |
|
Status update: I moved this PR back to draft because newer work has split The focused rewrite will build on #54076's Mamba state-grid correction and Attribution correction: three standalone test files in the current revision The remaining production change is scheduler-only behavior: periodic AI assistance from Claude Code and OpenAI Codex was used in the investigation |
|
@kamb-code our issue #54094 also relies on your fix, @rufftruffles tested your change and derived that it did fix for mamba but not for the SWA, so I will work on SWA fix meanwhile wait for yours to merge. |
|
@kamb-code Do you know timeline to land this, or I was thinking to cherry pick your commits for my fix issue #54094 . What do you think ? Any suggetions. |
|
Thanks for checking. I don’t have a reliable landing date yet, and I would not cherry-pick the current #53479 head—it is the superseded branch described in my status update, not the intended focused patch. #54713 merged today and changed the reachable replay-boundary retention path used by the cache managers, including SlidingWindowManager. Since @rufftruffles’s September 7 run predates that merge, I think the cheapest next step is to rerun #54094 on current main before either of us adds more code. It may address the remaining SWA=0 result, but I would not claim that until it is measured. #54076 is still pending. Once that settles, I’ll refresh #53479 as the narrow current-main Mamba retention-cadence change. If current main still reproduces the SWA miss, we can coordinate on the minimal remaining SWA fix rather than carrying forward the old stack. AI-assisted analysis was used in preparing this response; I checked the current branches and relevant cache paths before posting. |
Important — superseded draft and attribution correction
This PR is back in draft. Its current branch is superseded and should not be
reviewed as the intended final change.
Three standalone test files currently in this branch are byte-identical to
files first published by @akshaver in #52371, but this branch does not
preserve that commit attribution. They have been removed from my local
rewrite, and the final revision will explicitly credit #52371 as prior test
coverage. I have also removed unrelated offloading changes from the rewrite;
that work remains scoped to my #52771.
I am rebuilding this as a narrow scheduler follow-up to #54076 and #54713. I
will update this body and branch only after #54076 and #54713 merge; if
either closes unmerged, I will reassess. The focused change will then be
reverified against current
main.AI assistance from Claude Code and OpenAI Codex was used in the
investigation and rewrite; I reviewed and verified this correction.
Purpose
Two coupled defects in
_mamba_block_aligned_split(#52897) leave hybrid-model prefix caching mostly inert outside of exact-repeat traffic:num_tokens, above thenum_tokens - 1lookup cap.last_cache_position -= block_sizeunderuse_eaglewas sized for 16-token attention blocks; align blocks are 544–2,128 tokens, so the whole speculative family (eagle/eagle3/mtp/dflash/dspark) gives up one entire block of reusable prefix. Measured on GB10 production hardware by @jschmied ([Bug]: Align-mode prefix caching never hits (0 / 996k queries) with --scheduling-policy priority on hybrid GDN model (post-#51113) #52897): half the reusable prefix on aligned prompts, one extra cold pass, ~9× warm prefill (combined speculative/checkpoint path).Fix: a chunk stops at every block boundary whose state retention will hash, so a reusable state materializes wherever a lookup can find one; with states at those boundaries, a lookup whose last block is pruned falls back one block instead of missing, which is what made the back-off necessary — so it is removed. When
mamba_has_prefill_checkpoint_blocksapplies (#52789), mid-block states are recoverable and deep chunks are kept (no extra steps on that path).Retention coupling (found in review by @jschmied).
prefix_cache_retention_intervaldefaults to 0 since #52216 (Aug 17):MambaManager.reachable_block_maskthen hashes only the replay boundary and shared-prefix junctions, so on a default install (a) unconditional boundary stops would split the prefill for states that are discarded, and (b) the one state that is kept — the replay boundary,num_prompt_tokens - 1— sits one attention block beyond what an EAGLE/MTP lookup can reach (the lookup drops its last matched block), so an identical prompt only hit once a junction formed, on its third send. This PR therefore:None, or an interval at/below the block size), the next segment boundary under a positive interval, only the kept boundaries under 0 — a default install pays no extra chunk splits;eagle_reach_margin(the same rule its lookup already applies — one hash block under fine-grained partial hits, otherwise one group block),MambaManageradds that boundary to the retained set, and the split ends a chunk there so the state exists.Measured on the CPU scheduler+manager harness at retention 0 (
main@8d6b1832, @jschmied's 3-send identical-prompt protocol, 1,600-token align blocks; first hit on send N, amount in parentheses):Every dense-retention cell is unchanged by the retention work. Dense-retention results (harness
main@185cada36-era, every cell n=2; full matrix and per-group attribution in #52897): sibling geometries go from {0, 0, 1600-capped} to {1600, 1600, 3200}; the aligned-prompt zero becomes 3,200 (spec on) / 4,800 (off). GPU end-to-end on an A100 against thevllm==0.27.1release wheel (hybrid GDN, engine-forced 544-token align blocks; the wheel predates #52216, so these are dense-retention measurements): a sibling sharing 700 tokens goes from +0 to +544 cached tokens, deep siblings unchanged; worst-case latency cost measured at +33 ms per extra boundary step on a 0.8B--enforce-eagersetup (per-step overhead dominated; low single-digit % on production-scale prefills).Relationship to prior art (and why this is not a duplicate)
method == "mtp"only, and intentionally keeps the back-off for exactly-aligned prompts. This PR removes the back-off unconditionally and makes that safe via states at the reachable boundaries; no flag.num_tokens - 1cap mechanics first (Aug 14), adding a replay-landing stop. @jschmied measured it not moving his numbers on GB10; the retention-aware stops here subsume the landing stop (the replay boundary is always a chunk end).prefix_cache_retention_intervalto an argument and change the default to 0 #52216 made 0 the retention default; this PR does not change that default, it makes the store side consistent with it.Test Plan
tests/v1/core/test_mamba_align_chunk_split.py, 7 new regressions: dense stops without checkpoints; the last boundary stays reachable underuse_eagle; manager-level state placement at every boundary; retention-aware stops at the default interval (aligned and unaligned prompts: only the eagle-reachable and replay boundaries are chunk ends), at a positive segment interval, and under dense retention; and an end-to-end manager test in align geometry (attention block = mamba block, as the engine forces) that at retention 0 with EAGLE the pool keeps exactly the replay-boundary and eagle-reachable states and an identical second request hits 3 blocks — with a negative control that zeroes the margin and reproduces the old behaviour (one state, zero hit). All fail on unpatchedmain(the retention tests need scheduler and coordinator attributesmaindoes not have; the negative control is what shows the manager test discriminating).test_mamba_align_split_partial_tail_schedule[1|4]moves to the one-block-per-step staircase (docstring updated);test_hybrid_cache_mamba_align_shared_prefix_detection's junction stop is subsumed; the split stubs in those files gain the two new scheduler attributes with dense defaults. The checkpoint-path ([Perf] Support internal prefill checkpoints for Mamba prefix caching, 9%~25% TTFT improvement #52789) tests pass unchanged.tests/v1/core/+tests/v1/kv_connector/unit/offloading_connector/on this network-restricted CPU box: 681 passed, 127 failed — every failure classified by signature and all pre-existing on this box: 76KVCacheTensor.__init__() ... 'shared_by'and 48ModelConfigvalidation errors (offline model inspection) — the same counts and signatures as the unmodified tree in the earlier run — 3 engine-core boots, and 2assert 0 == 16inTestMambaHybridOffloadServingre-verified to fail identically with this PR's production files reverted (the [Bugfix] OffloadingConnector: stop zeroing offload hits under MTP/EAGLE spec decode #52771 defect). No failure attributable to this change.AI assistance disclosure
Developed with AI assistance (Claude Code). I reviewed every changed line and all results myself; the failure modes were measured on live serving (A100, 0.27.1 wheel) before the fix was written, independently confirmed on GB10 hardware by @jschmied in #52897, and the retention-interval coupling was found by @jschmied while validating this PR.