Skip to main content

aisimulate_core/engine/
protocol.rs

1// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Commands and effects exchanged with one scheduler rank.
5
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9use super::{HandoffId, HandoffTransferTiming};
10
11/// Runtime-neutral request accepted by the rank engine.
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
13pub struct Request {
14    /// Stable request identity allocated by the caller.
15    pub request_id: Uuid,
16    /// Prompt token IDs.
17    pub tokens: Vec<u32>,
18    /// Requested output length.
19    pub max_output_tokens: usize,
20    /// Optional exact output IDs. Its length overrides `max_output_tokens`.
21    #[serde(default, skip_serializing_if = "Option::is_none")]
22    pub output_token_ids: Option<Vec<u32>>,
23}
24
25/// Commands supported by the standalone scheduler.
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub enum Command {
28    /// Submit one request.
29    Submit(Request),
30    /// Submit a request whose completed prefill KV must remain source-held.
31    SubmitHandoffPrefill {
32        handoff_id: HandoffId,
33        request: Request,
34    },
35    /// Accept a decode request and reserve its destination KV footprint.
36    ReserveDestination {
37        handoff_id: HandoffId,
38        request: Request,
39    },
40    /// Make a reserved destination runnable after transfer completion.
41    ActivateDestination { handoff_id: HandoffId },
42    /// Release a successfully transferred source hold.
43    ReleaseSource { handoff_id: HandoffId },
44    /// Cancel pending or held source ownership.
45    CancelSource { handoff_id: HandoffId },
46    /// Cancel pending, reserved, or active destination ownership.
47    CancelDestination { handoff_id: HandoffId },
48    /// Cancel one request.
49    ///
50    /// A command that removes scheduler-owned state also suppresses output
51    /// retained by an in-flight pass. `discard_pending_output` additionally
52    /// requests suppression when scheduler cancellation is a no-op, which is
53    /// needed after an external driver has already retired the request.
54    CancelRequest {
55        request_id: Uuid,
56        discard_pending_output: bool,
57    },
58}
59
60/// Result of applying a scheduler command.
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum CommandResult {
63    /// A new request was accepted.
64    Submitted(Uuid),
65    /// A destination request was accepted; physical reservation may be pending.
66    DestinationAccepted { request_id: Uuid },
67    /// State or retained effects were changed.
68    Applied,
69    /// The command addressed no owned state or retained effect.
70    Noop,
71}
72
73/// Asynchronous scheduler lifecycle fact consumed by the Replayer's handoff
74/// coordinator.
75#[derive(Debug, Clone, Copy, PartialEq)]
76pub enum LifecycleEvent {
77    /// Prefill computation completed and source KV ownership is retained.
78    SourceHeld {
79        handoff_id: HandoffId,
80        request_id: Uuid,
81        transfer_timing: HandoffTransferTiming,
82    },
83    /// Decode-side physical KV capacity has been reserved.
84    DestinationReserved {
85        handoff_id: HandoffId,
86        request_id: Uuid,
87        transferable_prompt_tokens: usize,
88    },
89}
90
91/// One runtime-neutral KV block identity.
92#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
93pub struct KvBlock {
94    /// Sequence-aware block hash.
95    pub block_hash: u64,
96    /// Token-only local block hash.
97    pub tokens_hash: u64,
98    /// Token IDs retained only when explicitly configured.
99    #[serde(default, skip_serializing_if = "Option::is_none")]
100    pub token_ids: Option<Vec<u32>>,
101}
102
103/// A consecutive set of newly visible blocks.
104#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
105pub struct StoredBlocks {
106    /// Parent sequence hash immediately preceding the batch.
107    pub parent_hash: Option<u64>,
108    /// Optional absolute zero-based position of the first block.
109    ///
110    /// `None` preserves the parent-linked stream emitted by the native
111    /// schedulers; adapters must not invent an absolute position because that
112    /// changes how downstream radix indexes reconcile stores and removals.
113    #[serde(default, skip_serializing_if = "Option::is_none")]
114    pub start_position: Option<usize>,
115    /// Blocks in sequence order.
116    pub blocks: Vec<KvBlock>,
117}
118
119/// Runtime-neutral KV event payload.
120#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
121#[serde(rename_all = "snake_case")]
122pub enum KvEventData {
123    /// Blocks became prefix-cache visible.
124    Stored(StoredBlocks),
125    /// The final physical copy of these hashes was evicted.
126    Removed { block_hashes: Vec<u64> },
127}
128
129/// Ordered runtime-neutral KV event emitted by one rank.
130#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
131pub struct KvEvent {
132    /// Monotonic rank-local event sequence.
133    pub event_id: u64,
134    /// Attention-DP rank.
135    pub dp_rank: u32,
136    /// Event payload.
137    pub data: KvEventData,
138}
139
140/// First-admission provenance for prompt tokens reused across cache tiers.
141#[derive(Debug, Clone, Copy, PartialEq, Eq)]
142#[non_exhaustive]
143pub struct CacheTierAttribution {
144    /// Reused prompt tokens already resident in device KV before any H2D.
145    pub g1_reused_input_tokens: usize,
146    /// Additional reused prompt tokens restored from the native host tier.
147    pub host_reused_input_tokens: usize,
148}
149
150/// Request admission exposed at pass start.
151#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152pub struct Admission {
153    /// Admitted request.
154    pub request_id: Uuid,
155    /// Prompt tokens reused from all KV-cache tiers.
156    pub reused_input_tokens: usize,
157    /// Tier provenance captured before a host-loaded prefix becomes G1.
158    pub cache_tier_attribution: Option<CacheTierAttribution>,
159}
160
161/// Scheduler action taken to relieve KV pressure.
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
163#[serde(rename_all = "snake_case")]
164pub enum PressureKind {
165    /// vLLM evicted a running request and returned it to the waiting queue.
166    VllmPreemption,
167    /// SGLang retracted a running decode request for later readmission.
168    SglangRetraction,
169}
170
171/// Runtime-neutral scheduler and KV occupancy around one pressure action.
172#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
173pub struct PressureState {
174    /// Requests runnable before or after the action.
175    pub running_requests: usize,
176    /// Requests waiting for admission, when the scheduler exposes that count.
177    pub waiting_requests: Option<usize>,
178    /// Physically active native-G1 blocks.
179    pub active_blocks: usize,
180}
181
182/// One scheduler-owned KV pressure action emitted with pass-start effects.
183///
184/// The Replayer may attach topology/pool identity and correlate a later
185/// [`Admission`] for the same request. The engine always produces this
186/// lightweight fact; capture policy belongs to the consuming runtime.
187#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
188pub struct PressureEvent {
189    /// Modeled timestamp at which the scheduler took the action.
190    pub at_ms: f64,
191    /// Scheduler-specific pressure action.
192    pub kind: PressureKind,
193    /// Request removed from the running set.
194    pub request_id: Uuid,
195    /// Scheduler/KV state immediately before the action.
196    pub state_before: PressureState,
197    /// Scheduler/KV state immediately after the action.
198    pub state_after: PressureState,
199    /// Blocks owned by this request before it was preempted or retracted.
200    pub request_active_blocks_before: usize,
201    /// Logically available blocks used by the SGLang retraction decision.
202    pub logical_available_blocks_before: Option<usize>,
203    /// Blocks required by the SGLang retraction decision.
204    pub required_blocks_before: Option<usize>,
205}
206
207/// One client-visible output.
208#[derive(Debug, Clone, PartialEq)]
209pub struct Output {
210    /// Request producing the output.
211    pub request_id: Uuid,
212    /// Generated token, or `None` for a terminal-without-token signal.
213    pub token_id: Option<u32>,
214    /// Whether request ownership ended with this output.
215    pub completed: bool,
216    /// Whether admission rejected the request as physically impossible.
217    pub rejected: bool,
218    /// Prompt tokens served from KV cache at first admission, reported once
219    /// on the request's first output.
220    pub cached_tokens: Option<usize>,
221}
222
223/// Rank-local scheduler and G1 metrics.
224#[derive(Debug, Clone, Default, PartialEq)]
225pub struct Metrics {
226    pub dp_rank: u32,
227    /// Backend-native legacy occupied-block count. vLLM reports blocks
228    /// referenced by active requests; SGLang reports occupied page-pool blocks,
229    /// including evictable radix-resident pages.
230    pub active_blocks: u64,
231    /// Reusable resident blocks not included in `active_blocks`. This is
232    /// currently populated by vLLM; SGLang reports zero because its legacy
233    /// occupied count already includes radix-resident pages.
234    pub inactive_blocks: u64,
235    pub total_blocks: u64,
236    /// `active_blocks / total_blocks`, with backend-native semantics above.
237    pub cache_usage: f64,
238    /// Physical resident fraction. This includes inactive reusable vLLM blocks
239    /// and equals `cache_usage` for SGLang's legacy occupied-page metric.
240    pub physical_cache_usage: f64,
241    pub running_requests: u64,
242    pub waiting_requests: u64,
243    pub preemptions_total: u64,
244    /// SGLang radix-cache tokens reused by the most recently completed pass.
245    ///
246    /// Backends without an equivalent pass-local metric report zero.
247    pub sglang_cache_hit_tokens: u64,
248    /// Total SGLang prefill tokens considered by the most recently completed
249    /// pass. Backends without an equivalent pass-local metric report zero.
250    pub sglang_cache_total_tokens: u64,
251}
252
253/// Per-pass scheduling statistics.
254#[derive(Debug, Clone, Default, PartialEq)]
255pub struct ForwardPassMetrics {
256    pub num_prefill_requests: u32,
257    pub sum_prefill_tokens: u64,
258    pub var_prefill_length: f64,
259    pub sum_prefill_kv_tokens: u64,
260    pub num_decode_requests: u32,
261    pub sum_decode_kv_tokens: u64,
262    pub var_decode_kv_tokens: f64,
263    pub num_queued_prefill: u32,
264    pub sum_queued_prefill_tokens: u64,
265    pub var_queued_prefill_length: f64,
266    pub num_queued_decode: u32,
267    pub sum_queued_decode_kv_tokens: u64,
268    pub var_queued_decode_kv_tokens: f64,
269    pub duration_ms: f64,
270}
271
272/// Effects of a scheduler command.
273#[derive(Debug, Clone, PartialEq)]
274pub struct CommandEffects {
275    pub result: CommandResult,
276    pub lifecycle_events: Vec<LifecycleEvent>,
277    pub kv_events: Vec<KvEvent>,
278    /// Requests whose scheduler/KV ownership ended while applying this command.
279    ///
280    /// Replayers use this authoritative delta for cancellation and handoff
281    /// cleanup instead of inferring ownership from command ordering.
282    pub retired_requests: Vec<Uuid>,
283    /// Scheduler state after the command and all immediately admitted work.
284    ///
285    /// Live drivers use this to acknowledge commands while the engine is idle
286    /// without waiting for an otherwise unrelated forward pass.
287    pub metrics: Metrics,
288    /// Whether an output already computed by an in-flight pass was suppressed.
289    pub suppressed_pending_output: bool,
290}
291
292/// Effects visible as soon as an engine pass starts.
293#[derive(Debug, Clone, Default, PartialEq)]
294pub struct PassStartEffects {
295    pub admissions: Vec<Admission>,
296    pub pressure_events: Vec<PressureEvent>,
297    pub kv_events: Vec<KvEvent>,
298}
299
300/// Effects released at the modeled pass completion boundary.
301#[derive(Debug, Clone, Default, PartialEq)]
302pub struct PassCompletionEffects {
303    pub outputs: Vec<Output>,
304    pub lifecycle_events: Vec<LifecycleEvent>,
305    /// KV events whose scheduler visibility boundary is pass completion.
306    pub kv_events: Vec<KvEvent>,
307    pub metrics: Metrics,
308    pub forward_pass_metrics: ForwardPassMetrics,
309}
310
311/// Retained completion effects of an eagerly executed engine pass.
312#[doc(hidden)]
313pub struct PendingPass {
314    pub(crate) started_at_ms: f64,
315    pub(crate) effects: PassCompletionEffects,
316}