Repository navigation
fix(server): dispatch a lone idle request without the coalesce window - #658
YeonwooSung wants to merge 6 commits into
Conversation
An idle worker dispatches a request that stays alone immediately instead of holding it for idle_coalesce_ms. A one-item arrival inside that window is still the tail of a staggered burst and coalesces, and several items already pending when a batch is selected still fuse. The idle 1ms poll is now a wake-up event that submit() sets. The staggered-burst test changed because superlinked#373 deliberately stops charging the idle window to a request that arrives alone, and a burst that is already queued still fuses. Refs superlinked#373
krisztian-gajdar
left a comment
There was a problem hiding this comment.
Thanks, the event-based wakeup looks right to me, and the tests drive the real worker and batcher without patching the clock. A few things before merge:
- Multi-item requests.
selected.pending_count == 1(model_worker.py:1147) counts pending items, not requests, becausesubmit_manyadds one entry per item. A lone request with two or more items (batch encode, a multi-document rerank, multi-item extract) still waits the full window. Could you decide "alone" per request and add a multi-item test? - Tail check.
_follows_recent_arrivalcompares against the previous submit even after that request has finished, so a sequential client sending faster than the window still waits. The timestamps are also worker-wide whilepending_countis per LoRA batcher. Please either adjust this or document it in the docstring. - Throughput. The staggered-burst test now expects
[1, 3]instead of one fused batch. #373 asks that throughput under concurrent load stays within noise, so a short before and after on one GPU (sequential queue time, plus throughput at 8 and 32 in flight) would let us accept that trade. - Small. The "instead of polling every 1 ms" comment at
model_worker.py:288-289narrates the change, and the drain tests seed_last_arrival_atdirectly. Parking them with a two-item submit would avoid reaching into private state.
|
Addressed on 8dfac7b.
Default
|
krisztian-gajdar
left a comment
There was a problem hiding this comment.
Thanks, counting distinct requests and dropping the arrival timestamps fix both points, and the new tests cover them.
Understood on the GPU. The throughput question still has to be answered before this can merge, because with the new rule a burst that is not already queued costs at least two forwards. So this will stay open until a before and after measurement on one GPU is available (sequential queue time, plus throughput at 8 and 32 in flight).
One test issue in the meantime: test_staggered_burst_shreds_without_idle_window (test_worker_core.py:713) still submits with a 5 ms stagger. Under the new rule that stagger also splits with the idle window on, so the test no longer shows what the window adds, and its docstring's "the same stagger as test_staggered_burst_fuses_with_idle_window" no longer holds since that test now uses the queued-tail pattern. Reusing the fusing test's pattern with idle_coalesce_ms=0 would make it a real contrast.
Optional: test_already_queued_burst_fuses patches the private _ensure_process_loop_started, and pending_request_count could be checked only when the worker was idle and idle_coalesce_ms > 0.
The same already-queued tail shreds when idle_coalesce_ms is 0. The GPU before/after measurement is still outstanding. Refs superlinked#373
|
The throughput hold stands. I ran
|
Summary
An idle model worker held every request for
idle_coalesce_ms(default 3ms) and then polled withasyncio.sleep(0.001). Sequential clients paid that delay on every request. The window exists so a burst that reaches an idle worker is not split into one forward per request.A request that is still alone is now dispatched immediately. One later item that arrives inside the idle window is treated as the tail of a staggered burst and still coalesces, so the first request of that burst can run alone and the rest fuse behind it. Several items already pending when a batch is selected still form one batch.
idle_coalesce_ms=0still dispatches every idle arrival immediately. The idle loop waits on an event thatsubmit()sets instead of sleeping 1ms.The default window stays 3ms. Cost-ordered batching is unchanged.
Compatibility
Scheduling latency only. A lone request on an idle worker is no longer delayed by the coalesce window. A staggered burst may use two forwards (the first alone, the rest together) instead of one fused forward.
Tests
pytest packages/sie_server/tests/core/test_worker_core.py packages/sie_server/tests/core/test_worker_drain.py— 39 passed.A unit test sets
idle_coalesce_mshigh and checks a lone request finishes well under that window. It does not assert a hard 1ms, which is flaky under the test scheduler.Refs #373
Summary by CodeRabbit