Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/adding_models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,25 @@ methods are:
starting early on a thread of the submodule's own; it must not touch the device. The
DiT scaffold draws a request's seeded noise here (``PREFETCH_SEEDS``).

``get_stop_policies(self, graph_walk) -> dict[str, StopPolicy] | None`` (optional)
Declare what ``check_stop`` amounts to on a walk, per loop it can stop, when it is
only the common checks; the graph runtime then runs them over the step's token column
without calling ``check_stop``. That takes the batched output carrying the policies'
``token_signal`` as a stop buffer (``BatchedModelOutput(check_stop_buffers={...})``,
as Qwen3.5 and Orpheus return); a step without one, or one that mixes walks,
still calls ``check_stop``. ``StopPolicy(StopKind.AR, token_signal=...,
eos_tokens=..., sampler=...)`` stops its loop on an EOS token (unless the ``sampler``
resource's request config sets ``ignore_eos``) or when the loop's iteration count plus
one reaches ``max_iters`` (``info.max_tokens`` unless given). ``StopKind.ITER`` checks
only the count, and ``StopKind.EOS`` only the token, for a loop whose cap is its budget.
The limits are computed from the request's forward-pass info whenever
the worker receives it, not per step. Return ``{}`` for a
walk on which ``check_stop`` never stops a loop, and ``None`` (the default) to keep
calling ``check_stop``. The policies must agree with ``check_stop`` for every row;
``test/modular/test_stop_policies.py`` checks the models that declare them. A
``TokenStop`` with ``runtime_check=True`` declares them for you: its loop's stop ids,
as ``StopKind.EOS``, on ``walk``; its ``prefill_walks`` keep ``check_stop``.

``cleanup_request(self, request_id)`` (optional)
Free per-request state held inside the submodule when a request finishes: buffers,
per-request caches, counters. See Qwen3-Omni's ``Code2WavSubmodule`` for an example.
Expand Down
17 changes: 17 additions & 0 deletions mstar/engine/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
NodeSubmodule,
StepOrder,
StopCheck,
StopPolicy,
)
from mstar.platforms.compile import with_inductor_overrides
from mstar.profile.worker import ExecTimings
Expand Down Expand Up @@ -1138,6 +1139,15 @@ def after_output_copy(self, batch: ExecutingBatch) -> None:
if batch.committed is not None:
self._runner.after_output_copy(batch.committed)

def step_finished(
self, batch: ExecutingBatch, outputs: dict[str, NameToTensorList],
host_rows: HostRows | None = None,
) -> None:
"""A step's outputs are on the host (the stop check's copy) and its
stops not yet decided: so a request ending here has its state up to
date, e.g. its pages indexed for prefix reuse."""
self.extend_prefix_chains(batch, outputs, host_rows=host_rows)

def extend_prefix_chains(
self, batch: ExecutingBatch, outputs: dict[str, NameToTensorList],
host_rows: HostRows | None = None,
Expand Down Expand Up @@ -1902,6 +1912,13 @@ def exec_and_postprocess(
laps.lap("tail")
return outputs

def get_stop_policies(self, node_name: str, graph_walk: str) -> dict[str, StopPolicy] | None:
"""The node's declared stop policies on ``graph_walk``
(``NodeSubmodule.get_stop_policies``); None when ``check_stop``
decides, or the node has no submodule here."""
mgmt = self._submodules.get(node_name)
return None if mgmt is None else mgmt.submodule.get_stop_policies(graph_walk)

def check_stop_for_batch(
self, batch: ExecutingBatch, outputs: dict[str, NameToTensorList],
host_rows: HostRows | None = None,
Expand Down
Loading
Loading