Load plan: which part of each checkpoint tensor this rank needs, and where
in live memory those bytes go.
plan_loads traces the model's load_weights once (bake.py) on
the real tensors, between start_reload and finish_reload so that it
sees the layout direct mode actually restored (the NCCL engine does it at its
first target update), and reduces each traced copy_ to a box of the
checkpoint tensor and a strided region of the target's storage
(geometry.py). A name is
direct only if every byte it writes is a copy of one incoming byte; anything
else is a fallback, which the engine sends in full through load_weights.
The plan holds for every later update of the same model.
load_planned loads full checkpoint tensors through get_dest; the NCCL
engine uses it. get_boxes (with get_dest) is for engines that send or
read only the slices a rank needs (sharded RDT, NCCL M2N follow-ups).
Classes:
Functions:
-
check_plannable
–
Refuse a configuration no load plan supports: a reload mode other than
-
load_planned
–
Load full checkpoint tensors as plan says: copy each direct name's
-
plan_loads
–
Trace model.load_weights over the declared checkpoint tensors once
LoadPlan
dataclass
Methods:
-
get_boxes
–
Parts of the checkpoint tensor this rank needs; None: nothing.
-
get_dest
–
(part of a box, live tensor) pairs: copying each part, reshaped to
Source code in vllm/model_executor/model_loader/reload/plan.py
| @dataclass(frozen=True)
class LoadPlan:
entries: dict[str, Entry] # per declared name, in metadata order
dests: dict[str, Dest] # live tensors built at plan_loads; not data
def get_boxes(self, name: str) -> tuple[Box, ...] | None:
"""Parts of the checkpoint tensor this rank needs; ``None``: nothing.
For engines that send or read only those slices (sharded RDT, NCCL
M2N follow-ups); an engine that receives full tensors calls
``load_planned`` instead."""
return self.entries[name].boxes
def get_dest(self, name: str) -> list[tuple[Box, torch.Tensor]] | None:
"""(part of a box, live tensor) pairs: copying each part, reshaped to
its tensor's shape, into that tensor is exactly what the loader would
have written. ``None``: fallback, send the full tensor through
``load_weights``. Write only between ``start_reload`` and
``finish_reload``; never read.
``load_planned`` copies full tensors through it; an engine that sends
only ``get_boxes`` copies its slices the same way."""
if self.entries[name].writes is None:
return None
return list(self.dests[name])
|
get_boxes(name)
Parts of the checkpoint tensor this rank needs; None: nothing.
For engines that send or read only those slices (sharded RDT, NCCL
M2N follow-ups); an engine that receives full tensors calls
load_planned instead.
Source code in vllm/model_executor/model_loader/reload/plan.py
| def get_boxes(self, name: str) -> tuple[Box, ...] | None:
"""Parts of the checkpoint tensor this rank needs; ``None``: nothing.
For engines that send or read only those slices (sharded RDT, NCCL
M2N follow-ups); an engine that receives full tensors calls
``load_planned`` instead."""
return self.entries[name].boxes
|
get_dest(name)
(part of a box, live tensor) pairs: copying each part, reshaped to
its tensor's shape, into that tensor is exactly what the loader would
have written. None: fallback, send the full tensor through
load_weights. Write only between start_reload and
finish_reload; never read.
load_planned copies full tensors through it; an engine that sends
only get_boxes copies its slices the same way.
Source code in vllm/model_executor/model_loader/reload/plan.py
| def get_dest(self, name: str) -> list[tuple[Box, torch.Tensor]] | None:
"""(part of a box, live tensor) pairs: copying each part, reshaped to
its tensor's shape, into that tensor is exactly what the loader would
have written. ``None``: fallback, send the full tensor through
``load_weights``. Write only between ``start_reload`` and
``finish_reload``; never read.
``load_planned`` copies full tensors through it; an engine that sends
only ``get_boxes`` copies its slices the same way."""
if self.entries[name].writes is None:
return None
return list(self.dests[name])
|
_dest(targets, write, dtype)
The live tensor of write, in the checkpoint dtype.
Source code in vllm/model_executor/model_loader/reload/plan.py
| def _dest(targets: Targets, write: Write, dtype: torch.dtype) -> torch.Tensor:
"""The live tensor of ``write``, in the checkpoint dtype."""
target = targets.by_name[(write.module, write.tensor)]
r = write.dst
offset = target.byte_offset // dtype.itemsize + r.offset
storage = target.real.untyped_storage()
return storage_view(storage, offset, r.shape, r.stride, dtype)
|
_nbytes(entry)
What the engine moves for entry on this rank.
Source code in vllm/model_executor/model_loader/reload/plan.py
| def _nbytes(entry: Entry) -> int:
"""What the engine moves for ``entry`` on this rank."""
if entry.writes is None:
return prod(entry.shape) * entry.dtype.itemsize
boxes = entry.boxes or ()
return sum(prod(b - a for a, b in box) for box in boxes) * entry.dtype.itemsize
|
_overlaps(traced, targets)
Names whose writes share a byte with another write: direct writes land
in any order, so these go through load_weights in arrival order.
Source code in vllm/model_executor/model_loader/reload/plan.py
| def _overlaps(traced: Traced, targets: Targets) -> dict[str, str]:
"""Names whose writes share a byte with another write: direct writes land
in any order, so these go through ``load_weights`` in arrival order."""
runs: dict[int, list[tuple[int, int, str]]] = defaultdict(list)
for name, copies in traced.copies.items():
for c in copies:
if c.storage in targets.by_storage and 0 not in c.shape:
spans = byte_runs(c.byte_offset, c.shape, c.stride, c.dtype.itemsize)
runs[c.storage] += [(a, b, name) for a, b in spans]
reasons: dict[str, str] = {}
for named in runs.values():
named.sort()
active: list[tuple[int, str]] = [] # heap of (stop, name)
for start, stop, name in named:
while active and active[0][0] <= start:
heapq.heappop(active)
for _, other in active:
reasons.setdefault(name, f"writes overlap with {other!r}")
reasons.setdefault(other, f"writes overlap with {name!r}")
heapq.heappush(active, (stop, name))
return reasons
|
_report(plan, seconds)
Every name at debug; fallbacks grouped by reason and a summary at info.
Source code in vllm/model_executor/model_loader/reload/plan.py
| def _report(plan: LoadPlan, seconds: float) -> None:
"""Every name at debug; fallbacks grouped by reason and a summary at info."""
counts: dict[str, list[int]] = defaultdict(lambda: [0, 0]) # kind: [n, bytes]
fallbacks: dict[str, list[str]] = defaultdict(list)
for e in plan.entries.values():
kind = "fallback" if e.writes is None else "direct" if e.boxes else "unneeded"
nbytes = _nbytes(e)
counts[kind][0] += 1
counts[kind][1] += nbytes
if e.reason is not None:
fallbacks[e.reason].append(e.name)
suffix = f": {e.reason}" if e.reason else ""
logger.debug("load plan: %s %s (%d bytes)%s", kind, e.name, nbytes, suffix)
for reason, names in fallbacks.items():
logger.info(
"load plan: %d fallback names, e.g. %s: %s", len(names), names[:3], reason
)
logger.info(
"load plan: %d names: %d direct (%.1f MiB), %d fallback (%.1f MiB), "
"%d not needed on this rank; traced in %.2f s",
len(plan.entries),
counts["direct"][0],
counts["direct"][1] / (1 << 20),
counts["fallback"][0],
counts["fallback"][1] / (1 << 20),
counts["unneeded"][0],
seconds,
)
|
_write(copy, shape, dtype, targets)
copy as a box and region; None if it copies nothing.
Raises:
-
Fallback
–
it is not a plain copy of checkpoint bytes.
Source code in vllm/model_executor/model_loader/reload/plan.py
| def _write(
copy: Copy, shape: tuple[int, ...], dtype: torch.dtype, targets: Targets
) -> Write | None:
"""``copy`` as a box and region; ``None`` if it copies nothing.
Raises:
Fallback: it is not a plain copy of checkpoint bytes.
"""
src = copy.src
if src._geom is None:
raise Fallback(src._lost or "not a view of the checkpoint tensor")
if src.dtype != copy.dtype:
raise Fallback(
f"casts {src.dtype} to {copy.dtype} at copy_ "
f"(send it as {copy.dtype} to make it direct)"
)
target = targets.by_storage.get(copy.storage)
if target is None:
raise Fallback("copies into a tensor that is not a checkpoint tensor")
size = dtype.itemsize
rel = copy.byte_offset - target.byte_offset
if rel % size or target.byte_offset % size:
raise Fallback("copies into a destination viewed with another element size")
if 0 in copy.shape:
return None
geom = src._geom
if tuple(geom.shape) != copy.shape:
if geom.numel() != prod(copy.shape):
raise Fallback("broadcasting copy_")
try:
geom = geom.view(copy.shape)
except RuntimeError:
raise Fallback("copy_ with a reshape that is not a view") from None
dims = list(zip(copy.shape, geom.stride(), copy.stride))
box, dst_shape, dst_stride = box_and_region(shape, geom.storage_offset(), dims)
return Write(
box, target.module, target.tensor, Region(rel // size, dst_shape, dst_stride)
)
|
check_plannable(model)
Refuse a configuration no load plan supports: a reload mode other than
direct, and EPLB. Reads only configuration, so an engine can call it
before start_reload changes the model. Direct reload's own refusals
run in begin_direct_reload.
Raises:
Source code in vllm/model_executor/model_loader/reload/plan.py
| def check_plannable(model: torch.nn.Module) -> None:
"""Refuse a configuration no load plan supports: a reload mode other than
direct, and EPLB. Reads only configuration, so an engine can call it
before ``start_reload`` changes the model. Direct reload's own refusals
run in ``begin_direct_reload``.
Raises:
RuntimeError: the configuration cannot be planned.
"""
if not direct_reload_enabled():
raise RuntimeError("load plan: requires VLLM_RELOAD_MODE=direct")
for name, module in model.named_modules():
moe_config = getattr(module, "moe_config", None)
parallel = getattr(moe_config, "moe_parallel_config", None)
if getattr(parallel, "enable_eplb", False):
raise RuntimeError(f"load plan: EPLB is not supported ({name})")
|
load_planned(model, plan, weights)
Load full checkpoint tensors as plan says: copy each direct name's
boxes into its destinations, skip names this rank needs nothing of, and
pass fallbacks to model.load_weights. Call between start_reload
and finish_reload.
Source code in vllm/model_executor/model_loader/reload/plan.py
| def load_planned(
model: torch.nn.Module,
plan: LoadPlan,
weights: Iterable[tuple[str, torch.Tensor]],
) -> None:
"""Load full checkpoint tensors as ``plan`` says: copy each direct name's
boxes into its destinations, skip names this rank needs nothing of, and
pass fallbacks to ``model.load_weights``. Call between ``start_reload``
and ``finish_reload``."""
fallbacks = []
for name, full in weights:
dest = plan.get_dest(name)
if dest is None:
fallbacks.append((name, full))
for box, tensor in dest or ():
part = full[tuple(slice(start, stop) for start, stop in box)]
tensor.copy_(part.reshape(tensor.shape))
if fallbacks:
model.load_weights(fallbacks)
|
plan_loads(model, metadata)
Trace model.load_weights over the declared checkpoint tensors once
and return where each lands on this rank.
Call between start_reload and finish_reload: the plan traces
the real tensors in the layout begin_direct_reload applied. Incoming
tensors are data-free traces, so nothing is loaded. Loaders' constant
writes land, as on the load_weights path; so do writes into
non-checkpoint GPU tensors fed by a read of a checkpoint tensor (a
mirror), which are not restored: that name falls back and the update
rewrites them. Module, parameter and buffer state a loader sets stays,
as it would after load_weights.
Raises:
Source code in vllm/model_executor/model_loader/reload/plan.py
| def plan_loads(model: torch.nn.Module, metadata: "Iterable[ParamMeta]") -> LoadPlan:
"""Trace ``model.load_weights`` over the declared checkpoint tensors once
and return where each lands on this rank.
Call between ``start_reload`` and ``finish_reload``: the plan traces
the real tensors in the layout ``begin_direct_reload`` applied. Incoming
tensors are data-free traces, so nothing is loaded. Loaders' constant
writes land, as on the ``load_weights`` path; so do writes into
non-checkpoint GPU tensors fed by a read of a checkpoint tensor (a
mirror), which are not restored: that name falls back and the update
rewrites them. Module, parameter and buffer state a loader sets stays,
as it would after ``load_weights``.
Raises:
ValueError: a name is declared twice.
RuntimeError: the model cannot be planned.
"""
check_plannable(model)
if not direct_reload_active(model):
raise RuntimeError(
"load plan: call plan_loads between start_reload and finish_reload; "
"the plan takes its layout from what the direct reload restored"
)
metas: dict[str, ParamMeta] = {}
for meta in metadata:
if meta.name in metas:
raise ValueError(f"load plan: {meta.name!r} is declared twice")
metas[meta.name] = meta
# TODO(#54477 F2): refuse when a name of the required set (cold-start
# checkpoint names minus `is_unused_checkpoint_weight` and
# VLLM_DIRECT_RELOAD_EXCLUDE_REGEX) is missing from `metas`.
t0 = time.perf_counter()
targets = Targets(model)
traced = trace_loads(model, metas, targets)
if traced.lonely:
lonely = traced.lonely
raise RuntimeError(
f"load plan: {len(lonely)} fallback names write nothing themselves "
f"(e.g. {lonely[:3]}); their loaders combine several checkpoint "
"tensors. Move the combine into process_weights_after_loading."
)
for name, reason in _overlaps(traced, targets).items():
traced.reasons.setdefault(name, reason)
entries = {name: _entry(meta, traced, targets) for name, meta in metas.items()}
dests = {
name: tuple((w.src, _dest(targets, w, e.dtype)) for w in e.writes)
for name, e in entries.items()
if e.writes is not None
}
plan = LoadPlan(entries=entries, dests=dests)
_report(plan, time.perf_counter() - t0)
return plan
|