Repository navigation
Replies: 1 comment
Update: Over-Admission Is the Root Cause, Not Recompute-Mode PreemptionFurther investigation reveals the starvation is not inherent to recompute-mode preemption — it is caused by over-admission. The scheduler admits requests based on their prefill block cost but does not account for their eventual decode block cost. This is identical in both vLLM v1 and BLIS. The Mechanism
With Experimental ProofWe ran four configurations — varying spike vs sustained load and max-running-reqs:
Key finding: With The 300-request sustained case completes 161/300 in 120s at 1.34 req/s — this is the correct capacity planning answer (the system is overloaded, ~139 requests do not finish within the horizon). The 50-request spike completes all 50 in ~43s. vLLM Has the Same ProblemvLLM v1 has the same over-admission pattern:
In real vLLM deployments, this works because:
What BLIS Could Do That vLLM Does NotThese are potential BLIS enhancements that could upstream to vLLM: 1. Auto-compute When the user provides vLLM cannot easily do this because it does not know the output length in advance (it depends on the model generation). BLIS has the advantage of knowing the workload spec upfront. 2. Projected-capacity admission check Before admitting a request from the wait queue in Phase 2, estimate its total block cost at completion and check whether the running batch projected total exceeds capacity: This is a speculative check (actual output length may vary), but for BLIS where output lengths are pre-specified, it would be exact. For vLLM, it could use 3. Preemption-rate monitoring with admission backpressure Track a rolling preemption rate. When it exceeds a threshold (e.g., >1 preemption per step for 10 consecutive steps), temporarily reduce
This is the most "production-ready" mitigation because it does not require knowing output lengths in advance and could apply directly to vLLM. Updated Comparison Table
Revised QuestionsThe original discussion framed this as a recompute-vs-swap problem. The real framing is admission control:
|
Uh oh!
There was an error while loading. Please reload this page.
Context
While investigating the Phase 1 livelock bug (#349, fixed in #519), we discovered a second, deeper problem: under sustained KV overload, recompute-mode preemption causes complete starvation — no request ever completes because every request is preempted before finishing decode, loses all progress, and restarts from scratch.
This is not a bug — it is a faithful reproduction of real vLLM v1 behavior. Both systems exhibit identical starvation under the same conditions. This discussion explores the mechanism, validates BLIS fidelity, and considers potential mitigations.
The Reproducer
Result: 0 completed requests, 9,599 preemptions over 120s. Each request needs ~237 KV blocks at peak; 7,463 total blocks support ~31 concurrent. At rate=10/s, 300 requests arrive in 30s — a 6.5x overload on sustained throughput capacity (~1.55 completions/s).
BLIS vs vLLM v1: Side-by-Side Comparison
We traced the vLLM v1 scheduler (
vllm/v1/core/sched/scheduler.py) to verify that BLIS matches. Every relevant mechanism is identical:num_computed_tokens = 0, all KV blocks freedProgressIndex = 0, all KV blocks freedself.running.pop()— youngest request (LIFO from tail)RunningBatch.Requests[len-1]— youngest request (tail)self.waiting.prepend_request(request)— front of queueWaitQ.PrependFront(request)— front of queueif not preempted_reqs:— waiting queue skipped entirely!result.PreemptionHappened— waiting queue skipped entirelynum_preemptionstracked for metrics only, never used for scheduling priorityblock_hash,get_computed_blocks()finds them on re-scheduleGetCachedBlocks()checks hash table on re-admissionConclusion: BLIS preemption physics is faithful to vLLM v1. The starvation is not a BLIS-specific problem — it is an inherent limitation of recompute-mode preemption under sustained overload.
Why Starvation Occurs
ProgressIndex = 0— all decode progress (potentially thousands of tokens) is discarded.The fundamental problem: each completion requires ~3,400 uninterrupted decode steps (~20s). But under 6.5x overload, no request can hold its KV blocks long enough to finish decode before being evicted.
Potential Mitigations
These are options to explore, not proposals. Each has tradeoffs:
1. Swap-mode preemption (CPU offload)
vLLM v0 supported
PreemptionMode.SWAP— offload KV blocks to CPU memory, preserving progress. BLIS already hasTieredKVCachewith CPU offload infrastructure.Pro: Preempted requests preserve progress.
Con: CPU-to-GPU transfer latency. Under severe overload, swap space also fills up. vLLM v1 deliberately dropped swap for simplicity.
2. Anti-starvation priority boost
Track
num_preemptionsper request. After N preemptions, boost scheduling priority to prevent re-eviction.Pro: Simple. Guarantees forward progress.
Con: Boosted requests block new admissions indefinitely under severe overload.
3. Admission backpressure
When preemption rate exceeds a threshold, reject new requests or reduce admission rate.
Pro: Addresses root cause (more work than capacity). Matches real-world load shedding.
Con: Requires admission policy integration.
4. Progress-aware eviction
Instead of LIFO (youngest), evict the request with the least decode progress.
Pro: Requests close to completion are protected. Reduces wasted computation.
Con: Inverts fairness — newer requests are always evicted first.
5. Partial progress preservation (without swap)
On preemption, keep
ProgressIndexand rely on prefix cache to reconstruct KV blocks on re-admission. Block hashes survive preemption in both vLLM and BLIS.Pro: Zero CPU memory cost. Leverages existing prefix cache.
Con: Under severe pressure, freed blocks are immediately reallocated — prefix cache salvage is unlikely.
Related Issues
Questions for Discussion
Is starvation under 6.5x overload a scenario users care about? If BLIS is used for capacity planning, "0 completions at this rate" is the correct answer — scale up.
Should BLIS match vLLM v1 exactly? Or should it explore mitigations as a research/what-if tool?
Would swap-mode preemption leverage the existing tiered KV cache?
TieredKVCachealready has CPU-tier infrastructure.Is progress-aware eviction worth a hypothesis experiment? Test whether "evict least progress" beats "evict youngest" under sustained KV pressure.
All reactions