core.inference.disaggregation.inference_state_handoff#

Engine-side lifecycle for disaggregated prefill/decode state handoff.

Module Contents#

Classes#

_PreparedHandoffMetadata

Per-request metadata assembled once for a completed prefill batch.

InferenceStateHandoffMixin

Optional KV/SSM handoff behavior composed into the dynamic engine.

Data#

API#

core.inference.disaggregation.inference_state_handoff._SSM_STATE_KINDS#

(‘conv’, ‘recurrent’)

class core.inference.disaggregation.inference_state_handoff._PreparedHandoffMetadata#

Per-request metadata assembled once for a completed prefill batch.

local_blocks: list[int]#

None

local_ssm_slot: int | None#

None

kv_meta: Any#

None

ssm_meta: Any#

None

resume_tokens: list[int]#

None

class core.inference.disaggregation.inference_state_handoff.InferenceStateHandoffMixin#

Optional KV/SSM handoff behavior composed into the dynamic engine.

_initialize_disaggregation_state() → None#

Initialize state without importing or constructing a transfer backend.

_setup_handoff_completion_tracking(
hostname: str | None = None,
) → None#

Create the CPU path used to aggregate model-parallel transfer completion.

_drain_handoff_completion_notifications() → list[tuple[int, bool]]#

Collect decisions that the existing MP schedule broadcast must distribute.

Side: decode MP coordinator; pull and push transport paths.

_record_handoff_completion_notification(
request_id: int,
failed: bool,
) → None#

Record the coordinator’s shared admission decision on every MP rank.

Side: decode engine; pull and push transport paths.

property pending_kv_import_count: int#

Number of decode requests waiting for capacity or transfer completion.

Side: decode engine; pull and push transport paths.

property has_admittable_kv_import: bool#

Whether a completed import can be handled at the next admission point.

property pending_kv_push_count: int#

Number of prefill sends waiting for transport completion.

Side: prefill engine; push transport path only.

_reset_pending_kv_imports() → None#

Drain and release pending handoff transfers before an engine reset.

schedule_waiting_requests() → None#

Reject prompt scheduling on a dedicated disaggregated decode engine.

Side: decode engine; pull and push transport paths.

setup_kv_transfer(role: str, backend: str = 'nixl') → None#

Bring up the KV transfer agents for this engine.

This method must be called collectively by every model-parallel rank in the engine because each rank participates in PP and TP metadata gathers.

Parameters:
  • role – “prefill” or “decode”; used to name the local transfer agent.

  • backend – transfer backend name, resolved through the explicit registry (“nixl”; “nccl” selects the two-sided push family).

push_handoff_kv(request_id: int, decode_metas: list) → None#

Push a pinned hand-off’s KV and live SSM state to the decode instance described by decode_metas (two-sided transports only).

The decode posted its matching receives when SUBMIT_REQUEST_WITH_KV arrived; the sends are reaped asynchronously and the pins stay until the coordinator’s RELEASE_KV.

Side: prefill engine; push transport path only.

_poll_pending_kv_pushes() → int#

Reap completed push sends; unfinished ones stay pending.

Side: prefill engine; push transport path only.

_prepare_handoff_metadata_batch(
requests_and_state: list[tuple[megatron.core.inference.inference_request.DynamicInferenceRequest, list[int], int | None]],
decode_tokens_by_request: Dict[int, list[int]],
) → dict[int, core.inference.disaggregation.inference_state_handoff._PreparedHandoffMetadata]#

Assemble metadata for all handoffs completed by one engine step.

Side: prefill engine; pull and push transport paths.

static _ssm_stage_transfer_meta(
static_metas: dict,
selected_slot: int,
) → dict#

Attach the final recurrent-state slot to one stage’s descriptors.

_capture_handoff_meta(
request: megatron.core.inference.inference_request.DynamicInferenceRequest,
prepared: core.inference.disaggregation.inference_state_handoff._PreparedHandoffMetadata | None,
) → None#

Attach prepared transfer metadata and retain the request’s blocks.

Side: prefill engine; pull and push transport paths.

release_handoff_blocks(request_id: int) → None#

Release blocks pinned by a previous do_kv_handoff completion.

Side: prefill engine; pull and push transport paths.

_release_pinned_handoff_blocks(block_ids: list) → int#

Release this request’s ownership of its pinned handoff blocks.

Side: prefill engine; pull and push transport paths.

_release_pinned_handoff_ssm_slot(ssm_slot: int | None) → None#

Release a prefill live-state slot after its handoff ownership ends.

add_request_with_kv_handoff(
request_id: int,
prompt: list,
sampling_params: megatron.core.inference.sampling_params.SamplingParams,
kv_meta: dict,
src_block_ids: list,
) → asyncio.Future[DynamicInferenceRequest]#

Start or capacity-queue a KV import and return its completion future.

Side: decode engine; pull and push transport paths. A pull backend starts the read here, while a push backend posts the matching receive.

_try_start_kv_handoff_import(
handoff: megatron.core.inference.disaggregation.pending_handoff_imports.DeferredKvHandoff,
) → bool#

Reserve cache state and start one import, or return without mutation.

Side: decode engine; pull and push transport paths.

_find_cached_handoff_prefix(
hashes: list[int],
num_blocks: int,
) → list[int]#

Find the contiguous handoff prefix already cached on decode.

Side: decode engine; pull transport path only.

_handoff_capacity_available(
num_blocks: int,
cached_blocks: list[int],
) → bool#

Check capacity in the rank-local mirror of model-parallel allocator state.

Side: decode engine; pull and push transport paths.

_drain_deferred_kv_handoffs() → int#

Start queued handoffs in FIFO order while the queue head fits.

Side: decode engine; pull and push transport paths.

static _pending_transfer_handles(
pending: megatron.core.inference.disaggregation.pending_handoff_imports.PendingKvImport,
) → list#

Return this decode import’s active KV and SSM transfer handles.

Side: decode engine; pull and push transport paths.

_validate_decode_ready_handoff(
pending: megatron.core.inference.disaggregation.pending_handoff_imports.PendingKvImport,
) → None#

Validate that transferred state can start decode without prompt execution.

_finalize_kv_handoff_import(
pending: megatron.core.inference.disaggregation.pending_handoff_imports.PendingKvImport,
) → None#

Register transferred blocks and admit the decode request.

Side: decode engine; pull and push transport paths.

_complete_handoff_request_without_forward(request_id: int) → None#

Complete an imported request whose transferred token already satisfies it.

_release_pending_kv_import(
pending: megatron.core.inference.disaggregation.pending_handoff_imports.PendingKvImport,
) → None#

Release storage owned by an unadmitted decode import.

Side: decode engine; pull and push transport paths.

static _wait_for_transfer_handles(*handles) → bool#

Wait for known handles; return false if any may still be active.

_report_completed_kv_imports() → None#

Report locally terminal imports without synchronizing the compute ranks.

Side: decode engine; pull and push transport paths.

_poll_pending_kv_imports() → int#

Progress imports without mutating the active decode batch.

Side: decode engine; pull and push transport paths.

_admit_pending_kv_imports() → int#

Handle completed imports at an engine scheduling admission point.

Side: decode engine; pull and push transport paths.

_reserve_ssm_handoff_import() → megatron.core.inference.disaggregation.pending_handoff_imports.PendingSSMImport#

Reserve the live request slot that receives exact SSM state.

_start_ssm_handoff_import(
request_id: int,
ssm_meta: dict,
pending: megatron.core.inference.disaggregation.pending_handoff_imports.PendingSSMImport,
) → None#

Post transfers into slots already reserved for one handoff.