a busy model is waited for and then evicted, with no exception
Measured on zeiss 2026-11-01: eviction freed 12.2 GB of the 18.0 GB needed and
stopped 1.5 GB short -- "held by a busy model or another process" -- and
Z-Image-Turbo loaded with CPU/disk offload. The room it needed was not
unavailable. It was in use, by a request that was about to finish.
Waiting for a model to go idle and then taking its VRAM was already the house
rule for the active model and the keep-resident set. Ordinary LRU models were
the exception: pass 1 printed "is busy serving a request — not evicting it" and
moved on. Three deadlines elsewhere were the same exception in a different
dress, because a deadline here does not avert a hang -- it converts "this load
waits a few seconds" into "this load runs on the CPU for its whole life", with
nothing in the log to say why.
So every pass now waits:
idle LRU evict (first: it costs nothing)
busy LRU wait, then evict was "not evicting it"
active model wait, then evict was 120s, else leave loaded
keep-resident wait, then evict was 120s, else leave loaded
_evict_one wait, then evict was 120s, else "Skipping eviction"
and the give-up branches are deleted rather than left as dead code describing
an exception that no longer exists. _wait_until_idle defaults to no deadline.
The busy ones are a SECOND sweep rather than inline waits, so a cheap idle
eviction further down the LRU order never queues behind a wait that may turn
out to be unnecessary.
Two things keep an unbounded wait from being a hang, and both already held: the
pass never waits on `protect` -- the key the room is being made FOR, the one
model that provably cannot go idle because it is blocked on the memory being
freed -- and a model unloaded under us ends the wait. The wait also repeats
itself every 15 s, so a genuinely hung generation is legible AS a hung
generation instead of as an eviction that stopped responding.
Two waits stay bounded, deliberately, and are now asserted as such so neither
drifts back by accident:
* unload_model, an operator action with a caller waiting on an answer, where
"not unloaded" is a perfectly good answer. Eviction has no such option.
* the host-RAM evictor, untouched. Waiting there risks the kernel's OOM killer
taking the whole engine -- four times in five hours the night that code was
written. Different resource, different failure mode, separate decision.
test_the_source_never_waits_on_the_protected_model read src[i:i+6000] and
failed because this function grew past it, while the guarantee it protects was
intact; it is now bounded by the next method, like the other source tests here.
Co-Authored-By:
Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014T3rZozi1Ehk96NG1WesgC
Showing
This diff is collapsed.
Please
register
or
sign in
to comment