Skip to content

[Bugfix][HiSparse] Adopt GPU prefix copies after the hit's allocation - #59274

Closed
MatthewBonanni wants to merge 1 commit into
vllm-project:mainfrom
MatthewBonanni:hisparse-copy-adoption
Closed

MatthewBonanni wants to merge 1 commit into
vllm-project:mainfrom
MatthewBonanni:hisparse-copy-adoption

Conversation

@MatthewBonanni

Copy link
Copy Markdown
Member

Purpose

Fix an engine crash (Cannot get N free blocks from the pool) on a HiSparse host-prefix hit under GPU memory pressure. This is an alternative to #57457.

A host-prefix hit re-pins free GPU copies of its pages so the prefix comes back GPU-resident. Admission counts those copies as free blocks, but adoption pinned them before the hit's own allocation (hot region and new pages), which could then run the pool dry.

#57457 fixes this by charging the pins at admission. That mixes host and GPU accounting in HiSparseSourceManager.get_num_blocks_to_allocate, and under pressure it defers a request that could run by reading its prefix from host, just to keep an optimization.

Changes

  • Adopt after allocation. commit_computed_blocks records the pages to adopt, and update_residency (in cache_blocks, after allocate_new_blocks) adopts the copies that survived. The allocation always gets what admission counted, so no admission accounting is needed. A copy the allocation reuses is dropped by its reuse watcher and never adopted.
  • Copies are evicted last. BlockPool.unpin_blocks documents unpinned blocks as last-resort eviction candidates, but blocks freed afterwards were appended behind them, so an allocation evicted a prefix's copies before blocks nobody would reuse. FreeKVCacheBlockQueue now keeps a last-resort segment at its tail that later appends stay in front of, and unpin_blocks uses it.
  • Tail first. HiSparse releases a prefix's pages tail first, matching free_blocks' convention, so pressure trims a prefix from its end.

Replaying #57457's scenario (a resumed 3-page host prefix hit, free_blocks left in the pool):

free_blocks main #57457 this PR
5–6 rejected rejected rejected
7 crash rejected admitted, 0/3 copies
8 crash rejected admitted, 1/3
9 crash rejected admitted, 2/3
10+ 3/3 3/3 3/3

Test Plan

  • test_hisparse_prefix_hit_under_pressure_adopts_surviving_copies[7, 9, 10]: exact adopted pages, and no block shared between adopted copies and fresh allocations. 7 fails without the adoption timing, 9 without tail-first release, and 10 without the last-resort segment.
  • test_free_kv_cache_block_queue_last_resort_stays_behind: later appends stay ahead of the segment after its first block is removed or popped.
  • tests/v1/core/test_prefix_caching.py and tests/v1/core/test_kv_cache_utils.py, with CpuPlatform selected:
python cpu_pytest.py --confcutdir=tests/v1/core tests/v1/core/test_prefix_caching.py tests/v1/core/test_kv_cache_utils.py

Test Result

  • New tests fail on main (3 of 4) and pass with this PR; each case was also checked against the partial fixes above.
  • 297 passed. 8 errors are fixture 'caplog_vllm' not found, from running outside the top-level conftest, and are identical on main.

No GPU or model run: the change is scheduler-side block bookkeeping.

AI assistance (Claude Code) was used for the investigation, implementation, tests, and this description.

🤖 Generated with Claude Code

A HiSparse host-prefix hit re-pins free GPU copies of its pages. Admission
counts those copies as free blocks, but adoption pinned them before the
hit's own allocation, which could then run the pool dry and crash the engine
with "Cannot get N free blocks from the pool".

Adopt the copies after the allocation instead, from update_residency, so
the allocation always gets the blocks admission counted. To keep the copies
the allocation does not need, unpinned blocks now form a true last-resort
segment at the tail of the free queue, behind every later-freed block, and
HiSparse releases a prefix's pages tail first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Matthew Bonanni <mbonanni@redhat.com>
@mergify mergify Bot added bug Something isn't working kv-cache-manager labels Sep 29, 2026
@MatthewBonanni

Copy link
Copy Markdown
Member Author

Superseded by #59282 (stacked with the optional #59283), which carries this fix from a vllm-project branch so the follow-up can stack on it.

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

Labels

bug Something isn't working kv-cache-manager

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant