1use std::io;
2
3use super::{
4 activation::{decode_f16_to_f32_bytes, decode_q8_to_f32_bytes_with_state_flags},
5 invalid_data,
6};
7
8pub const STAGE_STATE_VERSION: i32 = 11;
12pub const MAX_STAGE_LOGIT_BIAS: usize = 256;
13pub const MAX_STAGE_PREDICTED_TOKENS: usize = 262_144;
14pub const MAX_STAGE_SIDEBAND_VALUES: usize = 1_048_576;
15pub const MAX_STAGE_CHAT_SAMPLING_METADATA_BYTES: usize = 8 * 1024 * 1024;
16pub const MAX_STAGE_STATE_IMPORT_BYTES: usize = 512 * 1024 * 1024;
17pub const MAX_STAGE_ACTIVATION_BYTES: usize = 512 * 1024 * 1024;
18pub const MAX_STAGE_DECODED_ACTIVATION_BYTES: usize = 512 * 1024 * 1024;
19pub const READY_MAGIC: i32 = 0x5352_4459; pub const LLAMA_TOKEN_NULL: i32 = -1;
21pub const STAGE_STATE_HEADER_BYTES: usize = 10 * 4;
22pub const STAGE_SAMPLING_CONFIG_BASE_BYTES: usize = 10 * 4;
23pub const STAGE_LOGIT_BIAS_WIRE_BYTES: usize = 4 + 4;
24pub const STAGE_WIRE_FIXED_HEADER_BYTES: usize = 5 * 4 + STAGE_STATE_HEADER_BYTES + 2 * 8;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27#[repr(i32)]
28pub enum WireActivationDType {
29 F32 = 0,
30 F16 = 1,
31 Q8 = 2,
32}
33
34impl TryFrom<i32> for WireActivationDType {
35 type Error = io::Error;
36
37 fn try_from(value: i32) -> Result<Self, Self::Error> {
38 match value {
39 0 => Ok(Self::F32),
40 1 => Ok(Self::F16),
41 2 => Ok(Self::Q8),
42 _ => Err(invalid_data("unknown activation wire dtype")),
43 }
44 }
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48#[repr(i32)]
49pub enum WireMessageKind {
50 PrefillEmbd = 1,
51 DecodeEmbd = 2,
52 Stop = 3,
53 PrefillFinalEmbd = 4,
54 DecodeReplayEmbd = 5,
55 DecodeReplayFinalEmbd = 6,
56 StateImport = 7,
57 DecodeReadout = 8,
58 DecodeLightCtx = 9,
59 VerifyWindow = 21,
60 RetireVerifyWindow = 22,
61 StateExport = 13,
62 ConfigureGeneration = 14,
63 ProbePrefill = 15,
64 RestorePrefill = 16,
65 TryRestorePrefill = 17,
66 TryRestorePrefillDecode = 18,
67 TrimSession = 19,
68 PredictionReturnOpen = 20,
69}
70
71impl WireMessageKind {
72 pub fn is_prefill(self) -> bool {
73 matches!(self, Self::PrefillEmbd | Self::PrefillFinalEmbd)
74 }
75
76 pub fn is_decode_replay(self) -> bool {
77 matches!(self, Self::DecodeReplayEmbd | Self::DecodeReplayFinalEmbd)
78 }
79
80 pub fn is_decode_light_context(self) -> bool {
81 matches!(self, Self::DecodeLightCtx)
82 }
83
84 pub fn requires_predicted_reply(self) -> bool {
85 matches!(
86 self,
87 Self::DecodeEmbd
88 | Self::DecodeReadout
89 | Self::DecodeLightCtx
90 | Self::VerifyWindow
91 | Self::PrefillFinalEmbd
92 | Self::DecodeReplayFinalEmbd
93 )
94 }
95
96 pub fn is_session_control(self) -> bool {
97 matches!(self, Self::TrimSession)
98 }
99
100 pub fn is_verify_retirement(self) -> bool {
101 matches!(self, Self::RetireVerifyWindow)
102 }
103
104 pub fn is_generation_control(self) -> bool {
105 matches!(self, Self::ConfigureGeneration)
106 }
107
108 pub fn is_prefix_cache_control(self) -> bool {
109 matches!(
110 self,
111 Self::ProbePrefill
112 | Self::RestorePrefill
113 | Self::TryRestorePrefill
114 | Self::TryRestorePrefillDecode
115 )
116 }
117
118 pub fn is_activationless_prefix_cache_control(self) -> bool {
119 matches!(
120 self,
121 Self::ProbePrefill | Self::RestorePrefill | Self::TryRestorePrefill
122 )
123 }
124}
125
126impl TryFrom<i32> for WireMessageKind {
127 type Error = io::Error;
128
129 fn try_from(value: i32) -> Result<Self, Self::Error> {
130 match value {
131 1 => Ok(Self::PrefillEmbd),
132 2 => Ok(Self::DecodeEmbd),
133 3 => Ok(Self::Stop),
134 4 => Ok(Self::PrefillFinalEmbd),
135 5 => Ok(Self::DecodeReplayEmbd),
136 6 => Ok(Self::DecodeReplayFinalEmbd),
137 7 => Ok(Self::StateImport),
138 8 => Ok(Self::DecodeReadout),
139 9 => Ok(Self::DecodeLightCtx),
140 13 => Ok(Self::StateExport),
141 14 => Ok(Self::ConfigureGeneration),
142 15 => Ok(Self::ProbePrefill),
143 16 => Ok(Self::RestorePrefill),
144 17 => Ok(Self::TryRestorePrefill),
145 18 => Ok(Self::TryRestorePrefillDecode),
146 19 => Ok(Self::TrimSession),
147 20 => Ok(Self::PredictionReturnOpen),
148 21 => Ok(Self::VerifyWindow),
149 22 => Ok(Self::RetireVerifyWindow),
150 _ => Err(invalid_data("unknown stage message kind")),
151 }
152 }
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156#[repr(i32)]
157pub enum WireReplyKind {
158 Ack = 1,
159 PredictedToken = 2,
160 PredictedTokens = 3,
161}
162
163impl TryFrom<i32> for WireReplyKind {
164 type Error = io::Error;
165
166 fn try_from(value: i32) -> Result<Self, Self::Error> {
167 match value {
168 1 => Ok(Self::Ack),
169 2 => Ok(Self::PredictedToken),
170 3 => Ok(Self::PredictedTokens),
171 _ => Err(invalid_data("unknown stage reply kind")),
172 }
173 }
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
177#[repr(i32)]
178pub enum WireStagePhase {
179 Prefill = 1,
180 Decode = 2,
181 DecodeReplay = 3,
182 DecodeLight = 4,
183}
184
185pub mod state_flags {
186 pub const FINAL_CHUNK: i32 = 1 << 0;
187 pub const LIGHT_CONTEXT: i32 = 1 << 1;
188 pub const SAMPLING: i32 = 1 << 3;
189 pub const FULL_STATE: i32 = 1 << 4;
190 pub const CHAT_SAMPLING_METADATA: i32 = 1 << 5;
191 pub const RWKV7_V_FIRST_SIDEBAND: i32 = 1 << 6;
192 pub const GEMMA3N_ALTUP_SIDEBAND: i32 = 1 << 7;
193 pub const INKLING_MTP_EMBD_SIDEBAND: i32 = 1 << 8;
194}
195
196pub const ACTIVATION_FLAG_RWKV7_V_FIRST: u64 = 1 << 0;
197pub const ACTIVATION_FLAG_GEMMA3N_ALTUP: u64 = 1 << 1;
198pub const ACTIVATION_FLAG_INKLING_MTP_EMBD: u64 = 1 << 2;
199
200pub fn activation_frame_flags_from_state_flags(flags: i32) -> u64 {
201 let mut frame_flags = 0;
202 if (flags & state_flags::RWKV7_V_FIRST_SIDEBAND) != 0 {
203 frame_flags |= ACTIVATION_FLAG_RWKV7_V_FIRST;
204 }
205 if (flags & state_flags::GEMMA3N_ALTUP_SIDEBAND) != 0 {
206 frame_flags |= ACTIVATION_FLAG_GEMMA3N_ALTUP;
207 }
208 if (flags & state_flags::INKLING_MTP_EMBD_SIDEBAND) != 0 {
209 frame_flags |= ACTIVATION_FLAG_INKLING_MTP_EMBD;
210 }
211 frame_flags
212}
213
214pub fn activation_state_flags_from_frame_flags(flags: u64) -> i32 {
215 let mut state = 0;
216 if (flags & ACTIVATION_FLAG_RWKV7_V_FIRST) != 0 {
217 state |= state_flags::RWKV7_V_FIRST_SIDEBAND;
218 }
219 if (flags & ACTIVATION_FLAG_GEMMA3N_ALTUP) != 0 {
220 state |= state_flags::GEMMA3N_ALTUP_SIDEBAND;
221 }
222 if (flags & ACTIVATION_FLAG_INKLING_MTP_EMBD) != 0 {
223 state |= state_flags::INKLING_MTP_EMBD_SIDEBAND;
224 }
225 state
226}
227
228#[derive(Debug, Clone, Copy, PartialEq, Eq)]
229pub struct StageStateHeader {
230 pub version: i32,
231 pub seq_id: i32,
232 pub phase: i32,
233 pub flags: i32,
234 pub checkpoint_generation: i32,
235 pub prompt_token_count: i32,
236 pub decode_step: i32,
237 pub current_token: i32,
238 pub source_stage_index: i32,
239 pub reserved: i32,
240}
241
242#[derive(Debug, Clone, Copy, PartialEq)]
243pub struct StageLogitBias {
244 pub token_id: i32,
245 pub bias: f32,
246}
247
248impl Default for StageLogitBias {
249 fn default() -> Self {
250 Self {
251 token_id: 0,
252 bias: 0.0,
253 }
254 }
255}
256
257#[derive(Debug, Clone, PartialEq)]
258pub struct StageSamplingConfig {
259 pub flags: u32,
260 pub seed: u32,
261 pub temperature: f32,
262 pub top_p: f32,
263 pub top_k: i32,
264 pub min_p: f32,
265 pub presence_penalty: f32,
266 pub frequency_penalty: f32,
267 pub repeat_penalty: f32,
268 pub penalty_last_n: i32,
269 pub logit_bias: Vec<StageLogitBias>,
270}
271
272impl Default for StageSamplingConfig {
273 fn default() -> Self {
274 Self {
275 flags: 0,
276 seed: 0,
277 temperature: 1.0,
278 top_p: 1.0,
279 top_k: 0,
280 min_p: 0.0,
281 presence_penalty: 0.0,
282 frequency_penalty: 0.0,
283 repeat_penalty: 1.0,
284 penalty_last_n: -1,
285 logit_bias: Vec::new(),
286 }
287 }
288}
289
290impl StageSamplingConfig {
291 pub fn enabled(&self) -> bool {
292 self.flags != 0
293 }
294}
295
296impl StageStateHeader {
297 pub fn new(kind: WireMessageKind, dtype: WireActivationDType) -> Self {
298 let mut header = Self {
299 version: STAGE_STATE_VERSION,
300 seq_id: 0,
301 phase: expected_phase(kind) as i32,
302 flags: 0,
303 checkpoint_generation: 0,
304 prompt_token_count: 0,
305 decode_step: -1,
306 current_token: LLAMA_TOKEN_NULL,
307 source_stage_index: -1,
308 reserved: dtype as i32,
309 };
310 if matches!(
311 kind,
312 WireMessageKind::PrefillFinalEmbd | WireMessageKind::DecodeReplayFinalEmbd
313 ) {
314 header.flags |= state_flags::FINAL_CHUNK;
315 }
316 if kind.is_decode_light_context() {
317 header.flags |= state_flags::LIGHT_CONTEXT;
318 }
319 header
320 }
321
322 pub fn dtype(self) -> io::Result<WireActivationDType> {
323 WireActivationDType::try_from(self.reserved)
324 }
325
326 pub fn matches_kind(self, kind: WireMessageKind) -> bool {
327 if matches!(
328 kind,
329 WireMessageKind::StateImport | WireMessageKind::StateExport
330 ) || kind.is_session_control()
331 || kind.is_verify_retirement()
332 || kind.is_generation_control()
333 {
334 return true;
335 }
336 if self.phase != expected_phase(kind) as i32 {
337 return false;
338 }
339 let expected_final = matches!(
340 kind,
341 WireMessageKind::PrefillFinalEmbd | WireMessageKind::DecodeReplayFinalEmbd
342 );
343 let actual_final = (self.flags & state_flags::FINAL_CHUNK) != 0;
344 let expected_light = kind.is_decode_light_context();
345 let actual_light = (self.flags & state_flags::LIGHT_CONTEXT) != 0;
346 expected_final == actual_final && expected_light == actual_light
347 }
348}
349
350impl Default for StageStateHeader {
351 fn default() -> Self {
352 Self::new(WireMessageKind::PrefillEmbd, WireActivationDType::F32)
353 }
354}
355
356#[derive(Debug, Clone, Copy, PartialEq, Eq)]
357pub struct StageRequestEpoch {
358 pub request_id: u64,
359 pub session_id: u64,
360 pub checkpoint_generation: i32,
361 pub prompt_token_count: i32,
362 pub decode_step: i32,
363}
364
365impl StageRequestEpoch {
366 pub fn same_flow(self, other: Self) -> bool {
367 self.request_id == other.request_id && self.session_id == other.session_id
368 }
369
370 pub fn is_stale_for(self, current: Self) -> bool {
378 self.same_flow(current)
379 && (
380 self.checkpoint_generation,
381 self.prompt_token_count,
382 self.decode_step,
383 ) < (
384 current.checkpoint_generation,
385 current.prompt_token_count,
386 current.decode_step,
387 )
388 }
389}
390
391#[derive(Debug, Clone, PartialEq)]
392pub struct StageWireMessage {
393 pub kind: WireMessageKind,
394 pub pos_start: i32,
395 pub token_count: i32,
396 pub state: StageStateHeader,
397 pub request_id: u64,
398 pub session_id: u64,
399 pub sampling: Option<StageSamplingConfig>,
400 pub chat_sampling_metadata: Option<String>,
401 pub tokens: Vec<i32>,
402 pub positions: Vec<i32>,
403 pub activation: Vec<u8>,
404 pub raw_bytes: Vec<u8>,
405}
406
407impl StageWireMessage {
408 pub fn authoritative_session_position(&self) -> Option<u64> {
413 if !matches!(
414 self.kind,
415 WireMessageKind::DecodeEmbd
416 | WireMessageKind::DecodeReadout
417 | WireMessageKind::DecodeLightCtx
418 | WireMessageKind::VerifyWindow
419 ) {
420 return None;
421 }
422 u64::try_from(self.pos_start).ok()
423 }
424
425 pub fn verify_window_id(&self) -> Option<i32> {
426 (self.kind == WireMessageKind::VerifyWindow).then_some(self.state.seq_id)
427 }
428
429 pub fn verify_window_base_position(&self) -> Option<i32> {
430 (self.kind == WireMessageKind::VerifyWindow).then_some(self.pos_start)
431 }
432
433 pub fn verify_window_token_count(&self) -> Option<i32> {
434 (self.kind == WireMessageKind::VerifyWindow).then_some(self.token_count)
435 }
436
437 pub fn estimated_wire_bytes(&self) -> usize {
438 let sampling_bytes = self.sampling.as_ref().map_or(0, |sampling| {
439 STAGE_SAMPLING_CONFIG_BASE_BYTES
440 + sampling.logit_bias.len().min(MAX_STAGE_LOGIT_BIAS) * STAGE_LOGIT_BIAS_WIRE_BYTES
441 });
442 let chat_metadata_bytes = self
443 .chat_sampling_metadata
444 .as_ref()
445 .map_or(0, |metadata| std::mem::size_of::<u32>() + metadata.len());
446 STAGE_WIRE_FIXED_HEADER_BYTES
447 .saturating_add(sampling_bytes)
448 .saturating_add(chat_metadata_bytes)
449 .saturating_add(self.payload_wire_bytes())
450 }
451
452 fn payload_wire_bytes(&self) -> usize {
453 if self.kind == WireMessageKind::StateImport {
454 return self.raw_bytes.len();
455 }
456 self.tokens
457 .len()
458 .saturating_mul(std::mem::size_of::<i32>())
459 .saturating_add(
460 self.positions
461 .len()
462 .saturating_mul(std::mem::size_of::<i32>()),
463 )
464 .saturating_add(self.activation.len())
465 }
466
467 pub fn request_epoch(&self) -> StageRequestEpoch {
468 StageRequestEpoch {
469 request_id: self.request_id,
470 session_id: self.session_id,
471 checkpoint_generation: self.state.checkpoint_generation,
472 prompt_token_count: self.state.prompt_token_count,
473 decode_step: self.state.decode_step,
474 }
475 }
476
477 pub fn stop(dtype: WireActivationDType) -> Self {
478 Self::stop_with_identity(dtype, 0, 0)
479 }
480
481 pub fn stop_with_identity(
482 dtype: WireActivationDType,
483 request_id: u64,
484 session_id: u64,
485 ) -> Self {
486 Self {
487 kind: WireMessageKind::Stop,
488 pos_start: 0,
489 token_count: 0,
490 state: StageStateHeader::new(WireMessageKind::Stop, dtype),
491 request_id,
492 session_id,
493 sampling: None,
494 chat_sampling_metadata: None,
495 tokens: Vec::new(),
496 positions: Vec::new(),
497 activation: Vec::new(),
498 raw_bytes: Vec::new(),
499 }
500 }
501
502 pub fn configure_generation(
503 dtype: WireActivationDType,
504 request_id: u64,
505 session_id: u64,
506 prompt_token_count: i32,
507 sampling: Option<StageSamplingConfig>,
508 chat_sampling_metadata: Option<String>,
509 ) -> Self {
510 let mut state = StageStateHeader::new(WireMessageKind::ConfigureGeneration, dtype);
511 state.prompt_token_count = prompt_token_count;
512 Self {
513 kind: WireMessageKind::ConfigureGeneration,
514 pos_start: 0,
515 token_count: 0,
516 state,
517 request_id,
518 session_id,
519 sampling,
520 chat_sampling_metadata,
521 tokens: Vec::new(),
522 positions: Vec::new(),
523 activation: Vec::new(),
524 raw_bytes: Vec::new(),
525 }
526 }
527
528 pub fn activation_f32_payload(&self, n_embd: i32) -> io::Result<Vec<u8>> {
529 if self.activation.is_empty() {
530 return Ok(Vec::new());
531 }
532 match self.state.dtype()? {
533 WireActivationDType::F32 => {
534 if self.activation.len() > MAX_STAGE_DECODED_ACTIVATION_BYTES {
535 return Err(invalid_data(
536 "decoded activation payload byte count exceeds maximum",
537 ));
538 }
539 Ok(self.activation.clone())
540 }
541 WireActivationDType::F16 => decode_f16_to_f32_bytes(&self.activation),
542 WireActivationDType::Q8 => decode_q8_to_f32_bytes_with_state_flags(
543 &self.activation,
544 self.token_count,
545 n_embd,
546 self.state.flags,
547 ),
548 }
549 }
550
551 pub fn take_activation_f32_payload(&mut self, n_embd: i32) -> io::Result<Vec<u8>> {
552 if self.activation.is_empty() {
553 return Ok(Vec::new());
554 }
555 match self.state.dtype()? {
556 WireActivationDType::F32 => {
557 if self.activation.len() > MAX_STAGE_DECODED_ACTIVATION_BYTES {
558 return Err(invalid_data(
559 "decoded activation payload byte count exceeds maximum",
560 ));
561 }
562 Ok(std::mem::take(&mut self.activation))
563 }
564 WireActivationDType::F16 => decode_f16_to_f32_bytes(&self.activation),
565 WireActivationDType::Q8 => decode_q8_to_f32_bytes_with_state_flags(
566 &self.activation,
567 self.token_count,
568 n_embd,
569 self.state.flags,
570 ),
571 }
572 }
573}
574
575#[derive(Debug, Clone, PartialEq, Eq)]
576pub struct StageReply {
577 pub kind: WireReplyKind,
578 pub predicted: i32,
579 pub predicted_tokens: Vec<i32>,
581 pub native_mtp_draft: Option<StageNativeMtpDraft>,
582 pub window: StageReplyWindow,
583 pub stats: StageReplyStats,
584}
585
586#[derive(Debug, Clone, PartialEq, Eq)]
592pub struct StageNativeMtpDraft {
593 pub token_ids: Vec<i32>,
594 pub proposal_compute_us: i64,
595}
596
597#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
598pub struct StageReplyWindow {
599 pub window_id: i32,
600}
601
602#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
603pub struct StageReplyStats {
604 pub kv_lookup_hits: i64,
605 pub kv_lookup_misses: i64,
606 pub kv_lookup_errors: i64,
607 pub kv_imported_pages: i64,
608 pub kv_imported_tokens: i64,
609 pub kv_recorded_pages: i64,
610 pub kv_recorded_bytes: i64,
611 pub kv_hit_stage_mask: i64,
612 pub kv_record_stage_mask: i64,
613 pub verify_window_compute_us: i64,
614 pub verify_window_forward_write_us: i64,
615 pub verify_window_downstream_wait_us: i64,
616 pub verify_window_total_us: i64,
617 pub verify_window_stage_count: i64,
618 pub verify_window_request_count: i64,
619 pub verify_window_token_count: i64,
620 pub verify_window_max_tokens: i64,
621 pub prefill_edge_write_us_max: i64,
622 pub prefill_edge_wait_us_max: i64,
623 pub prefill_edge_total_us_max: i64,
624 pub prefill_edge_stage_index: i64,
625 pub prefill_edge_activation_bytes_max: i64,
626 pub prefill_edge_observation_count: i64,
627}
628
629impl StageReplyStats {
630 pub fn merge(&mut self, other: Self) {
631 self.kv_lookup_hits += other.kv_lookup_hits;
632 self.kv_lookup_misses += other.kv_lookup_misses;
633 self.kv_lookup_errors += other.kv_lookup_errors;
634 self.kv_imported_pages += other.kv_imported_pages;
635 self.kv_imported_tokens += other.kv_imported_tokens;
636 self.kv_recorded_pages += other.kv_recorded_pages;
637 self.kv_recorded_bytes += other.kv_recorded_bytes;
638 self.kv_hit_stage_mask |= other.kv_hit_stage_mask;
639 self.kv_record_stage_mask |= other.kv_record_stage_mask;
640 self.verify_window_compute_us += other.verify_window_compute_us;
641 self.verify_window_forward_write_us += other.verify_window_forward_write_us;
642 self.verify_window_downstream_wait_us += other.verify_window_downstream_wait_us;
643 self.verify_window_total_us += other.verify_window_total_us;
644 self.verify_window_stage_count += other.verify_window_stage_count;
645 self.verify_window_request_count += other.verify_window_request_count;
646 self.verify_window_token_count += other.verify_window_token_count;
647 self.verify_window_max_tokens = self
648 .verify_window_max_tokens
649 .max(other.verify_window_max_tokens);
650 self.prefill_edge_write_us_max = self
651 .prefill_edge_write_us_max
652 .max(other.prefill_edge_write_us_max);
653 self.prefill_edge_wait_us_max = self
654 .prefill_edge_wait_us_max
655 .max(other.prefill_edge_wait_us_max);
656 if other.prefill_edge_total_us_max > self.prefill_edge_total_us_max {
657 self.prefill_edge_total_us_max = other.prefill_edge_total_us_max;
658 self.prefill_edge_stage_index = other.prefill_edge_stage_index;
659 self.prefill_edge_activation_bytes_max = other.prefill_edge_activation_bytes_max;
660 }
661 self.prefill_edge_observation_count += other.prefill_edge_observation_count;
662 }
663
664 pub fn observe_prefill_edge_transport(
665 &mut self,
666 stage_index: u32,
667 write_us: i64,
668 wait_us: i64,
669 activation_bytes: usize,
670 ) {
671 let write_us = write_us.max(0);
672 let wait_us = wait_us.max(0);
673 let total_us = write_us.saturating_add(wait_us);
674 self.prefill_edge_write_us_max = self.prefill_edge_write_us_max.max(write_us);
675 self.prefill_edge_wait_us_max = self.prefill_edge_wait_us_max.max(wait_us);
676 if total_us > self.prefill_edge_total_us_max {
677 self.prefill_edge_total_us_max = total_us;
678 self.prefill_edge_stage_index = i64::from(stage_index);
679 self.prefill_edge_activation_bytes_max =
680 i64::try_from(activation_bytes).unwrap_or(i64::MAX);
681 }
682 self.prefill_edge_observation_count = self.prefill_edge_observation_count.saturating_add(1);
683 }
684
685 pub fn is_empty(self) -> bool {
686 self.kv_lookup_hits == 0
687 && self.kv_lookup_misses == 0
688 && self.kv_lookup_errors == 0
689 && self.kv_imported_pages == 0
690 && self.kv_imported_tokens == 0
691 && self.kv_recorded_pages == 0
692 && self.kv_recorded_bytes == 0
693 && self.kv_hit_stage_mask == 0
694 && self.kv_record_stage_mask == 0
695 && self.verify_window_compute_us == 0
696 && self.verify_window_forward_write_us == 0
697 && self.verify_window_downstream_wait_us == 0
698 && self.verify_window_total_us == 0
699 && self.verify_window_stage_count == 0
700 && self.verify_window_request_count == 0
701 && self.verify_window_token_count == 0
702 && self.verify_window_max_tokens == 0
703 && self.prefill_edge_observation_count == 0
704 }
705}
706
707fn expected_phase(kind: WireMessageKind) -> WireStagePhase {
708 if kind.is_prefill()
709 || matches!(
710 kind,
711 WireMessageKind::StateImport | WireMessageKind::StateExport
712 )
713 || kind.is_session_control()
714 || kind.is_verify_retirement()
715 || kind.is_generation_control()
716 || kind.is_prefix_cache_control()
717 {
718 WireStagePhase::Prefill
719 } else if kind.is_decode_replay() {
720 WireStagePhase::DecodeReplay
721 } else if kind.is_decode_light_context() {
722 WireStagePhase::DecodeLight
723 } else {
724 WireStagePhase::Decode
725 }
726}