Skip to main content

aisimulate_core/engine/generalized/
contracts.rs

1// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::num::NonZeroU32;
5
6use anyhow::Result;
7
8/// Stable identity of one logical mock engine.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub struct EngineIdentity {
11    /// Stable logical worker ID.
12    pub worker_id: u64,
13}
14
15impl EngineIdentity {
16    /// Construct an engine identity from its stable worker ID.
17    pub const fn new(worker_id: u64) -> Self {
18        Self { worker_id }
19    }
20
21    /// Return the identity of one attention-DP rank.
22    pub const fn rank(self, dp_rank: u32, dp_size: NonZeroU32) -> RankIdentity {
23        RankIdentity {
24            worker_id: self.worker_id,
25            dp_rank,
26            dp_size,
27        }
28    }
29}
30
31/// Stable identity of one scheduler core within a logical engine.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33pub struct RankIdentity {
34    /// Stable logical worker ID shared by sibling ranks.
35    pub worker_id: u64,
36    /// Zero-based attention-DP rank.
37    pub dp_rank: u32,
38    /// Total ranks in this logical engine's attention-DP group.
39    pub dp_size: NonZeroU32,
40}
41
42/// Construction parameters for a generalized engine.
43#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct GeneralizedEngineConfig<C> {
45    /// Number of scheduler cores in the attention-DP group.
46    pub dp_size: NonZeroU32,
47    /// Configuration cloned into each rank core.
48    pub rank: C,
49}
50
51impl<C> GeneralizedEngineConfig<C> {
52    /// Construct a single-rank engine configuration.
53    pub const fn single_rank(rank: C) -> Self {
54        Self {
55            dp_size: NonZeroU32::MIN,
56            rank,
57        }
58    }
59
60    /// Construct an attention-DP engine configuration.
61    pub const fn attention_dp(dp_size: NonZeroU32, rank: C) -> Self {
62        Self { dp_size, rank }
63    }
64}
65
66/// Context supplied while a rank applies a scheduler command.
67#[derive(Debug, Clone, Copy, PartialEq)]
68pub struct CommandContext {
69    /// Driver clock at which the command becomes visible.
70    pub now_ms: f64,
71    /// Whether this logical engine has a committed pass awaiting completion.
72    ///
73    /// This is group-wide. It is `true` for an otherwise idle sibling rank
74    /// while another rank is executing, preserving the attention-DP barrier.
75    pub pass_in_flight: bool,
76}
77
78impl CommandContext {
79    /// Whether a command may immediately admit work into the current pass.
80    pub const fn allow_immediate_admission(self) -> bool {
81        !self.pass_in_flight
82    }
83}
84
85/// A command addressed to one attention-DP rank.
86#[derive(Debug, Clone, PartialEq, Eq)]
87pub struct SchedulerCommand<C> {
88    /// Target attention-DP rank.
89    pub dp_rank: u32,
90    /// Rank-engine-specific, runtime-neutral command payload.
91    pub command: C,
92}
93
94impl<C> SchedulerCommand<C> {
95    /// Address a command to a rank.
96    pub const fn new(dp_rank: u32, command: C) -> Self {
97        Self { dp_rank, command }
98    }
99}
100
101/// Effects produced by one rank.
102#[derive(Debug, Clone, PartialEq, Eq)]
103pub struct RankEffects<T> {
104    /// Rank that produced the effects.
105    pub dp_rank: u32,
106    /// Rank-engine-specific effects.
107    pub effects: T,
108}
109
110/// Effects produced by zero or more ranks of a logical engine.
111#[derive(Debug, Clone, PartialEq, Eq)]
112pub struct EngineEffects<T> {
113    /// Effects in stable DP-rank order.
114    pub by_rank: Vec<RankEffects<T>>,
115}
116
117impl<T> EngineEffects<T> {
118    fn empty() -> Self {
119        Self {
120            by_rank: Vec::new(),
121        }
122    }
123
124    pub(crate) fn one(dp_rank: u32, effects: T) -> Self {
125        Self {
126            by_rank: vec![RankEffects { dp_rank, effects }],
127        }
128    }
129
130    /// Return `true` when no rank produced effects.
131    pub fn is_empty(&self) -> bool {
132        self.by_rank.is_empty()
133    }
134
135    /// Consume the wrapper and return effects in stable DP-rank order.
136    pub fn into_by_rank(self) -> Vec<RankEffects<T>> {
137        self.by_rank
138    }
139}
140
141impl<T> Default for EngineEffects<T> {
142    fn default() -> Self {
143        Self::empty()
144    }
145}
146
147/// Opaque ID of a committed logical-engine pass.
148#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
149pub struct PassId(pub(crate) u64);
150
151impl PassId {
152    /// Return the monotonically increasing per-engine sequence number.
153    pub const fn get(self) -> u64 {
154        self.0
155    }
156}
157
158/// Rank-local status for a bounded same-timestamp scheduler retry.
159///
160/// This is a driver hint, not an observable effect or ordinary progress.
161/// Drivers evaluate it only after an effect-free, zero-duration pass.
162#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
163pub enum SameTimestampRetry {
164    /// This rank has no internal same-timestamp convergence protocol.
165    #[default]
166    NotApplicable,
167    /// Internal scheduler state changed and another pass may expose work.
168    Retry,
169    /// The rank's internal state no longer changes at this timestamp.
170    Exhausted,
171}
172
173/// Eager execution result returned by a rank core.
174///
175/// `start_effects` may become visible immediately. `pending` is retained by
176/// the generalized engine and handed back to the rank only at the shared
177/// completion boundary.
178#[derive(Debug)]
179pub struct RankPass<S, P> {
180    /// Modeled completion time for this rank.
181    pub end_ms: f64,
182    /// Rank-local bounded retry status.
183    pub same_timestamp_retry: SameTimestampRetry,
184    /// Effects visible at pass start.
185    pub start_effects: S,
186    /// Rank-private state needed to finish the pass.
187    pub pending: P,
188}
189
190/// Pass-start effects from one rank.
191#[derive(Debug, Clone, PartialEq)]
192pub struct RankPassStarted<T> {
193    /// Rank that executed work.
194    pub dp_rank: u32,
195    /// This rank's modeled completion time before group alignment.
196    pub rank_end_ms: f64,
197    /// Effects visible at pass start.
198    pub effects: T,
199}
200
201/// A logical pass committed by
202/// [`GeneralizedMockerEngine::execute_pass`](super::GeneralizedMockerEngine::execute_pass).
203#[derive(Debug, Clone, PartialEq)]
204pub struct EnginePassStarted<T> {
205    /// ID supplied later to
206    /// [`GeneralizedMockerEngine::complete_pass`](super::GeneralizedMockerEngine::complete_pass).
207    pub pass_id: PassId,
208    /// Driver time at which the pass was committed.
209    pub started_at_ms: f64,
210    /// Shared completion boundary, equal to the slowest executed rank.
211    pub end_ms: f64,
212    /// Total sibling ranks held by the barrier, including idle ranks.
213    pub participating_ranks: NonZeroU32,
214    /// Grouped retry status at [`Self::started_at_ms`]. A retry request from
215    /// any executed rank takes precedence over an exhausted sibling.
216    pub same_timestamp_retry: SameTimestampRetry,
217    /// Start effects from ranks that had work, in stable rank order.
218    pub by_rank: Vec<RankPassStarted<T>>,
219}
220
221/// A logical pass released at its shared completion boundary.
222#[derive(Debug, Clone, PartialEq)]
223pub struct EnginePassCompleted<T> {
224    /// ID of the completed pass.
225    pub pass_id: PassId,
226    /// Completion effects from executed ranks and idle siblings that released
227    /// deferred work at the shared group boundary.
228    pub effects: EngineEffects<T>,
229}
230
231/// One scheduler/KV/timing core.
232///
233/// Implementations own all single-rank scheduler state. The generalized layer
234/// owns attention-DP grouping and never inspects the command/effect payloads.
235///
236/// `execute_pass` eagerly commits a non-preemptive batch. Implementations must
237/// not expose pass-end effects until `complete_pass` receives the retained
238/// `PendingPass`.
239pub trait RankEngine: Sized {
240    /// Rank construction configuration.
241    type Config;
242    /// Scheduler command payload.
243    type Command;
244    /// Effects of applying one command.
245    type CommandEffects;
246    /// Effects visible when a pass starts.
247    type PassStartEffects;
248    /// Opaque state retained between pass start and completion.
249    type PendingPass;
250    /// Effects visible when a pass completes.
251    type PassCompletionEffects;
252    /// Effects produced by deadline-driven internal work.
253    type InternalEffects;
254
255    /// Construct one rank core.
256    fn new(identity: RankIdentity, config: &Self::Config) -> Result<Self>;
257
258    /// Apply one scheduler command.
259    ///
260    /// `pending_pass` is the eagerly committed pass for this rank, when this
261    /// rank participated in the logical engine's current in-flight pass.
262    /// Commands such as cancellation may mutate it to suppress effects that
263    /// were computed at pass start but must no longer become visible at pass
264    /// completion. A logical attention-DP pass can be in flight while this is
265    /// `None` when only sibling ranks participated; use
266    /// [`CommandContext::pass_in_flight`] for the group-wide state.
267    ///
268    /// This operation must be error-atomic: returning `Err` must leave both
269    /// the rank and `pending_pass` unchanged. Command errors are recoverable
270    /// at the generalized boundary because a command targets only one rank;
271    /// use a successful command effect to represent any committed mutation.
272    fn apply_command_effects(
273        &mut self,
274        command: Self::Command,
275        context: CommandContext,
276        pending_pass: Option<&mut Self::PendingPass>,
277    ) -> Result<Self::CommandEffects>;
278
279    /// Whether this rank can commit a pass.
280    fn is_ready(&self) -> bool;
281
282    /// Whether a ready rank is blocked only on externally commanded state.
283    ///
284    /// This is narrower than having queued work. Implementations return true
285    /// only when a later command can release retained ownership that prevents
286    /// the ready work from advancing. Drivers use this signal to avoid
287    /// repeatedly executing an effect-free, zero-duration pass while keeping
288    /// genuine scheduler livelocks visible.
289    fn waiting_for_external_command(&self) -> bool {
290        false
291    }
292
293    /// Eagerly commit one non-preemptive pass.
294    fn execute_pass(
295        &mut self,
296        now_ms: f64,
297    ) -> Result<RankPass<Self::PassStartEffects, Self::PendingPass>>;
298
299    /// Release the effects of a previously committed pass.
300    fn complete_pass(
301        &mut self,
302        pending: Self::PendingPass,
303        end_ms: f64,
304    ) -> Result<Self::PassCompletionEffects>;
305
306    /// Cross the shared completion boundary without a rank-local pass.
307    ///
308    /// Attention-DP ranks that had no work when a sibling pass started still
309    /// participate in the group barrier. Implementations may use this hook to
310    /// release effects deferred while [`CommandContext::pass_in_flight`] was
311    /// true. `end_ms` is the modeled shared group boundary (the maximum rank
312    /// end), even when a wall-clock driver calls `complete_pass` later.
313    /// Returning `None` means the idle rank has no boundary effects.
314    fn complete_idle_group_pass(
315        &mut self,
316        _started_at_ms: f64,
317        _end_ms: f64,
318    ) -> Result<Option<Self::PassCompletionEffects>> {
319        Ok(None)
320    }
321
322    /// Earliest deadline for independently modeled internal work.
323    ///
324    /// The generalized engine masks this deadline while a grouped pass is in
325    /// flight. A physical deadline that falls inside a model step becomes
326    /// scheduler-visible only when that shared pass completes.
327    fn next_internal_deadline_ms(&self) -> Option<f64>;
328
329    /// Process internal work due at `now_ms`.
330    ///
331    /// Callers may invoke this method defensively with `pass_in_flight=true`;
332    /// implementations must return without mutating rank state in that case.
333    fn process_internal_work(
334        &mut self,
335        now_ms: f64,
336        pass_in_flight: bool,
337    ) -> Result<Self::InternalEffects>;
338
339    /// Whether this rank owns no request, pass, or internal work.
340    fn is_drained(&self) -> bool;
341}