Summary
In P/D disaggregation mode, in the non-prefix-caching handoff path, when a request finishes prefill, it is transferred to a decode scheduler through:
Router.transfer_prefill_request() -> Scheduler.add_decode()
The decode side then immediately allocates the request's prefilled KV state on the selected decode worker's NPU memory. If the selected decode worker does not have enough free NPU
memory, MemoryModel.allocate(..., Device.NPU) raises a RuntimeError, causing the simulator to abort.
This seems to happen before the handoff path verifies whether the selected decode worker can actually admit the request.
Observed behavior
The relevant path appears to be:
In the non-prefix-caching path, the code appears to be:
def add_decode(self, req):
req.instance_id = self.instance_id
self.request.append(req)
...
kv_size = self.memory.get_total_kv(req)
self.memory.allocate(kv_size, Device.NPU)
MemoryModel.allocate() then raises when the requested size exceeds available NPU memory:
if self.npu_used + size > self.npu_mem:
raise RuntimeError(...)
As a result, the current behavior is:
- a request finishes prefill
- a decode worker is selected
- the full prefilled KV is allocated immediately on that decode worker
- if the selected decode worker does not have enough free NPU memory, the simulator aborts
Reproduction conditions
This behavior should be reproducible under a P/D configuration where:
- the prefill completion rate exceeds the decode side's ability to admit or drain requests
- decode workers are configured with relatively limited available NPU memory
- the workload includes sufficiently long prompts, resulting in large prefilled KV states during handoff
Under these conditions, once a prefilled request is transferred to a decode worker without enough free NPU memory, the simulator aborts in MemoryModel.allocate().
Question
I would like to clarify whether this behavior is expected in the current simulator design.
Specifically, should decode-side memory exhaustion during P/D handoff be treated as a fatal simulation error, or should it be considered a missing admission-control / backpressure mechanism in the P/D handoff path?
I am asking because decode-side memory pressure seems like a natural condition in memory-constrained P/D disaggregation experiments. If the simulator terminates immediately in this case, it becomes difficult to study handoff queuing, decode-side congestion, or memory-aware decode scheduling.
If this is a known limitation rather than intended behavior, would future support for a recoverable P/D handoff path be within the project scope, such as decode-side admission checks, retrying another decode worker, or delaying the handoff until decode memory becomes available?
Summary
In P/D disaggregation mode, in the non-prefix-caching handoff path, when a request finishes prefill, it is transferred to a decode scheduler through:
Router.transfer_prefill_request() -> Scheduler.add_decode()The decode side then immediately allocates the request's prefilled KV state on the selected decode worker's NPU memory. If the selected decode worker does not have enough free NPU
memory,
MemoryModel.allocate(..., Device.NPU)raises aRuntimeError, causing the simulator to abort.This seems to happen before the handoff path verifies whether the selected decode worker can actually admit the request.
Observed behavior
The relevant path appears to be:
serving/__main__.pyrouter.transfer_prefill_request(finished_reqs)serving/core/router.pytransfer_prefill_request()selects a decode scheduler and callssched.add_decode(req)serving/core/scheduler.pyadd_decode()appends the request to the decode queueserving/core/memory_model.pyallocate(..., Device.NPU)raises if the NPU memory is insufficientIn the non-prefix-caching path, the code appears to be:
MemoryModel.allocate()then raises when the requested size exceeds available NPU memory:As a result, the current behavior is:
Reproduction conditions
This behavior should be reproducible under a P/D configuration where:
Under these conditions, once a prefilled request is transferred to a decode worker without enough free NPU memory, the simulator aborts in
MemoryModel.allocate().Question
I would like to clarify whether this behavior is expected in the current simulator design.
Specifically, should decode-side memory exhaustion during P/D handoff be treated as a fatal simulation error, or should it be considered a missing admission-control / backpressure mechanism in the P/D handoff path?
I am asking because decode-side memory pressure seems like a natural condition in memory-constrained P/D disaggregation experiments. If the simulator terminates immediately in this case, it becomes difficult to study handoff queuing, decode-side congestion, or memory-aware decode scheduling.
If this is a known limitation rather than intended behavior, would future support for a recoverable P/D handoff path be within the project scope, such as decode-side admission checks, retrying another decode worker, or delaying the handoff until decode memory becomes available?