Skip to main content

Module residency

Module residency 

Source
Expand description

Residency analysis + eviction for the pipelined executor.

Ported from fuel-graph-router::{residency_planner, residency_eviction} (executor-unification Session 6, 2026-06-11). The legacy shape was a GraphMutatingSchedulerRule that emitted a three-node Op::Copy{Cpu} + Op::Release + Op::Copy{device} chain for the legacy GraphExecutor<Router>; the pipelined port emits the fused two-node form — Op::Move{Cpu} + reload Op::Copy{device} — making this pass the first production emitter of WorkItemKind::Move (shipped b93bdb82).

§The two halves

  • Analysis — ResidencyPlanner::analyze walks a graph’s topo order, tracks each node’s live range (first use → last consumer), and computes the peak working-set size. Pure; no graph mutation.
  • Transform — insert_residency_evictions consumes the analysis and, while the peak exceeds a byte budget, inserts Op::Move{Cpu} + reload Op::Copy{device} chains around the highest-scoring candidates (bytes × inactive_gap). The derive_ordering half of execution_plan (run inside both pipelined realize paths) pins each Move after every non-destructive reader of its source, and the executor’s destructive_input cleanup frees the device storage when the Move runs.

§Const-pool byte budget (deferred — planner program)

The legacy executor’s with_const_pool_limit LRU was the only other larger-than-VRAM mechanism, and it retired with the legacy executor. Per the 2026-06-11 re-audit (gap 7), the replacement is NOT an executor-side LRU: weight residency under a byte budget is a planning decision, and it folds into the load-time incremental planner’s residency program (docs/session-prompts/ load-time-incremental-planner.md) — the planner prices evict/reload chains with Stage 1 TransferCalibration data and emits the same Op::Move/Op::Copy primitives this module does. This module is that program’s substrate, not its policy.

§Known limitations (follow-up work, inherited from the port)

  • Only one eviction per candidate (the largest gap). Multiple gaps would need multiple evict chains.
  • Greedy selection; no cost-awareness for the CPU↔device transfer overhead vs the VRAM savings (the planner program adds pricing).
  • No integration with the VulkanBackend::evict mmap-tiering path — that’s a transparent runtime mechanism, distinct from graph-level planning.

Structs§

EvictReload
One evict/reload chain emitted by insert_residency_evictions. move_node is the Op::Move { target: Cpu } (destructive stage- to-host); reload is the Op::Copy { target: src_device } the post-gap consumers were rewired to.
LiveRange
One tensor’s residency span. [first_use, last_use] are op positions in a topo order (inclusive — the tensor is live during both). bytes is the output storage size. inactive_gap is the longest stretch of ops between consecutive reads where the tensor is resident but not accessed — a strong signal for eviction viability.
ResidencyPlanner
Analysis-only residency planner. Computes live ranges and peak bytes for a graph, emits a ResidencyReport. Does not mutate the graph. Takes &Graph — the caller holds whatever lock it already has; no hidden lock acquisition.
ResidencyReport
Structured report on a graph’s residency profile.

Functions§

insert_residency_evictions
Graph-mutating eviction pass: while the graph’s peak residency exceeds budget_bytes, pick the top candidate (by bytes × inactive_gap) that has a realizable inactive gap and insert an Op::Move{Cpu} + reload Op::Copy{device} chain around it (via fuel_graph::opt::insert_evict_reload).