metrale_scheduler/effect.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-25: [`Effect`], the device-side bookkeeping the core asks a router for
4//! between steps, and [`EffectOutcome`], the router's answer. Generic over the
5//! sequence state `S` and the logits handle `P`.
6//!
7//! Owner: scheduler.
8//! Invariants: none beyond the types.
9
10use crate::plan::Label;
11
12pub enum Effect<'a, S, P> {
13 /// 2026-09-25: Release a sequence's device resources: optionally offer its KV to the
14 /// prefix cache, free it, then tell the EP worker.
15 ReleaseSeq {
16 seq: &'a mut S,
17 cache: bool,
18 /// 2026-09-25: The caller's label, for the failure log lines.
19 what: &'static str,
20 },
21 /// 2026-09-25: Migrate a live sequence onto slot `target`.
22 CompactSlot {
23 seq: &'a mut S,
24 target: usize,
25 },
26 /// 2026-09-25: Disown a sequence's slot after it was migrated to another
27 /// sequence, so a later free or drop cannot release it twice.
28 DetachSlot {
29 seq: &'a mut S,
30 },
31 /// 2026-09-25: Stream a sequence's device state into `writer` (spill).
32 SaveSequenceState {
33 seq: &'a S,
34 writer: &'a mut dyn std::io::Write,
35 },
36 /// 2026-09-25: Copy the logits block `logits` (`rows` rows) to the host.
37 ReadLogits {
38 logits: P,
39 rows: usize,
40 into: &'a mut Vec<u8>,
41 },
42 /// 2026-09-25: Block-aligned Marconi SSM checkpoint after a decode step.
43 MarconiCheckpoint {
44 seq: &'a mut S,
45 },
46 SsmSnapshotSave {
47 seq: &'a S,
48 slot: usize,
49 },
50 SsmSnapshotRestore {
51 seq: &'a S,
52 slot: usize,
53 },
54 /// 2026-09-25: `save_hidden_for_catchup(row, pos)`: copy row `row`'s hidden into the
55 /// MTP catch-up ring at label `pos`.
56 SaveHiddenCatchup {
57 row: usize,
58 pos: usize,
59 },
60 /// 2026-09-25: Make the default stream wait for the secondary stream.
61 SyncSecondary,
62 /// 2026-09-25: Every worker slot down.
63 EpShutdown,
64 /// 2026-09-25: Synchronise `stream` before teardown.
65 Quiesce {
66 stream: u64,
67 },
68 /// 2026-09-25: Make sure the KV block for the sequence's next decode position exists
69 /// before a step is launched ahead of the host; answers `Reserved` with
70 /// the blocks it added (0 when the block was already there) or
71 /// `Exhausted` when the allocation fails.
72 ReserveKv {
73 seq: &'a mut S,
74 },
75 /// 2026-09-25: The over-run of a fed step was discarded for this sequence: release
76 /// the blocks the latest `ReserveKv` added for it. Only a router that
77 /// reserves ahead supports it; the synchronous router returns an error.
78 Rollback {
79 seq: &'a mut S,
80 },
81}
82
83impl<S, P> Label for Effect<'_, S, P> {
84 fn label(&self) -> String {
85 match self {
86 Self::ReleaseSeq { cache, what, .. } => format!("ReleaseSeq{{cache={cache}, {what}}}"),
87 Self::CompactSlot { target, .. } => format!("CompactSlot{{target={target}}}"),
88 Self::DetachSlot { .. } => "DetachSlot".into(),
89 Self::SaveSequenceState { .. } => "SaveSequenceState".into(),
90 Self::ReadLogits { rows, .. } => format!("ReadLogits{{rows={rows}}}"),
91 Self::MarconiCheckpoint { .. } => "MarconiCheckpoint".into(),
92 Self::SsmSnapshotSave { slot, .. } => format!("SsmSnapshotSave{{slot={slot}}}"),
93 Self::SsmSnapshotRestore { slot, .. } => format!("SsmSnapshotRestore{{slot={slot}}}"),
94 Self::SaveHiddenCatchup { row, pos } => {
95 format!("SaveHiddenCatchup{{row={row}, pos={pos}}}")
96 }
97 Self::SyncSecondary => "SyncSecondary".into(),
98 Self::EpShutdown => "EpShutdown".into(),
99 Self::Quiesce { stream } => format!("Quiesce{{stream={stream}}}"),
100 Self::ReserveKv { .. } => "ReserveKv".into(),
101 Self::Rollback { .. } => "Rollback".into(),
102 }
103 }
104}
105
106#[derive(Debug, PartialEq, Eq)]
107pub enum EffectOutcome {
108 Unit,
109 /// 2026-09-25: `ReadLogits`: the element width the model writes.
110 HostLogits {
111 elem_bytes: usize,
112 },
113 /// 2026-09-25: `ReserveKv`: the blocks added for the next position.
114 Reserved {
115 blocks: usize,
116 },
117 /// 2026-09-25: `ReserveKv`: no block could be added; the core does not launch ahead.
118 Exhausted,
119}