You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Concurrent kvcached instances on the same physical GPU need cross-process admission for physical KV growth.
#418 makes VMM allocation and mapping failures transactional, and #453 converts physical-capacity exhaustion into a scheduling miss. Those changes are necessary, but they do not arbitrate capacity between processes. Under sustained colocated pressure, both instances can observe the same free-memory snapshot, admit overlapping growth, and race in cuMemCreate().
This is no longer only a code-review concern. We can reproduce the race reliably with two TP=4 serving instances under high concurrency. Without cross-process admission, the CUDA driver rejects physical-page allocations with OOM. Transactional rollback prevents a fatal process abort, but repeated OOM attempts become allocation misses, request failures, and severe asymmetry.
A similar race was discussed as a possibility in #221, but that report stopped reproducing after its TP socket collision was fixed. The reproduction here uses separated instance IPC and current transaction handling, so it is a distinct remaining problem.
Evidence
Transactional rollback without cross-process admission
Two high-pressure rounds were run against two colocated instances:
Round
Instance A
Instance B
1
411 succeeded, 0 failed
55 succeeded, 356 failed
2
115 succeeded, 296 failed
411 succeeded, 0 failed
The two instances logged 1,932 and 2,552 raw CUDA physical-page OOM failures respectively. There was no process restart or fatal CUDA error because the failures were rolled back, but request-level correctness and fairness were not acceptable.
holds the lock across the complete physical-growth mapping transaction.
Its focused reproducer changes the uncontrolled race into one successful growth and one recoverable capacity_exhausted result, with both processes exiting normally.
Among the designs tested so far, this remains the strongest correctness boundary and the best current candidate. It makes the capacity decision and the corresponding physical growth one transaction. However, its cost concern is valid: file-lock acquisition, device selection, memory query, and a relatively broad critical section are added to successful growth.
2. Smaller per-page transactions and fairness retries
A version that reduced growth to one page per transaction and retried misses removed raw CUDA OOM and completed all requests, but produced stable starvation:
Metric
Baseline
Candidate
Aggregate effective throughput
3,246 tok/s
1,574-1,600 tok/s
Change
-
-50.7% to -51.5%
Slow-side median TTFT
about 3 s
about 70 s
Mutual exclusion alone did not provide fair admission. One process repeatedly reacquired capacity while the other accumulated retries.
3. Worker-owned all-TP headroom admission
We also evaluated worker-owned admission where each physical growth queried all TP workers and rejected the batch if any rank lacked headroom. It avoided OOM and permanent hangs, and both instances completed 390/390 requests, but it moved a distributed control round trip into the allocation hot path:
Metric
Change
Elapsed time
+40%
Output throughput
-28.5%
Mean TTFT
+63%
Headroom rejections
2,182 / 2,176
Allocation misses
1,102 / 1,096
Removing that hot-path admission restored average throughput to within about 1.4% in the same workload, which isolates the regression to the admission path rather than VMM rollback itself. More detail is available in #416.
4. No admission, rely only on the CUDA driver and rollback
This has the lowest uncontended overhead, but the first result above shows that it is not sufficient under sustained colocated pressure. The CUDA driver is a final atomic gate, not a fair or efficient cross-process allocator.
Current conclusion
#418 and #453 remain required, but they do not replace cross-process capacity admission.
All alternatives tested after the original #455 shape either:
allow repeated physical allocation OOM and request failures;
introduce a distributed slow path on every growth attempt; or
avoid OOM at the cost of severe starvation and roughly 50% aggregate throughput loss.
For that reason, #455 has been reopened as a draft. Its original transaction boundary is currently the best candidate among the tested designs, but it should not merge until its uncontended cost and fairness under sustained contention are addressed.
A promising refinement is to keep a process-shared transaction boundary while shortening the critical section around physical capacity reservation, rather than holding it across Python IPC, TP response waits, or synchronization. That needs an explicit ownership model for reserved bytes or handles so the lock cannot be released before the capacity decision becomes real.
Design questions
Can physical handles be reserved under a short process-shared lock, then mapped outside the lock without reopening the TOCTOU race?
Should admission use bounded chunks or tickets to prevent one instance from repeatedly acquiring all newly available capacity?
What is the right cross-container coordination primitive and deployment contract?
How should admission expose contention, wait time, failed reservations, and fairness without placing worker RPC in the allocation hot path?
Can the uncontended path remain close to the current rollback-only baseline while preserving a coherent capacity snapshot?
Acceptance criteria
A replacement for the current draft should demonstrate all of the following with at least two colocated instances:
no raw physical-page OOM during expected capacity contention;
no process abort, illegal memory access, or partial VMM state;
Summary
Concurrent kvcached instances on the same physical GPU need cross-process admission for physical KV growth.
#418 makes VMM allocation and mapping failures transactional, and #453 converts physical-capacity exhaustion into a scheduling miss. Those changes are necessary, but they do not arbitrate capacity between processes. Under sustained colocated pressure, both instances can observe the same free-memory snapshot, admit overlapping growth, and race in
cuMemCreate().This is no longer only a code-review concern. We can reproduce the race reliably with two TP=4 serving instances under high concurrency. Without cross-process admission, the CUDA driver rejects physical-page allocations with OOM. Transactional rollback prevents a fatal process abort, but repeated OOM attempts become allocation misses, request failures, and severe asymmetry.
A similar race was discussed as a possibility in #221, but that report stopped reproducing after its TP socket collision was fixed. The reproduction here uses separated instance IPC and current transaction handling, so it is a distinct remaining problem.
Evidence
Transactional rollback without cross-process admission
Two high-pressure rounds were run against two colocated instances:
The two instances logged 1,932 and 2,552 raw CUDA physical-page OOM failures respectively. There was no process restart or fatal CUDA error because the failures were rolled back, but request-level correctness and fairness were not acceptable.
This is the gap between rollback and admission:
cuMemCreate();Admission designs evaluated
1. Full physical-growth transaction lock (#455)
The original #455 design:
mem_get_infowhile holding the lock;Its focused reproducer changes the uncontrolled race into one successful growth and one recoverable
capacity_exhaustedresult, with both processes exiting normally.Among the designs tested so far, this remains the strongest correctness boundary and the best current candidate. It makes the capacity decision and the corresponding physical growth one transaction. However, its cost concern is valid: file-lock acquisition, device selection, memory query, and a relatively broad critical section are added to successful growth.
2. Smaller per-page transactions and fairness retries
A version that reduced growth to one page per transaction and retried misses removed raw CUDA OOM and completed all requests, but produced stable starvation:
Mutual exclusion alone did not provide fair admission. One process repeatedly reacquired capacity while the other accumulated retries.
3. Worker-owned all-TP headroom admission
We also evaluated worker-owned admission where each physical growth queried all TP workers and rejected the batch if any rank lacked headroom. It avoided OOM and permanent hangs, and both instances completed 390/390 requests, but it moved a distributed control round trip into the allocation hot path:
Removing that hot-path admission restored average throughput to within about 1.4% in the same workload, which isolates the regression to the admission path rather than VMM rollback itself. More detail is available in #416.
4. No admission, rely only on the CUDA driver and rollback
This has the lowest uncontended overhead, but the first result above shows that it is not sufficient under sustained colocated pressure. The CUDA driver is a final atomic gate, not a fair or efficient cross-process allocator.
Current conclusion
#418 and #453 remain required, but they do not replace cross-process capacity admission.
All alternatives tested after the original #455 shape either:
For that reason, #455 has been reopened as a draft. Its original transaction boundary is currently the best candidate among the tested designs, but it should not merge until its uncontended cost and fairness under sustained contention are addressed.
A promising refinement is to keep a process-shared transaction boundary while shortening the critical section around physical capacity reservation, rather than holding it across Python IPC, TP response waits, or synchronization. That needs an explicit ownership model for reserved bytes or handles so the lock cannot be released before the capacity decision becomes real.
Design questions
Acceptance criteria
A replacement for the current draft should demonstrate all of the following with at least two colocated instances: