Repository navigation
Conversation
Signed-off-by: LyxWxj <yuxuanlou621@foxmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
Thanks @0z5a for reporting the original split-prefill livelock and providing a detailed reproduction in #137.
As the follow-up noted, the original workload drains on the newer mainline. However, a separate finite workload still reproduces a related livelock with priority preemption and WCPB: requests can be repeatedly preempted and have their unfinished prefill work rewound, even though the higher-priority request cannot obtain enough KV capacity to be admitted.
This PR addresses that preemption cycle while preserving request outputs and resource cleanup.
Bug Description
As discussion under pr #137 shows, when priority preemption is enabled and all active slots are occupied, the scheduler may suspend a lower-priority request to admit a higher-priority request. Suspending an in-flight staged-prefill request rewinds its unfinished chunk to its last fully prefilled frontier.
If the higher-priority request still cannot obtain enough KV capacity, it remains waiting. The suspended request can then resume, perform prefill work, and be preempted again before completing the chunk. Repeating this cycle can prevent a finite workload from draining even though engine.step() continues to return and execute work.
WCPB can yield between recurrence depths, so it does not guarantee that a chunk completes before the next scheduling decision. Default refill without WCPB instead runs a prefill chunk through all recurrence depths before returning to the scheduler.
The original workload reported in #137 drains on the newer mainline. This PR is motivated by a separate finite workload that reproduces a related preemption/replay cycle on the PR’s parent revision.
PR Description
For the new ten-request regression workload:
On the fixed revision, generated token IDs, exit depths, and finish reasons match a no-preemption reference; no KV blocks remain occupied after the workload drains.
The focused regression can be run with:
This is bounded CPU scheduler evidence, not a general starvation-freedom guarantee or a GPU performance claim.
Required human contributor answers
The human contributor must answer all four questions before PR submission.
An explicit answer already recorded elsewhere may be referenced with a precise,
accessible source; a bare link without an identifiable answer is insufficient.
Agents must not invent or fill in the human's answers. Blank, placeholder, or
unresolved answers do not complete this gate. See the
contributor-intent gate
and contributing guide.
1. What outcome are you trying to achieve?
Prevent a finite workload from getting stuck in a preemption/replay cycle when priority scheduling and staged prefill compete for limited KV-cache capacity.
The intended outcome is that requests can make forward progress and finish, while preserving their generated outputs and releasing their resources when the workload drains.
2. What is the highest-leverage variable for that outcome?
The number of futile priority preemptions: cases where the scheduler rewinds a running request to make room for a higher-priority request, but the latter still cannot obtain enough KV capacity to be admitted.
Repeated futile preemptions erase useful prefill progress without admitting new work. Preventing that cycle directly addresses the observed failure.
3. How will this work move that variable rather than create busywork?
Before preempting a request for a priority slot, the scheduler estimates whether the waiting request could be admitted after reclaiming eligible KV allocations. The estimate accounts for prompt growth, watermarks, shared prefixes, and resident or offloaded snapshots. If a candidate cannot make enough capacity available, the scheduler tries another eligible victim or leaves the active requests running.
Some information, such as pending prefix publication, is uncertain. If an optimistic preflight still leads to a failed admission, a fallback guard prevents the same request from repeatedly triggering priority preemption until the available budget improves.
The PR also adds regression tests that fail on the parent revision and pass with the fix, rather than relying only on a timeout or a change in scheduling statistics.
4. Who is the customer or user, and what do they actually need?
The users are operators and applications using priority scheduling with preemption and staged prefill under KV-cache pressure, including WCPB workloads.
They need finite requests to complete, not repeatedly replay the same prefill work; they also need correct outputs and KV/snapshot cleanup. This change is a scheduler-liveness fix, not a throughput optimization.
PR necessity and bugfix evidence
The reviewer’s original historical workload drains on the newer mainline, so that result alone is not evidence of an outstanding regression. A different finite, ten-request workload demonstrates that a related livelock remains possible on this PR’s parent.
Using CPU, FP32, the torch attention backend, priority scheduling, WCPB, 40 KV blocks of size 2,
max_num_seqs=4,max_num_batched_tokens=6, andprefill_chunk_size=4:The fixed run’s token IDs, exit depths, and finish reasons match a no-preemption reference. The regression also covers
mixedmode, prefix-cache accounting, restoration, and insufficient-capacity cases.Run the focused regression on the PR head with:
For the parent comparison, copy the PR’s
tests/test_prefill_livelock.pyinto the parent checkout first; that file does not exist on the parent. The selected test fails there with 3/10 requests finished and passes on the fix.The evidence is bounded CPU scheduler validation. It does not establish a general starvation-freedom guarantee, GPU serving correctness, or a performance improvement.
Test Plan
**vllm-rlt Version / Commit:**88c8f96a45690c92a8efea876173cd73487dced7
Run the targeted CPU regression suite:
The tests cover:
To reproduce the new workload against the parent revision, copy this PR’s tests/test_prefill_livelock.py into a parent checkout, then run:
Test Result
The fixed workload’s outputs match the no-preemption reference. A separate local exploratory scan of 120 bounded WCPB runs across refill/mixed and prefix-cache configurations also drained; that diagnostic script is not part of the repository.