1use std::cell::RefCell;
77use std::marker::PhantomData;
78use std::rc::Rc;
79use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
80use std::sync::{Arc, Mutex, OnceLock, Weak};
81
82use cudarc::driver::{CudaContext, CudaEvent, CudaSlice, CudaStream};
83
84use crate::Engine;
85
86pub(crate) struct PrimaryContextRestore<'a> {
90 engine: &'a Engine,
91 restored: bool,
92}
93
94impl<'a> PrimaryContextRestore<'a> {
95 pub(crate) fn new(engine: &'a Engine) -> Self {
96 Self {
97 engine,
98 restored: false,
99 }
100 }
101
102 pub(crate) fn restore(mut self) -> Result<(), Box<dyn std::error::Error>> {
103 let result = self.engine.ctx().bind_to_thread();
104 self.restored = result.is_ok();
105 result?;
106 Ok(())
107 }
108}
109
110impl Drop for PrimaryContextRestore<'_> {
111 fn drop(&mut self) {
112 if !self.restored {
113 let _ = self.engine.ctx().bind_to_thread();
114 }
115 }
116}
117
118pub fn pp_cuts(n_layers: usize) -> Option<Vec<usize>> {
123 let n_st: usize = match std::env::var("MEMRA_PP_STAGES") {
124 Ok(v) if v.is_empty() || v == "0" || v == "1" => return None,
125 Ok(v) => match v.parse::<usize>() {
126 Ok(n) => n,
127 Err(_) => {
128 warn_bad_once(&format!("MEMRA_PP_STAGES={v} unparseable; door stays OFF"));
129 return None;
130 }
131 },
132 Err(_) => return None,
133 };
134 if n_st < 2 || n_st > n_layers {
135 warn_bad_once(&format!(
136 "MEMRA_PP_STAGES={n_st} outside [2, n_layers={n_layers}]; door stays OFF"
137 ));
138 return None;
139 }
140 let mut fence = Vec::with_capacity(n_st + 1);
141 fence.push(0usize);
142 if let Ok(s) = std::env::var("MEMRA_PP_SPLITS") {
143 let parts: Result<Vec<usize>, _> =
144 s.split(',').map(|p| p.trim().parse::<usize>()).collect();
145 match parts {
146 Ok(cuts) if cuts.len() == n_st - 1 => fence.extend(cuts),
147 _ => {
148 warn_bad_once(&format!(
149 "MEMRA_PP_SPLITS={s} invalid (want {} comma-separated cuts); door stays OFF",
150 n_st - 1
151 ));
152 return None;
153 }
154 }
155 } else if let Ok(v) = std::env::var("MEMRA_PP_SPLIT") {
156 if n_st != 2 {
159 warn_bad_once(&format!(
160 "MEMRA_PP_SPLIT={v} set with MEMRA_PP_STAGES={n_st}; use MEMRA_PP_SPLITS \
161 for N>2 — door stays OFF"
162 ));
163 return None;
164 }
165 match v.parse::<usize>() {
166 Ok(c) => fence.push(c),
167 Err(_) => {
168 warn_bad_once(&format!("MEMRA_PP_SPLIT={v} unparseable; door stays OFF"));
169 return None;
170 }
171 }
172 } else {
173 for s in 1..n_st {
174 fence.push(s * n_layers / n_st);
175 }
176 }
177 fence.push(n_layers);
178 for w in fence.windows(2) {
179 if w[0] >= w[1] {
180 warn_bad_once(&format!(
181 "pp stage fence {fence:?} not strictly increasing over [0, {n_layers}]; \
182 door stays OFF"
183 ));
184 return None;
185 }
186 }
187 Some(fence)
188}
189
190pub fn pp2_split(n_layers: usize) -> Option<usize> {
193 pp_cuts(n_layers).filter(|f| f.len() == 3).map(|f| f[1])
194}
195
196pub fn stage_of(fence: &[usize], il: usize) -> usize {
198 debug_assert!(fence.len() >= 2);
199 match fence[1..fence.len() - 1].binary_search(&il) {
200 Ok(k) => k + 1,
202 Err(k) => k,
203 }
204}
205
206pub fn pp2_streams_off() -> bool {
209 matches!(std::env::var("MEMRA_PP_STREAMS").as_deref(), Ok("0"))
210}
211
212pub fn pp_multi_stream_same_device() -> bool {
223 let stages_open = std::env::var("MEMRA_PP_STAGES")
224 .map(|v| v.parse::<usize>().map(|n| n >= 2).unwrap_or(false))
225 .unwrap_or(false);
226 let devices = std::env::var("MEMRA_PP_DEVICES")
227 .ok()
228 .filter(|v| !v.is_empty());
229 if (!stages_open && devices.is_none()) || pp2_streams_off() {
230 return false;
231 }
232 match devices {
233 None => true, Some(s) => pp_devices_repeat(&s),
235 }
236}
237
238fn pp_devices_repeat(raw: &str) -> bool {
239 let Ok(mut devices) = raw
240 .split(',')
241 .map(|part| part.trim().parse::<usize>())
242 .collect::<Result<Vec<_>, _>>()
243 else {
244 return true;
247 };
248 let count = devices.len();
249 devices.sort_unstable();
250 devices.dedup();
251 devices.len() < count
252}
253
254pub fn pp_sharded_cross_device() -> bool {
268 let stages_open = std::env::var("MEMRA_PP_STAGES")
269 .map(|v| v.parse::<usize>().map(|n| n >= 2).unwrap_or(false))
270 .unwrap_or(false);
271 if !stages_open || pp_shard_off() || pp2_streams_off() {
278 return false;
279 }
280 match pp2_devices_env() {
281 None => false, Some(s) => {
283 let mut v: Vec<&str> = s.split(',').map(|p| p.trim()).collect();
284 v.sort_unstable();
285 v.dedup();
286 v.len() >= 2
287 }
288 }
289}
290
291pub fn refuse_unsplit_if_remote(path: &str, alt: &str) -> Result<(), Box<dyn std::error::Error>> {
303 if pp_host_bounce_active() {
304 return Err(format!(
305 "{path}: refused with MEMRA_PP_HOST_BOUNCE=1 on sharded cross-device PP — \
306 this unsplit path peer-reads remote weights, while host bounce covers only \
307 explicit stage-boundary transfers. Use {alt}; the \
308 MEMRA_PP_ALLOW_UNSPLIT_BATCH override is unavailable on a broken-peer host."
309 )
310 .into());
311 }
312 if pp_sharded_cross_device()
313 && std::env::var("MEMRA_PP_ALLOW_UNSPLIT_BATCH").as_deref() != Ok("1")
314 {
315 return Err(format!(
316 "{path}: refused with the ppN door open across 2+ devices — this path has no pp \
317 stage split, so it would walk ALL layers on one stream and peer-read every \
318 remote stage's weights each step (measured 28x slower at B=1, 13.9x at B=8 on \
319 a PRO 6000 pair over PCIe Gen5 x16 P2P; research/pp2-hardening-20260806). \
320 Exactness is unaffected — peer reads return identical bytes and the exactness \
321 gates PASS on this config — which is exactly why it must refuse instead of \
322 being caught by a gate. Fixes, in order: {alt}; or MEMRA_PP_SHARD=0 (all \
323 weights home on the primary — full speed, forfeits the capacity PP-2 exists \
324 for); or close the pp door. MEMRA_PP_ALLOW_UNSPLIT_BATCH=1 overrides for \
325 measurement."
326 )
327 .into());
328 }
329 Ok(())
330}
331
332pub fn batch_pp_on() -> bool {
340 std::env::var("MEMRA_BATCH_PP").as_deref() != Ok("0")
341}
342
343pub const PP_WAVE_MAX_STAGES: usize = 4;
347
348pub fn pp_wave_on_value(value: Option<&str>) -> Result<bool, &'static str> {
352 match value {
353 None | Some("0") => Ok(false),
354 Some("1") => Ok(true),
355 Some(_) => Err("MEMRA_PP_WAVE must be 0 or 1"),
356 }
357}
358
359pub fn pp_wave_on() -> Result<bool, &'static str> {
360 match std::env::var_os("MEMRA_PP_WAVE") {
361 None => pp_wave_on_value(None),
362 Some(value) => value
363 .to_str()
364 .ok_or("MEMRA_PP_WAVE must be valid UTF-8 and exactly 0 or 1")
365 .and_then(|value| pp_wave_on_value(Some(value))),
366 }
367}
368
369pub fn pp_wave_ranges(batch: usize, stages: usize) -> Vec<(usize, usize)> {
373 if batch == 0 || stages == 0 {
374 return Vec::new();
375 }
376 let waves = batch.min(stages);
377 let base = batch / waves;
378 let extra = batch % waves;
379 let mut out = Vec::with_capacity(waves);
380 let mut start = 0usize;
381 for wave in 0..waves {
382 let len = base + usize::from(wave < extra);
383 out.push((start, start + len));
384 start += len;
385 }
386 debug_assert_eq!(start, batch);
387 out
388}
389
390pub fn pp_wave_diagonal(stages: usize, waves: usize, diagonal: usize) -> Vec<(usize, usize)> {
395 if stages == 0 || waves == 0 || diagonal >= stages + waves - 1 {
396 return Vec::new();
397 }
398 let first_stage = diagonal.saturating_sub(waves - 1);
399 let last_stage = diagonal.min(stages - 1);
400 (first_stage..=last_stage)
401 .map(|stage| (diagonal - stage, stage))
402 .collect()
403}
404
405pub fn pp_wave_eligibility(
409 stages: usize,
410 double_slot: bool,
411 host_bounce: bool,
412 repeated_device: bool,
413) -> Result<(), &'static str> {
414 if !(3..=PP_WAVE_MAX_STAGES).contains(&stages) {
415 return Err("PP wavefront requires 3 or 4 stages; PP2 is owned by MEMRA_DUAL_PP");
416 }
417 if !double_slot {
418 return Err("PP wavefront requires MEMRA_PP_OVERLAP=1 double-buffered boundaries");
419 }
420 if host_bounce {
421 return Err(
422 "PP wavefront is unqualified with MEMRA_PP_HOST_BOUNCE=1; use native peer transport",
423 );
424 }
425 if repeated_device {
426 return Err("PP wavefront requires one distinct CUDA device per stage");
427 }
428 Ok(())
429}
430
431pub const PP_WAVE_W4A16_BF16_REFUSAL: &str = "PP wavefront for a W4A16 artifact with preserved BF16 non-expert weights requires \
437 MEMRA_BF16_MMV=1; without the row-wise BF16 program, wave batch-width decomposition changes \
438 logits. Keep MEMRA_PP_WAVE=0 or enable and qualify MEMRA_BF16_MMV=1";
439
440pub fn pp_wave_numeric_eligibility(
441 weight_only_nvfp4: bool,
442 bf16_mmv: bool,
443) -> Result<(), &'static str> {
444 if weight_only_nvfp4 && !bf16_mmv {
445 return Err(PP_WAVE_W4A16_BF16_REFUSAL);
446 }
447 Ok(())
448}
449
450pub fn pp_wave_route_enabled(
453 requested: bool,
454 overlap: bool,
455 stages: usize,
456 work_items: usize,
457) -> bool {
458 requested && overlap && (3..=PP_WAVE_MAX_STAGES).contains(&stages) && work_items >= 2
459}
460
461static PP_WAVE_ACTIVE_CELLS: AtomicUsize = AtomicUsize::new(0);
462static PP_WAVE_OVERLAPS: AtomicUsize = AtomicUsize::new(0);
463static PP_WAVE_TICKS: AtomicUsize = AtomicUsize::new(0);
464static PP_WAVE_CELLS: AtomicUsize = AtomicUsize::new(0);
465
466pub(crate) struct PpWaveCellGuard;
467
468pub(crate) fn enter_pp_wave_cell() -> PpWaveCellGuard {
472 let active = PP_WAVE_ACTIVE_CELLS.fetch_add(1, Ordering::AcqRel);
473 if active > 0 {
474 PP_WAVE_OVERLAPS.fetch_add(1, Ordering::Relaxed);
475 }
476 PP_WAVE_CELLS.fetch_add(1, Ordering::Relaxed);
477 PpWaveCellGuard
478}
479
480impl Drop for PpWaveCellGuard {
481 fn drop(&mut self) {
482 let active = PP_WAVE_ACTIVE_CELLS.fetch_sub(1, Ordering::AcqRel);
483 debug_assert!(active > 0, "PP wave active-cell counter underflow");
484 }
485}
486
487pub(crate) fn record_pp_wave_tick() {
488 PP_WAVE_TICKS.fetch_add(1, Ordering::Relaxed);
489}
490
491pub fn pp_wave_snapshot() -> (usize, usize, usize) {
493 (
494 PP_WAVE_TICKS.load(Ordering::Relaxed),
495 PP_WAVE_CELLS.load(Ordering::Relaxed),
496 PP_WAVE_OVERLAPS.load(Ordering::Relaxed),
497 )
498}
499
500#[derive(Clone, Copy, PartialEq, Eq, Debug)]
518pub enum DualPpMode {
519 Off,
520 Forced,
521 Auto,
522}
523
524pub fn dual_pp_mode_resolve(v: Option<&str>) -> DualPpMode {
527 match v {
528 Some("0") => DualPpMode::Off,
529 Some("1") => DualPpMode::Forced,
530 _ => DualPpMode::Auto,
531 }
532}
533
534pub fn dual_pp_mode() -> DualPpMode {
535 dual_pp_mode_resolve(std::env::var("MEMRA_DUAL_PP").ok().as_deref())
536}
537
538pub fn dual_pp_on() -> bool {
541 dual_pp_mode() != DualPpMode::Off
542}
543
544pub fn dual_pp_route(
550 mode: DualPpMode,
551 batch: usize,
552 stages: usize,
553 double_slot: bool,
554 host_bounce: bool,
555) -> bool {
556 if batch < 2 {
557 return false;
558 }
559 match mode {
560 DualPpMode::Off => false,
561 DualPpMode::Forced => true,
562 DualPpMode::Auto => stages == 2 && double_slot && !host_bounce,
563 }
564}
565
566pub const DUAL_PP_SINGLE_SLOT_REFUSAL: &str = "decode_step_batch_dual: refused: PP boundary is single-slot; set MEMRA_PP_OVERLAP=1 so both alternating boundary slots are prepared before dual-active decode";
569pub const DUAL_PP_HOST_BOUNCE_REFUSAL: &str = "decode_step_batch_dual: refused: MEMRA_PP_HOST_BOUNCE=1 is unvalidated for dual-active decode; disable MEMRA_DUAL_PP or use peer transport";
570
571#[allow(clippy::manual_div_ceil)] pub fn dual_pp_wave_mid(batch: usize) -> Option<usize> {
575 (batch >= 2).then_some((batch + 1) / 2)
576}
577
578pub fn dual_pp_eligibility(
581 stages: usize,
582 double_slot: bool,
583 host_bounce: bool,
584) -> Result<(), &'static str> {
585 if stages != 2 {
586 return Err(
587 "decode_step_batch_dual: refused: dual-active decode requires exactly two PP stages",
588 );
589 }
590 if !double_slot {
591 return Err(DUAL_PP_SINGLE_SLOT_REFUSAL);
592 }
593 if host_bounce {
594 return Err(DUAL_PP_HOST_BOUNCE_REFUSAL);
595 }
596 Ok(())
597}
598
599static DUAL_PP_OVERLAPS: AtomicUsize = AtomicUsize::new(0);
602static DUAL_PP_ACTIVE_STAGES: AtomicUsize = AtomicUsize::new(0);
603static DUAL_PP_STAGE_NS: [AtomicU64; 4] = [
604 AtomicU64::new(0),
605 AtomicU64::new(0),
606 AtomicU64::new(0),
607 AtomicU64::new(0),
608];
609static DUAL_PP_STAGE_SAMPLES: [AtomicUsize; 4] = [
610 AtomicUsize::new(0),
611 AtomicUsize::new(0),
612 AtomicUsize::new(0),
613 AtomicUsize::new(0),
614];
615static DUAL_PP_TIMING_DROPPED: AtomicUsize = AtomicUsize::new(0);
616static DUAL_PP_SLOT_PAIRS: AtomicUsize = AtomicUsize::new(0);
617static DUAL_PP_SLOT_USES: [AtomicUsize; 2] = [AtomicUsize::new(0), AtomicUsize::new(0)];
618static DUAL_PP_SLOT_COLLISIONS: AtomicUsize = AtomicUsize::new(0);
619
620pub const DUAL_PP_STAGE_NAMES: [&str; 4] = [
621 "wave_a_stage0",
622 "wave_a_stage1",
623 "wave_b_stage0",
624 "wave_b_stage1",
625];
626
627pub fn dual_pp_overlaps() -> usize {
628 DUAL_PP_OVERLAPS.load(Ordering::Relaxed)
629}
630
631pub(crate) fn record_dual_pp_slot_pair(slot_a: usize, slot_b: usize) -> bool {
635 debug_assert!(slot_a < DUAL_PP_SLOT_USES.len());
636 debug_assert!(slot_b < DUAL_PP_SLOT_USES.len());
637 if slot_a == slot_b {
638 DUAL_PP_SLOT_COLLISIONS.fetch_add(1, Ordering::Relaxed);
639 return false;
640 }
641 DUAL_PP_SLOT_USES[slot_a].fetch_add(1, Ordering::Relaxed);
642 DUAL_PP_SLOT_USES[slot_b].fetch_add(1, Ordering::Relaxed);
643 DUAL_PP_SLOT_PAIRS.fetch_add(1, Ordering::Relaxed);
644 true
645}
646
647pub fn dual_pp_slot_snapshot() -> (usize, [usize; 2], usize) {
649 (
650 DUAL_PP_SLOT_PAIRS.load(Ordering::Relaxed),
651 std::array::from_fn(|i| DUAL_PP_SLOT_USES[i].load(Ordering::Relaxed)),
652 DUAL_PP_SLOT_COLLISIONS.load(Ordering::Relaxed),
653 )
654}
655
656pub fn dual_pp_timing_on() -> bool {
660 static ON: OnceLock<bool> = OnceLock::new();
661 *ON.get_or_init(|| std::env::var("MEMRA_DUAL_PP_TIMING").as_deref() == Ok("1"))
662}
663
664pub(crate) fn record_dual_pp_stage_ms(stage: usize, ms: f32) {
665 assert!(
666 stage < DUAL_PP_STAGE_NS.len(),
667 "dual PP timing stage out of range"
668 );
669 let ns = (f64::from(ms) * 1_000_000.0).round() as u64;
670 DUAL_PP_STAGE_NS[stage].fetch_add(ns, Ordering::Relaxed);
671 DUAL_PP_STAGE_SAMPLES[stage].fetch_add(1, Ordering::Relaxed);
672}
673
674pub(crate) fn record_dual_pp_timing_drop(context: &str, err: &dyn std::fmt::Display) {
677 let previous = DUAL_PP_TIMING_DROPPED.fetch_add(1, Ordering::Relaxed);
678 if previous == 0 {
679 eprintln!(
680 "[dual-pp] WARN: skipped diagnostic timing sample at {context}: {err}; decode continues"
681 );
682 }
683}
684
685pub(crate) fn record_dual_pp_stage_result<E: std::fmt::Display>(
686 stage: usize,
687 elapsed: Result<f32, E>,
688) {
689 match elapsed {
690 Ok(ms) => record_dual_pp_stage_ms(stage, ms),
691 Err(err) => record_dual_pp_timing_drop(DUAL_PP_STAGE_NAMES[stage], &err),
692 }
693}
694
695pub fn dual_pp_timing_dropped() -> usize {
696 DUAL_PP_TIMING_DROPPED.load(Ordering::Relaxed)
697}
698
699pub fn dual_pp_timing_snapshot() -> ([u64; 4], [usize; 4]) {
701 (
702 std::array::from_fn(|i| DUAL_PP_STAGE_NS[i].load(Ordering::Relaxed)),
703 std::array::from_fn(|i| DUAL_PP_STAGE_SAMPLES[i].load(Ordering::Relaxed)),
704 )
705}
706
707pub(crate) struct DualPpStageGuard;
708
709pub(crate) fn enter_dual_pp_stage() -> DualPpStageGuard {
710 let active = DUAL_PP_ACTIVE_STAGES.fetch_add(1, Ordering::AcqRel);
711 if active > 0 {
712 DUAL_PP_OVERLAPS.fetch_add(1, Ordering::Relaxed);
713 }
714 DualPpStageGuard
715}
716
717impl Drop for DualPpStageGuard {
718 fn drop(&mut self) {
719 let active = DUAL_PP_ACTIVE_STAGES.fetch_sub(1, Ordering::AcqRel);
720 debug_assert!(active > 0, "dual PP active-stage counter underflow");
721 }
722}
723
724pub fn prime_pp_on() -> bool {
734 std::env::var("MEMRA_PRIME_PP").as_deref() != Ok("0")
735}
736
737pub fn prime_pipe_on() -> bool {
742 std::env::var("MEMRA_PRIME_PIPE").as_deref() != Ok("0")
743}
744
745pub static PRIME_SPLIT_CHUNKS: AtomicUsize = AtomicUsize::new(0);
752
753pub fn prime_split_chunks() -> usize {
755 PRIME_SPLIT_CHUNKS.load(Ordering::Relaxed)
756}
757
758pub static PRIME_PIPE_OVERLAPS: AtomicUsize = AtomicUsize::new(0);
763
764pub fn prime_pipe_overlaps() -> usize {
766 PRIME_PIPE_OVERLAPS.load(Ordering::Relaxed)
767}
768
769static PRIME_PIPE_ACTIVE_STAGES: AtomicUsize = AtomicUsize::new(0);
770
771pub(crate) struct PrimePipeStageGuard;
772
773pub(crate) fn enter_prime_pipe_stage() -> PrimePipeStageGuard {
776 let active = PRIME_PIPE_ACTIVE_STAGES.fetch_add(1, Ordering::AcqRel);
777 if active > 0 {
778 PRIME_PIPE_OVERLAPS.fetch_add(1, Ordering::Relaxed);
779 }
780 PrimePipeStageGuard
781}
782
783impl Drop for PrimePipeStageGuard {
784 fn drop(&mut self) {
785 let active = PRIME_PIPE_ACTIVE_STAGES.fetch_sub(1, Ordering::AcqRel);
786 debug_assert!(active > 0, "prime pipeline active-stage counter underflow");
787 }
788}
789
790pub static STEP35_PRIME_BATCHES: AtomicUsize = AtomicUsize::new(0);
794pub static STEP35_PRIME_BATCH_SPLITS: AtomicUsize = AtomicUsize::new(0);
795
796pub fn step35_prime_batches() -> usize {
797 STEP35_PRIME_BATCHES.load(Ordering::Relaxed)
798}
799
800pub fn step35_prime_batch_splits() -> usize {
801 STEP35_PRIME_BATCH_SPLITS.load(Ordering::Relaxed)
802}
803
804pub fn spec_pp_on() -> bool {
812 std::env::var("MEMRA_SPEC_PP").as_deref() != Ok("0")
813}
814
815pub fn pp2_overlap() -> bool {
826 pp2_overlap_resolve(
827 std::env::var("MEMRA_PP_OVERLAP").ok().as_deref(),
828 dual_pp_mode(),
829 )
830}
831
832pub fn pp2_overlap_resolve(v: Option<&str>, mode: DualPpMode) -> bool {
835 match v {
836 Some("1") => true,
837 Some(_) => false,
838 None => mode == DualPpMode::Auto,
839 }
840}
841
842pub fn pp_host_bounce_on() -> bool {
845 matches!(std::env::var("MEMRA_PP_HOST_BOUNCE").as_deref(), Ok("1"))
846}
847
848pub fn pp_host_bounce_active() -> bool {
851 (pp_host_bounce_on() || PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire))
852 && pp_sharded_cross_device()
853}
854
855pub fn pp_shard_off() -> bool {
859 matches!(std::env::var("MEMRA_PP_SHARD").as_deref(), Ok("0"))
860}
861
862fn pp2_devices_env() -> Option<String> {
865 std::env::var("MEMRA_PP_DEVICES")
866 .ok()
867 .filter(|v| !v.is_empty())
868}
869
870static WARNED_BAD: AtomicBool = AtomicBool::new(false);
871fn warn_bad_once(msg: &str) {
872 if !WARNED_BAD.swap(true, Ordering::Relaxed) {
873 eprintln!("[pp] {msg}");
874 }
875}
876
877static WARNED_UNWIRED: AtomicBool = AtomicBool::new(false);
878pub fn warn_unwired_once(path: &str) {
881 let open = std::env::var("MEMRA_PP_STAGES")
882 .map(|v| !v.is_empty() && v != "0" && v != "1")
883 .unwrap_or(false);
884 if open && !WARNED_UNWIRED.swap(true, Ordering::Relaxed) {
885 eprintln!("[pp] MEMRA_PP_STAGES set but `{path}` has no pp arm at this N; running unsplit");
886 }
887}
888
889pub struct StageRt {
897 pub dev: usize,
898 pub ctx: Arc<CudaContext>,
899 pub stream: Arc<CudaStream>,
900 pub blas: Arc<cudarc::cublaslt::CudaBlasLT>,
901 engine: Option<Engine>,
903}
904
905struct BoundarySlot {
910 buf: Mutex<Option<CudaSlice<f32>>>,
911 ev_tx: CudaEvent,
914 ev_rx: CudaEvent,
918}
919
920struct BoundaryRt {
924 slots: [BoundarySlot; 2],
925 step: AtomicUsize,
926 cross: bool,
928}
929
930#[derive(Clone, Copy, Debug, PartialEq, Eq)]
931enum BoundaryTransport {
932 Local,
933 Peer,
934 HostBounce,
935}
936
937#[derive(Clone, Copy)]
938struct BoundaryPath {
939 boundary: usize,
940 src_stage: usize,
941 dst_stage: usize,
942 transport: BoundaryTransport,
943}
944
945fn boundary_transport(cross: bool, host_bounce: bool) -> BoundaryTransport {
946 match (cross, host_bounce) {
947 (false, _) => BoundaryTransport::Local,
948 (true, false) => BoundaryTransport::Peer,
949 (true, true) => BoundaryTransport::HostBounce,
950 }
951}
952
953const PEER_PROBE_FIXED_BYTES: usize = 16 * 1024;
954const PEER_PROBE_TOKEN_WIDTHS: [usize; 4] = [1, 8, 16, crate::cache::PRIME_CHUNK_MAX_TOKENS];
955
956pub const PEER_RUNTIME_PROBE_INTERVAL_COPIES: u64 = 8 * 1024;
959pub const PEER_RUNTIME_PROBE_CYCLE_COPIES: u64 =
961 PEER_RUNTIME_PROBE_INTERVAL_COPIES * PEER_PROBE_TOKEN_WIDTHS.len() as u64;
962pub const PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS: u64 = PEER_PROBE_TOKEN_WIDTHS.len() as u64;
965const PEER_RUNTIME_PROBE_BUDGET_NS: u64 = 5_000_000;
967
968pub const PEER_PROBE_REQUIRED_REFUSAL: &str = "PP bring-up refused: MEMRA_PEER_PROBE=0 cannot authorize native peer transport for a \
969 sharded cross-device placement while MEMRA_PP_HOST_BOUNCE!=1; leave MEMRA_PEER_PROBE \
970 enabled or set MEMRA_PP_HOST_BOUNCE=1";
971
972#[derive(Clone, Copy, Debug, PartialEq, Eq)]
973pub enum PeerProbeStartupPolicy {
974 Allowed,
975 BypassedWithHostBounce,
976}
977
978pub fn peer_probe_startup_policy(
981 probe_on: bool,
982 sharded_cross_device: bool,
983 host_bounce: bool,
984) -> Result<PeerProbeStartupPolicy, &'static str> {
985 match (probe_on, sharded_cross_device, host_bounce) {
986 (false, true, false) => Err(PEER_PROBE_REQUIRED_REFUSAL),
987 (false, true, true) => Ok(PeerProbeStartupPolicy::BypassedWithHostBounce),
988 _ => Ok(PeerProbeStartupPolicy::Allowed),
989 }
990}
991
992static PEER_PROBE_BYPASSED: AtomicU64 = AtomicU64::new(0);
993static PEER_BOUNDARY_COPIES: AtomicU64 = AtomicU64::new(0);
994static PEER_RUNTIME_PROBES: AtomicU64 = AtomicU64::new(0);
995static PEER_RUNTIME_PROBE_FAILURES: AtomicU64 = AtomicU64::new(0);
996static PEER_RUNTIME_PROBE_DEFERRED: AtomicU64 = AtomicU64::new(0);
997static PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED: AtomicBool = AtomicBool::new(false);
998static PEER_RUNTIME_PROBE_FAILED: AtomicBool = AtomicBool::new(false);
999static PEER_RUNTIME_HOST_BOUNCE: AtomicBool = AtomicBool::new(false);
1000static PEER_RUNTIME_NEXT_PROBE_COPY: [AtomicU64; PEER_PROBE_TOKEN_WIDTHS.len()] = [
1001 AtomicU64::new(PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1002 AtomicU64::new(2 * PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1003 AtomicU64::new(3 * PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1004 AtomicU64::new(4 * PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1005];
1006static PEER_RUNTIME_PROBE_MAX_COST_NS: [AtomicU64; PEER_PROBE_TOKEN_WIDTHS.len()] = [
1007 AtomicU64::new(0),
1008 AtomicU64::new(0),
1009 AtomicU64::new(0),
1010 AtomicU64::new(0),
1011];
1012
1013#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1014pub struct PeerProbeMetrics {
1015 pub bypassed: u64,
1016 pub boundary_copies: u64,
1017 pub runtime_probes: u64,
1018 pub runtime_failures: u64,
1019 pub deferred_total: u64,
1020 pub integrity_degraded: bool,
1021 pub degraded_to_host_bounce: bool,
1022}
1023
1024pub fn peer_probe_metrics() -> PeerProbeMetrics {
1025 PeerProbeMetrics {
1026 bypassed: PEER_PROBE_BYPASSED.load(Ordering::Relaxed),
1027 boundary_copies: PEER_BOUNDARY_COPIES.load(Ordering::Relaxed),
1028 runtime_probes: PEER_RUNTIME_PROBES.load(Ordering::Relaxed),
1029 runtime_failures: PEER_RUNTIME_PROBE_FAILURES.load(Ordering::Relaxed),
1030 deferred_total: PEER_RUNTIME_PROBE_DEFERRED.load(Ordering::Relaxed),
1031 integrity_degraded: PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED.load(Ordering::Acquire),
1032 degraded_to_host_bounce: PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire),
1033 }
1034}
1035
1036#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1037pub enum RuntimePeerProbeStatus {
1038 NotRun,
1039 Deferred,
1040 Passed,
1041 DegradedToHostBounce,
1042}
1043
1044impl RuntimePeerProbeStatus {
1045 pub fn ran(self) -> bool {
1046 matches!(self, Self::Passed | Self::DegradedToHostBounce)
1047 }
1048}
1049
1050fn publish_runtime_peer_probe_deferral(
1051 deferred_total: &AtomicU64,
1052 integrity_degraded: &AtomicBool,
1053 intervals: u64,
1054 bound_reached: bool,
1055) {
1056 deferred_total.fetch_add(intervals, Ordering::Relaxed);
1057 if bound_reached {
1058 integrity_degraded.store(true, Ordering::Release);
1059 }
1060}
1061
1062pub fn record_runtime_peer_probe_deferral(intervals: u64, bound_reached: bool) {
1065 publish_runtime_peer_probe_deferral(
1066 &PEER_RUNTIME_PROBE_DEFERRED,
1067 &PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED,
1068 intervals,
1069 bound_reached,
1070 );
1071}
1072
1073pub fn clear_runtime_peer_probe_integrity_degraded() {
1075 PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED.store(false, Ordering::Release);
1076}
1077
1078fn runtime_peer_probe_idle_only(width_index: usize, measured_cost_ns: u64) -> bool {
1079 width_index + 1 == PEER_PROBE_TOKEN_WIDTHS.len()
1080 || measured_cost_ns > PEER_RUNTIME_PROBE_BUDGET_NS
1081}
1082
1083fn runtime_peer_probe_candidate(
1086 copies: u64,
1087 next_probe_copy: [u64; PEER_PROBE_TOKEN_WIDTHS.len()],
1088 measured_cost_ns: [u64; PEER_PROBE_TOKEN_WIDTHS.len()],
1089 scheduler_idle: bool,
1090) -> Option<(usize, usize)> {
1091 let mut selected: Option<(usize, u64)> = None;
1092 for width_index in 0..PEER_PROBE_TOKEN_WIDTHS.len() {
1093 let due = next_probe_copy[width_index];
1094 if copies < due
1095 || (!scheduler_idle
1096 && runtime_peer_probe_idle_only(width_index, measured_cost_ns[width_index]))
1097 {
1098 continue;
1099 }
1100 if selected.is_none_or(|(_, selected_due)| due < selected_due) {
1101 selected = Some((width_index, due));
1102 }
1103 }
1104 selected.map(|(width_index, _)| (width_index, PEER_PROBE_TOKEN_WIDTHS[width_index]))
1105}
1106
1107fn runtime_peer_probe_next_copy(due: u64, copies: u64) -> u64 {
1110 let cycles = copies.saturating_sub(due) / PEER_RUNTIME_PROBE_CYCLE_COPIES + 1;
1111 due.saturating_add(PEER_RUNTIME_PROBE_CYCLE_COPIES.saturating_mul(cycles))
1112}
1113
1114fn latch_runtime_host_bounce<E>(
1117 native_failed: &AtomicBool,
1118 degraded_to_host_bounce: &AtomicBool,
1119 arm_and_validate: impl FnOnce() -> Result<(), E>,
1120) -> Result<(), E> {
1121 native_failed.store(true, Ordering::Release);
1122 arm_and_validate()?;
1123 degraded_to_host_bounce.store(true, Ordering::Release);
1124 Ok(())
1125}
1126
1127fn peer_probe_on() -> bool {
1128 std::env::var("MEMRA_PEER_PROBE").as_deref() != Ok("0")
1129}
1130
1131#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1132enum PeerProbeDecision {
1133 Clean,
1134 ProceedWithHostBounce { mismatches: usize },
1135}
1136
1137fn peer_probe_mismatch_count(expected: &[u8], readback: &[u8]) -> usize {
1138 expected
1139 .iter()
1140 .zip(readback)
1141 .filter(|(a, b)| a != b)
1142 .count()
1143 + expected.len().abs_diff(readback.len())
1144}
1145
1146fn peer_probe_decision(
1147 expected: &[u8],
1148 readback: &[u8],
1149 host_bounce: bool,
1150) -> Result<PeerProbeDecision, String> {
1151 let mismatches = peer_probe_mismatch_count(expected, readback);
1152 if mismatches == 0 {
1153 Ok(PeerProbeDecision::Clean)
1154 } else if host_bounce {
1155 Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches })
1156 } else {
1157 Err(format!("{mismatches} mismatched byte(s)"))
1158 }
1159}
1160
1161fn peer_probe_pattern(bytes: usize, boundary: usize, src_dev: usize, dst_dev: usize) -> Vec<u8> {
1162 let mut state = 0xD1B5_4A32_D192_ED03u64
1163 ^ (bytes as u64).rotate_left(7)
1164 ^ (boundary as u64).rotate_left(19)
1165 ^ (src_dev as u64).rotate_left(31)
1166 ^ (dst_dev as u64).rotate_left(43);
1167 (0..bytes)
1168 .map(|_| {
1169 state ^= state << 13;
1170 state ^= state >> 7;
1171 state ^= state << 17;
1172 state as u8
1173 })
1174 .collect()
1175}
1176
1177fn peer_probe_bytes_to_f32(bytes: &[u8]) -> Vec<f32> {
1178 assert_eq!(bytes.len() % std::mem::size_of::<f32>(), 0);
1179 bytes
1180 .chunks_exact(std::mem::size_of::<f32>())
1181 .map(|chunk| f32::from_bits(u32::from_ne_bytes(chunk.try_into().unwrap())))
1182 .collect()
1183}
1184
1185fn peer_probe_f32_to_bytes(values: &[f32]) -> Vec<u8> {
1186 values
1187 .iter()
1188 .flat_map(|value| value.to_bits().to_ne_bytes())
1189 .collect()
1190}
1191
1192struct PeerProbeBuffer {
1196 ctx: Arc<CudaContext>,
1197 ptr: cudarc::driver::sys::CUdeviceptr,
1198}
1199
1200impl PeerProbeBuffer {
1201 fn new(ctx: &Arc<CudaContext>, bytes: usize) -> Result<Self, Box<dyn std::error::Error>> {
1202 ctx.bind_to_thread()?;
1203 let ptr = unsafe { cudarc::driver::result::malloc_sync(bytes)? };
1204 Ok(Self {
1205 ctx: ctx.clone(),
1206 ptr,
1207 })
1208 }
1209}
1210
1211impl Drop for PeerProbeBuffer {
1212 fn drop(&mut self) {
1213 if self.ctx.bind_to_thread().is_ok() {
1214 let _ = unsafe { cudarc::driver::result::free_sync(self.ptr) };
1215 }
1216 }
1217}
1218
1219fn peer_probe_copy(
1220 src: &StageRt,
1221 dst: &StageRt,
1222 expected: &[u8],
1223) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
1224 let bytes = expected.len();
1225 let src_buf = PeerProbeBuffer::new(&src.ctx, bytes)?;
1226 unsafe {
1227 cudarc::driver::result::memcpy_htod_sync(src_buf.ptr, expected)?;
1228 }
1229
1230 let dst_buf = PeerProbeBuffer::new(&dst.ctx, bytes)?;
1231 let poison: Vec<u8> = expected.iter().map(|b| !b).collect();
1232 unsafe {
1233 cudarc::driver::result::memcpy_htod_sync(dst_buf.ptr, &poison)?;
1234 }
1235
1236 src.ctx.bind_to_thread()?;
1237 unsafe {
1238 cudarc::driver::result::memcpy_peer_async(
1239 dst.ctx.cu_ctx(),
1240 dst_buf.ptr,
1241 src.ctx.cu_ctx(),
1242 src_buf.ptr,
1243 bytes,
1244 src.stream.cu_stream(),
1245 )?;
1246 }
1247
1248 let published = src.ctx.new_event(None)?;
1254 published.record(&src.stream)?;
1255
1256 dst.ctx.bind_to_thread()?;
1257 dst.stream.wait(&published)?;
1258 dst.stream.synchronize()?;
1259 let mut readback = vec![0u8; bytes];
1260 unsafe {
1261 cudarc::driver::result::memcpy_dtoh_sync(&mut readback, dst_buf.ptr)?;
1262 }
1263 Ok(readback)
1264}
1265
1266fn run_peer_probe_pass(
1267 stages: &[StageRt],
1268 peer_capable: &[(usize, usize)],
1269 host_bounce: bool,
1270 label: &str,
1271 bytes: usize,
1272) -> Result<(), Box<dyn std::error::Error>> {
1273 if bytes == 0 {
1274 return Err(format!("PP peer byte-integrity probe {label} size is zero").into());
1275 }
1276 let started = std::time::Instant::now();
1277 let mut copies = 0usize;
1278 let mut skipped = 0usize;
1279 let mut total_mismatches = 0usize;
1280
1281 for boundary in 0..stages.len() - 1 {
1282 if stages[boundary].dev == stages[boundary + 1].dev {
1283 continue;
1284 }
1285 for (src_idx, dst_idx) in [(boundary, boundary + 1), (boundary + 1, boundary)] {
1286 let src = &stages[src_idx];
1287 let dst = &stages[dst_idx];
1288 if !peer_capable.contains(&(src.dev, dst.dev)) {
1289 if host_bounce {
1290 skipped += 1;
1291 eprintln!(
1292 "[pp] peer byte-integrity probe SKIP: boundary={boundary} \
1293 dev{}->dev{} label={label} bytes={bytes} (peer capability unavailable; \
1294 MEMRA_PP_HOST_BOUNCE=1 remains fail-safe)",
1295 src.dev, dst.dev,
1296 );
1297 continue;
1298 }
1299 return Err(format!(
1300 "PP peer byte-integrity probe cannot run boundary={boundary} \
1301 dev{}->dev{}: peer access was not enabled",
1302 src.dev, dst.dev,
1303 )
1304 .into());
1305 }
1306
1307 let expected = peer_probe_pattern(bytes, boundary, src.dev, dst.dev);
1308 let readback = match peer_probe_copy(src, dst, &expected) {
1309 Ok(readback) => readback,
1310 Err(err) if host_bounce => {
1311 skipped += 1;
1312 eprintln!(
1313 "[pp] peer byte-integrity probe ERROR: boundary={boundary} \
1314 dev{}->dev{} label={label} bytes={bytes}: {err}; \
1315 MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path",
1316 src.dev, dst.dev,
1317 );
1318 continue;
1319 }
1320 Err(err) => {
1321 return Err(format!(
1322 "PP peer byte-integrity probe FAILED: boundary={boundary} \
1323 dev{}->dev{} label={label} bytes={bytes}: {err}; refusing native P2P \
1324 (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
1325 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)",
1326 src.dev, dst.dev,
1327 )
1328 .into());
1329 }
1330 };
1331 copies += 1;
1332 match peer_probe_decision(&expected, &readback, host_bounce) {
1333 Ok(PeerProbeDecision::Clean) => {}
1334 Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches }) => {
1335 total_mismatches += mismatches;
1336 eprintln!(
1337 "[pp] peer byte-integrity probe CORRUPTION: boundary={boundary} \
1338 dev{}->dev{} label={label} bytes={bytes} mismatches={mismatches}; \
1339 MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path",
1340 src.dev, dst.dev,
1341 );
1342 }
1343 Err(mismatch) => {
1344 return Err(format!(
1345 "PP peer byte-integrity probe FAILED: boundary={boundary} \
1346 dev{}->dev{} label={label} bytes={bytes}: {mismatch}; refusing native \
1347 P2P (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
1348 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)",
1349 src.dev, dst.dev,
1350 )
1351 .into());
1352 }
1353 }
1354 }
1355 }
1356
1357 let status = if total_mismatches > 0 {
1358 "BOUNCE"
1359 } else if skipped > 0 && copies > 0 {
1360 "PARTIAL"
1361 } else if skipped > 0 {
1362 "SKIP"
1363 } else {
1364 "PASS"
1365 };
1366 eprintln!(
1367 "[pp] peer byte-integrity probe {}: label={label} bytes={bytes} copies={copies} \
1368 skipped={skipped} mismatches={total_mismatches} elapsed_ms={:.3}",
1369 status,
1370 started.elapsed().as_secs_f64() * 1e3,
1371 );
1372 Ok(())
1373}
1374
1375fn host_bounce_capacity(n_embd: usize) -> Result<(usize, usize), String> {
1376 if n_embd == 0 {
1377 return Err("MEMRA_PP_HOST_BOUNCE needs non-zero model n_embd".into());
1378 }
1379 let elems = n_embd
1380 .checked_mul(crate::cache::PRIME_CHUNK_MAX_TOKENS)
1381 .ok_or_else(|| format!("host-bounce element count overflows for n_embd={n_embd}"))?;
1382 let bytes = elems
1383 .checked_mul(std::mem::size_of::<f32>())
1384 .ok_or_else(|| format!("host-bounce byte count overflows for n_embd={n_embd}"))?;
1385 Ok((elems, bytes))
1386}
1387
1388fn boundary_slot_growth_elements(current: [usize; 2], required: usize) -> usize {
1389 current.into_iter().fold(0usize, |total, len| {
1390 total.saturating_add(required.saturating_sub(len))
1391 })
1392}
1393
1394struct PinnedHostBounce {
1399 ptr: *mut f32,
1400 len: usize,
1401}
1402
1403unsafe impl Send for PinnedHostBounce {}
1404unsafe impl Sync for PinnedHostBounce {}
1405
1406impl PinnedHostBounce {
1407 fn new(len: usize) -> Result<Self, Box<dyn std::error::Error>> {
1408 let bytes = len
1409 .checked_mul(std::mem::size_of::<f32>())
1410 .ok_or("host-bounce pinned allocation size overflow")?;
1411 let ptr = unsafe {
1412 cudarc::driver::result::malloc_host(
1413 bytes,
1414 cudarc::driver::sys::CU_MEMHOSTALLOC_PORTABLE,
1415 )?
1416 } as *mut f32;
1417 if ptr.is_null() {
1418 return Err("cuMemHostAlloc returned a null host-bounce pointer".into());
1419 }
1420 Ok(Self { ptr, len })
1421 }
1422
1423 fn prefix(&self, n: usize) -> &[f32] {
1424 assert!(
1425 n <= self.len,
1426 "host-bounce source {n} > capacity {}",
1427 self.len
1428 );
1429 unsafe { std::slice::from_raw_parts(self.ptr, n) }
1430 }
1431
1432 fn prefix_mut(&mut self, n: usize) -> &mut [f32] {
1433 assert!(
1434 n <= self.len,
1435 "host-bounce destination {n} > capacity {}",
1436 self.len
1437 );
1438 unsafe { std::slice::from_raw_parts_mut(self.ptr, n) }
1439 }
1440}
1441
1442impl Drop for PinnedHostBounce {
1443 fn drop(&mut self) {
1444 let _ = unsafe { cudarc::driver::result::free_host(self.ptr.cast()) };
1445 }
1446}
1447
1448struct HostBounceRt {
1449 n_embd: usize,
1450 capacity: usize,
1451 slots: Vec<Option<[Mutex<PinnedHostBounce>; 2]>>,
1452}
1453
1454impl HostBounceRt {
1455 fn new(n_embd: usize, boundaries: &[BoundaryRt]) -> Result<Self, Box<dyn std::error::Error>> {
1456 let (capacity, _) = host_bounce_capacity(n_embd)?;
1457 let mut slots = Vec::with_capacity(boundaries.len());
1458 for boundary in boundaries {
1459 slots.push(if boundary.cross {
1460 Some([
1461 Mutex::new(PinnedHostBounce::new(capacity)?),
1462 Mutex::new(PinnedHostBounce::new(capacity)?),
1463 ])
1464 } else {
1465 None
1466 });
1467 }
1468 Ok(Self {
1469 n_embd,
1470 capacity,
1471 slots,
1472 })
1473 }
1474
1475 fn slot(
1476 &self,
1477 boundary: usize,
1478 slot: usize,
1479 ) -> Result<&Mutex<PinnedHostBounce>, Box<dyn std::error::Error>> {
1480 self.slots
1481 .get(boundary)
1482 .and_then(Option::as_ref)
1483 .and_then(|slots| slots.get(slot))
1484 .ok_or_else(|| format!("host-bounce slot {boundary}:{slot} is not initialized").into())
1485 }
1486}
1487
1488pub struct PpNRt {
1489 stages: Vec<StageRt>,
1490 boundaries: Vec<BoundaryRt>,
1491 walk_active: Arc<AtomicU64>,
1495 walk_next: AtomicU64,
1496 deferred_walk: Mutex<Weak<PpWalkState>>,
1500 cross_any: bool,
1502 host_bounce: bool,
1505 peer_probe: bool,
1507 peer_capable: Vec<(usize, usize)>,
1509 peer_probe_geometry: OnceLock<Result<usize, String>>,
1511 bounce: OnceLock<Result<HostBounceRt, String>>,
1513 readback: Arc<CudaStream>,
1516}
1517
1518#[derive(Debug)]
1519struct PpWalkState {
1520 active: Arc<AtomicU64>,
1521 generation: u64,
1522 runtime_id: usize,
1523 deferred_owner: Option<std::thread::ThreadId>,
1524}
1525
1526impl PpWalkState {
1527 fn is_active(&self) -> bool {
1528 self.active.load(Ordering::Acquire) == self.generation
1529 }
1530}
1531
1532impl Drop for PpWalkState {
1533 fn drop(&mut self) {
1534 let _ =
1535 self.active
1536 .compare_exchange(self.generation, 0, Ordering::AcqRel, Ordering::Acquire);
1537 }
1538}
1539
1540#[derive(Debug)]
1544pub struct PpWalkLease {
1545 state: Arc<PpWalkState>,
1546}
1547
1548#[derive(Clone, Debug)]
1550pub(crate) struct PpWalkPermit {
1551 state: Arc<PpWalkState>,
1552}
1553
1554thread_local! {
1555 static PP_WALK_BORROWS: RefCell<Vec<Arc<PpWalkState>>> = const { RefCell::new(Vec::new()) };
1556}
1557
1558pub(crate) struct PpWalkBorrowGuard {
1561 prior_len: usize,
1562 _not_send: PhantomData<Rc<()>>,
1563}
1564
1565impl Drop for PpWalkBorrowGuard {
1566 fn drop(&mut self) {
1567 PP_WALK_BORROWS.with(|borrows| borrows.borrow_mut().truncate(self.prior_len));
1568 }
1569}
1570
1571fn next_pp_walk_generation(next: &AtomicU64) -> u64 {
1572 loop {
1573 let generation = next.fetch_add(1, Ordering::Relaxed);
1574 if generation != 0 {
1575 return generation;
1576 }
1577 }
1578}
1579
1580fn acquire_pp_walk(
1581 active: &Arc<AtomicU64>,
1582 next: &AtomicU64,
1583 runtime_id: usize,
1584 deferred_owner: Option<std::thread::ThreadId>,
1585 path: &str,
1586) -> Result<PpWalkLease, String> {
1587 let generation = next_pp_walk_generation(next);
1588 active
1589 .compare_exchange(0, generation, Ordering::AcqRel, Ordering::Acquire)
1590 .map_err(|_| {
1591 format!(
1592 "{path}: refused concurrent PP walk; shared boundary slots already have an owner"
1593 )
1594 })?;
1595 Ok(PpWalkLease {
1596 state: Arc::new(PpWalkState {
1597 active: active.clone(),
1598 generation,
1599 runtime_id,
1600 deferred_owner,
1601 }),
1602 })
1603}
1604
1605fn borrowed_pp_walk(runtime_id: usize) -> Option<PpWalkLease> {
1606 PP_WALK_BORROWS.with(|borrows| {
1607 borrows
1608 .borrow()
1609 .iter()
1610 .rev()
1611 .find(|state| state.runtime_id == runtime_id && state.is_active())
1612 .cloned()
1613 .map(|state| PpWalkLease { state })
1614 })
1615}
1616
1617fn lock_deferred_walk<'a>(
1618 deferred: &'a Mutex<Weak<PpWalkState>>,
1619 path: &str,
1620) -> Result<std::sync::MutexGuard<'a, Weak<PpWalkState>>, String> {
1621 deferred
1622 .lock()
1623 .map_err(|_| format!("{path}: deferred PP walk owner lock is poisoned"))
1624}
1625
1626fn validate_walk_state(state: &PpWalkState, runtime_id: usize, path: &str) -> Result<(), String> {
1627 if state.runtime_id != runtime_id {
1628 return Err(format!(
1629 "{path}: PP walk permit belongs to a different runtime"
1630 ));
1631 }
1632 if !state.is_active() {
1633 return Err(format!(
1634 "{path}: PP walk permit generation is no longer active"
1635 ));
1636 }
1637 Ok(())
1638}
1639
1640pub type Pp2Rt = PpNRt;
1642
1643static RTN: OnceLock<Result<PpNRt, String>> = OnceLock::new();
1644
1645impl PpNRt {
1646 pub fn get(e: &Engine) -> Result<&'static PpNRt, Box<dyn std::error::Error>> {
1650 RTN.get_or_init(|| Self::build(e).map_err(|err| err.to_string()))
1651 .as_ref()
1652 .map_err(|s| -> Box<dyn std::error::Error> { s.clone().into() })
1653 }
1654
1655 fn build(e: &Engine) -> Result<PpNRt, Box<dyn std::error::Error>> {
1656 pp_wave_on().map_err(|reason| -> Box<dyn std::error::Error> { reason.into() })?;
1659 let primary_dev = e.ctx().ordinal();
1660 let devices: Vec<usize> =
1663 match pp2_devices_env() {
1664 Some(s) => {
1665 let parts: Result<Vec<usize>, _> =
1666 s.split(',').map(|p| p.trim().parse::<usize>()).collect();
1667 match parts {
1668 Ok(v) if v.len() >= 2 => v,
1669 _ => return Err(format!(
1670 "MEMRA_PP_DEVICES={s} unparseable (want <d0>,..,<dN-1> e.g. 0,1,2,3)"
1671 )
1672 .into()),
1673 }
1674 }
1675 None => {
1676 let n_st = std::env::var("MEMRA_PP_STAGES")
1677 .ok()
1678 .and_then(|v| v.parse::<usize>().ok())
1679 .filter(|&n| n >= 2)
1680 .unwrap_or(2);
1681 vec![primary_dev; n_st]
1682 }
1683 };
1684 if let Ok(v) = std::env::var("MEMRA_PP_STAGES")
1685 && let Ok(n) = v.parse::<usize>()
1686 && n >= 2
1687 && n != devices.len()
1688 {
1689 return Err(format!(
1690 "MEMRA_PP_DEVICES lists {} devices but MEMRA_PP_STAGES={n} — \
1691 refusing an ambiguous placement",
1692 devices.len()
1693 )
1694 .into());
1695 }
1696 let n_st = devices.len();
1697 let cross_any = devices.iter().any(|&d| d != devices[0]);
1698 let host_bounce = pp_host_bounce_on();
1699 let peer_probe = peer_probe_on();
1700 let sharded_cross_device = cross_any && !pp_shard_off();
1701 if host_bounce && cross_any {
1702 if pp_shard_off() {
1703 return Err(
1704 "MEMRA_PP_HOST_BOUNCE=1 refuses MEMRA_PP_SHARD=0: the boundary can bounce, \
1705 but remote stages would still peer-read primary-device weights"
1706 .into(),
1707 );
1708 }
1709 if devices.last().copied() != Some(primary_dev) {
1710 return Err(format!(
1711 "MEMRA_PP_HOST_BOUNCE=1 requires the primary engine on the last/head stage \
1712 (primary dev{primary_dev}, placement {devices:?}); otherwise returned \
1713 logits/hidden state remain peer reads"
1714 )
1715 .into());
1716 }
1717 }
1718 let peer_probe_policy =
1719 peer_probe_startup_policy(peer_probe, sharded_cross_device, host_bounce)?;
1720 if peer_probe_policy == PeerProbeStartupPolicy::BypassedWithHostBounce {
1721 PEER_PROBE_BYPASSED.fetch_add(1, Ordering::Relaxed);
1722 eprintln!(
1723 "[pp] SECURITY RED: peer_probe_bypassed: MEMRA_PEER_PROBE=0 on a sharded \
1724 cross-device placement; MEMRA_PP_HOST_BOUNCE=1 is the only enabled transport"
1725 );
1726 }
1727
1728 let mut used: Vec<usize> = devices.clone();
1732 used.push(primary_dev);
1733 used.sort_unstable();
1734 used.dedup();
1735 let mut peer_capable = Vec::new();
1736 if used.len() > 1 {
1737 let n = cudarc::driver::result::device::get_count()? as usize;
1738 for &d in &used {
1739 if d >= n {
1740 return Err(format!(
1741 "MEMRA_PP_DEVICES={devices:?} but only {n} CUDA device(s) present"
1742 )
1743 .into());
1744 }
1745 }
1746 if !host_bounce || peer_probe {
1747 for &a in &used {
1748 for &b in &used {
1749 if a == b {
1750 continue;
1751 }
1752 let da = cudarc::driver::result::device::get(a as i32)?;
1753 let db = cudarc::driver::result::device::get(b as i32)?;
1754 let mut can: i32 = 0;
1755 let capability = unsafe {
1756 cudarc::driver::sys::cuDeviceCanAccessPeer(&mut can, da, db).result()
1757 };
1758 if let Err(err) = capability {
1759 if host_bounce {
1760 eprintln!(
1761 "[pp] peer byte-integrity probe capability query failed for \
1762 dev{a}->dev{b}: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
1763 );
1764 continue;
1765 }
1766 return Err(err.into());
1767 }
1768 if can == 0 {
1769 if !host_bounce {
1770 return Err(format!(
1771 "device {a} cannot peer-access device {b} \
1772 (cuDeviceCanAccessPeer=0); ppN cross-device needs P2P — \
1773 refusing a silently-staged path"
1774 )
1775 .into());
1776 }
1777 } else {
1778 peer_capable.push((a, b));
1779 }
1780 }
1781 }
1782 }
1783 }
1784
1785 let mk_stage = |dev: usize, s: usize| -> Result<StageRt, Box<dyn std::error::Error>> {
1798 if dev == primary_dev && s == 0 {
1799 let ctx = e.ctx().clone();
1800 let stream = ctx.new_stream()?;
1801 let blas = Arc::new(cudarc::cublaslt::CudaBlasLT::new(stream.clone())?);
1802 Ok(StageRt {
1803 dev,
1804 ctx,
1805 stream,
1806 blas,
1807 engine: None,
1808 })
1809 } else {
1810 let eng = Engine::new(dev)?;
1811 let ctx = eng.ctx().clone();
1812 let stream = ctx.new_stream()?;
1813 let blas = Arc::new(cudarc::cublaslt::CudaBlasLT::new(stream.clone())?);
1814 Ok(StageRt {
1815 dev,
1816 ctx,
1817 stream,
1818 blas,
1819 engine: Some(eng),
1820 })
1821 }
1822 };
1823 let mut stages = Vec::with_capacity(n_st);
1824 for (s, &d) in devices.iter().enumerate() {
1825 stages.push(mk_stage(d, s)?);
1826 }
1827
1828 if cross_any
1829 && !peer_probe
1830 && peer_probe_policy != PeerProbeStartupPolicy::BypassedWithHostBounce
1831 {
1832 eprintln!(
1833 "[pp] WARNING: MEMRA_PEER_PROBE=0 skips the boot-time peer byte-integrity \
1834 gate; diagnostics escape hatch active"
1835 );
1836 }
1837
1838 if used.len() > 1 {
1839 if !host_bounce {
1840 let ctx_of = |d: usize| -> &Arc<CudaContext> {
1843 if d == primary_dev {
1844 e.ctx()
1845 } else {
1846 &stages.iter().find(|s| s.dev == d).unwrap().ctx
1847 }
1848 };
1849 for &a in &used {
1852 for &b in &used {
1853 if a == b {
1854 continue;
1855 }
1856 ctx_of(a).bind_to_thread()?;
1857 let rc = unsafe {
1858 cudarc::driver::sys::cuCtxEnablePeerAccess(ctx_of(b).cu_ctx(), 0)
1859 };
1860 use cudarc::driver::sys::cudaError_enum as E;
1861 if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED
1862 {
1863 return Err(format!(
1864 "cuCtxEnablePeerAccess(dev{a} -> dev{b}) failed: {rc:?}"
1865 )
1866 .into());
1867 }
1868 }
1869 }
1870 if peer_probe && cross_any {
1874 let probe = run_peer_probe_pass(
1875 &stages,
1876 &peer_capable,
1877 host_bounce,
1878 "fixed-16KiB",
1879 PEER_PROBE_FIXED_BYTES,
1880 );
1881 e.ctx().bind_to_thread()?;
1882 probe?;
1883 }
1884 for &owner in &used {
1893 for &accessor in &used {
1894 if owner == accessor {
1895 continue;
1896 }
1897 let dev = cudarc::driver::result::device::get(owner as i32)?;
1898 let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
1899 unsafe {
1900 cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev)
1901 .result()?;
1902 }
1903 let desc = cudarc::driver::sys::CUmemAccessDesc {
1904 location: cudarc::driver::sys::CUmemLocation {
1905 type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
1906 id: accessor as i32,
1907 },
1908 flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
1909 };
1910 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
1911 if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
1912 return Err(format!(
1913 "cuMemPoolSetAccess(dev{owner} pool -> dev{accessor}) failed: {rc:?}"
1914 )
1915 .into());
1916 }
1917 }
1918 }
1919 for (owner, accessor) in [
1928 (stages[0].dev, stages[1].dev),
1929 (stages[1].dev, stages[0].dev),
1930 ] {
1931 let dev = cudarc::driver::result::device::get(owner as i32)?;
1932 let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
1933 unsafe {
1934 cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
1935 }
1936 let desc = cudarc::driver::sys::CUmemAccessDesc {
1937 location: cudarc::driver::sys::CUmemLocation {
1938 type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
1939 id: accessor as i32,
1940 },
1941 flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
1942 };
1943 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
1944 if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
1945 return Err(format!(
1946 "cuMemPoolSetAccess(dev{owner} pool -> dev{accessor}) failed: {rc:?}"
1947 )
1948 .into());
1949 }
1950 }
1951 e.ctx().bind_to_thread()?;
1953 eprintln!(
1954 "[pp] cross-device transport: {} (cudaMemcpyPeerAsync per cross boundary; \
1955 peer + default-pool access granted all pairs over {used:?}; weight home: {})",
1956 devices
1957 .iter()
1958 .enumerate()
1959 .map(|(s, d)| format!("stage{s}=dev{d}"))
1960 .collect::<Vec<_>>()
1961 .join(" "),
1962 if pp_shard_off() {
1963 format!("dev{primary_dev} (MEMRA_PP_SHARD=0 bring-up placement)")
1964 } else {
1965 "per-stage (sharded loader)".to_string()
1966 }
1967 );
1968 } else {
1969 e.ctx().bind_to_thread()?;
1970 eprintln!(
1971 "[pp] cross-device transport: {} (HOST-STAGED pinned D2H -> H2D per cross \
1972 boundary; MEMRA_PP_HOST_BOUNCE=1; peer-pool grants bypassed; \
1973 diagnostic peer access is removed before host-staged serving; \
1974 weight home: per-stage (sharded loader))",
1975 devices
1976 .iter()
1977 .enumerate()
1978 .map(|(s, d)| format!("stage{s}=dev{d}"))
1979 .collect::<Vec<_>>()
1980 .join(" "),
1981 );
1982 }
1983 }
1984
1985 let mk_slot =
1986 |tx: &StageRt, rx: &StageRt| -> Result<BoundarySlot, Box<dyn std::error::Error>> {
1987 Ok(BoundarySlot {
1988 buf: Mutex::new(None),
1989 ev_tx: tx.ctx.new_event(None)?,
1990 ev_rx: rx.ctx.new_event(None)?,
1991 })
1992 };
1993 let mut boundaries = Vec::with_capacity(n_st - 1);
1994 for b in 0..n_st - 1 {
1995 let (tx, rx) = (&stages[b], &stages[b + 1]);
1996 boundaries.push(BoundaryRt {
1997 slots: [mk_slot(tx, rx)?, mk_slot(tx, rx)?],
1998 step: AtomicUsize::new(0),
1999 cross: tx.dev != rx.dev,
2000 });
2001 }
2002 let readback = stages[n_st - 1].ctx.new_stream()?;
2003 let rt = PpNRt {
2004 stages,
2005 boundaries,
2006 walk_active: Arc::new(AtomicU64::new(0)),
2007 walk_next: AtomicU64::new(1),
2008 deferred_walk: Mutex::new(Weak::new()),
2009 cross_any,
2010 host_bounce,
2011 peer_probe,
2012 peer_capable,
2013 peer_probe_geometry: OnceLock::new(),
2014 bounce: OnceLock::new(),
2015 readback,
2016 };
2017 if rt.peer_probe && rt.cross_any && rt.host_bounce {
2018 rt.run_host_bounce_legacy_probe(e)?;
2019 }
2020 Ok(rt)
2021 }
2022
2023 pub fn n_stages(&self) -> usize {
2024 self.stages.len()
2025 }
2026
2027 pub fn acquire_walk(
2031 &'static self,
2032 path: &str,
2033 ) -> Result<PpWalkLease, Box<dyn std::error::Error>> {
2034 let runtime_id = self as *const Self as usize;
2035 if let Some(lease) = borrowed_pp_walk(runtime_id) {
2036 return Ok(lease);
2037 }
2038 acquire_pp_walk(&self.walk_active, &self.walk_next, runtime_id, None, path)
2039 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })
2040 }
2041
2042 pub(crate) fn acquire_deferred_walk(
2045 &'static self,
2046 path: &str,
2047 ) -> Result<PpWalkLease, Box<dyn std::error::Error>> {
2048 let runtime_id = self as *const Self as usize;
2049 let current_thread = std::thread::current().id();
2050 let mut weak = lock_deferred_walk(&self.deferred_walk, path)
2051 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2052 if let Some(state) = weak.upgrade() {
2053 validate_walk_state(&state, runtime_id, path)
2054 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2055 if state.deferred_owner.as_ref() != Some(¤t_thread) {
2056 return Err(format!(
2057 "{path}: refused cross-thread join of the active deferred PP window"
2058 )
2059 .into());
2060 }
2061 return Ok(PpWalkLease { state });
2062 }
2063 let lease = acquire_pp_walk(
2064 &self.walk_active,
2065 &self.walk_next,
2066 runtime_id,
2067 Some(current_thread),
2068 path,
2069 )
2070 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2071 *weak = Arc::downgrade(&lease.state);
2072 Ok(lease)
2073 }
2074
2075 pub(crate) fn walk_permit(
2078 &'static self,
2079 lease: &PpWalkLease,
2080 path: &str,
2081 ) -> Result<PpWalkPermit, Box<dyn std::error::Error>> {
2082 let runtime_id = self as *const Self as usize;
2083 validate_walk_state(&lease.state, runtime_id, path)
2084 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2085 if lease.state.deferred_owner.is_some() {
2086 return Err(
2087 format!("{path}: deferred PP windows cannot mint coordinator permits").into(),
2088 );
2089 }
2090 Ok(PpWalkPermit {
2091 state: lease.state.clone(),
2092 })
2093 }
2094
2095 pub(crate) fn borrow_walk(
2097 &'static self,
2098 permit: &PpWalkPermit,
2099 path: &str,
2100 ) -> Result<PpWalkBorrowGuard, Box<dyn std::error::Error>> {
2101 let runtime_id = self as *const Self as usize;
2102 validate_walk_state(&permit.state, runtime_id, path)
2103 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2104 let prior_len = PP_WALK_BORROWS.with(|borrows| {
2105 let mut borrows = borrows.borrow_mut();
2106 let prior_len = borrows.len();
2107 borrows.push(permit.state.clone());
2108 prior_len
2109 });
2110 Ok(PpWalkBorrowGuard {
2111 prior_len,
2112 _not_send: PhantomData,
2113 })
2114 }
2115
2116 pub fn cross_device(&self) -> bool {
2118 self.cross_any
2119 }
2120
2121 pub fn host_bounce_active(&self) -> bool {
2122 self.host_bounce || PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire)
2123 }
2124
2125 pub fn repeated_stage_device(&self) -> bool {
2128 let mut devices: Vec<_> = self.stages.iter().map(|stage| stage.dev).collect();
2129 devices.sort_unstable();
2130 devices.dedup();
2131 devices.len() != self.stages.len()
2132 }
2133
2134 fn context_for_dev<'a>(
2135 &'a self,
2136 e: &'a Engine,
2137 dev: usize,
2138 ) -> Result<&'a Arc<CudaContext>, Box<dyn std::error::Error>> {
2139 if dev == e.ctx().ordinal() {
2140 return Ok(e.ctx());
2141 }
2142 self.stages
2143 .iter()
2144 .find(|stage| stage.dev == dev)
2145 .map(|stage| &stage.ctx)
2146 .ok_or_else(|| format!("PP peer probe has no CUDA context for dev{dev}").into())
2147 }
2148
2149 fn enable_probe_peer_access(
2150 &self,
2151 e: &Engine,
2152 pairs: &[(usize, usize)],
2153 ) -> Result<Vec<(usize, usize)>, Box<dyn std::error::Error>> {
2154 let mut enabled = Vec::new();
2155 for &(src_dev, dst_dev) in pairs {
2156 let enable = (|| -> Result<(), Box<dyn std::error::Error>> {
2157 let src_ctx = self.context_for_dev(e, src_dev)?;
2158 let dst_ctx = self.context_for_dev(e, dst_dev)?;
2159 src_ctx.bind_to_thread()?;
2160 let rc = unsafe { cudarc::driver::sys::cuCtxEnablePeerAccess(dst_ctx.cu_ctx(), 0) };
2161 use cudarc::driver::sys::cudaError_enum as E;
2162 if rc == E::CUDA_SUCCESS || rc == E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
2163 Ok(())
2164 } else {
2165 Err(format!("{rc:?}").into())
2166 }
2167 })();
2168 if let Err(err) = enable {
2169 eprintln!(
2170 "[pp] peer byte-integrity probe could not enable \
2171 dev{src_dev}->dev{dst_dev}: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
2172 );
2173 } else {
2174 enabled.push((src_dev, dst_dev));
2175 }
2176 }
2177 Ok(enabled)
2178 }
2179
2180 fn disable_probe_peer_access(
2181 &self,
2182 e: &Engine,
2183 pairs: &[(usize, usize)],
2184 ) -> Result<(), Box<dyn std::error::Error>> {
2185 let mut failures = Vec::new();
2186 for &(src_dev, dst_dev) in pairs {
2187 let disable = (|| -> Result<(), Box<dyn std::error::Error>> {
2188 let src_ctx = self.context_for_dev(e, src_dev)?;
2189 let dst_ctx = self.context_for_dev(e, dst_dev)?;
2190 src_ctx.bind_to_thread()?;
2191 let rc = unsafe { cudarc::driver::sys::cuCtxDisablePeerAccess(dst_ctx.cu_ctx()) };
2192 use cudarc::driver::sys::cudaError_enum as E;
2193 if rc == E::CUDA_SUCCESS || rc == E::CUDA_ERROR_PEER_ACCESS_NOT_ENABLED {
2194 Ok(())
2195 } else {
2196 Err(format!("{rc:?}").into())
2197 }
2198 })();
2199 if let Err(err) = disable {
2200 failures.push(format!("dev{src_dev}->dev{dst_dev}: {err}"));
2201 }
2202 }
2203 e.ctx().bind_to_thread()?;
2204 if failures.is_empty() {
2205 eprintln!(
2206 "[pp] peer byte-integrity probe teardown: disabled {} diagnostic pair(s); \
2207 host-bounce serving has no probe-enabled peer access",
2208 pairs.len(),
2209 );
2210 Ok(())
2211 } else {
2212 Err(format!(
2213 "PP peer probe could not disable diagnostic peer access ({}); \
2214 refusing host-bounce serving",
2215 failures.join(", "),
2216 )
2217 .into())
2218 }
2219 }
2220
2221 fn grant_probe_pool_access(
2222 &self,
2223 e: &Engine,
2224 pairs: &[(usize, usize)],
2225 ) -> Result<Vec<(usize, usize)>, Box<dyn std::error::Error>> {
2226 let mut granted = Vec::new();
2227 for &(src_dev, dst_dev) in pairs {
2228 let grant = (|| -> Result<(), Box<dyn std::error::Error>> {
2229 self.context_for_dev(e, dst_dev)?.bind_to_thread()?;
2230 let dev = cudarc::driver::result::device::get(dst_dev as i32)?;
2231 let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
2232 unsafe {
2233 cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
2234 }
2235 let desc = cudarc::driver::sys::CUmemAccessDesc {
2236 location: cudarc::driver::sys::CUmemLocation {
2237 type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
2238 id: src_dev as i32,
2239 },
2240 flags:
2241 cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
2242 };
2243 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
2244 if rc == cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
2245 Ok(())
2246 } else {
2247 Err(format!("{rc:?}").into())
2248 }
2249 })();
2250 if let Err(err) = grant {
2251 eprintln!(
2252 "[pp] production-slot probe could not grant dev{src_dev} access to \
2253 dev{dst_dev}'s default pool: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
2254 );
2255 } else {
2256 granted.push((src_dev, dst_dev));
2257 }
2258 }
2259 Ok(granted)
2260 }
2261
2262 fn revoke_probe_pool_access(
2263 &self,
2264 e: &Engine,
2265 pairs: &[(usize, usize)],
2266 ) -> Result<(), Box<dyn std::error::Error>> {
2267 let mut failures = Vec::new();
2268 for &(src_dev, dst_dev) in pairs {
2269 let revoke = (|| -> Result<(), Box<dyn std::error::Error>> {
2270 self.context_for_dev(e, dst_dev)?.bind_to_thread()?;
2271 let dev = cudarc::driver::result::device::get(dst_dev as i32)?;
2272 let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
2273 unsafe {
2274 cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
2275 }
2276 let desc = cudarc::driver::sys::CUmemAccessDesc {
2277 location: cudarc::driver::sys::CUmemLocation {
2278 type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
2279 id: src_dev as i32,
2280 },
2281 flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_NONE,
2282 };
2283 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
2284 if rc == cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
2285 Ok(())
2286 } else {
2287 Err(format!("{rc:?}").into())
2288 }
2289 })();
2290 if let Err(err) = revoke {
2291 failures.push(format!("dev{src_dev}->dev{dst_dev}: {err}"));
2292 }
2293 }
2294 e.ctx().bind_to_thread()?;
2295 if failures.is_empty() {
2296 Ok(())
2297 } else {
2298 Err(format!(
2299 "PP peer probe could not revoke diagnostic pool access ({}); \
2300 refusing host-bounce serving",
2301 failures.join(", "),
2302 )
2303 .into())
2304 }
2305 }
2306
2307 fn run_host_bounce_legacy_probe(&self, e: &Engine) -> Result<(), Box<dyn std::error::Error>> {
2308 let enabled = self.enable_probe_peer_access(e, &self.peer_capable)?;
2309 let probe = run_peer_probe_pass(
2310 &self.stages,
2311 &enabled,
2312 true,
2313 "fixed-16KiB-legacy-preflight",
2314 PEER_PROBE_FIXED_BYTES,
2315 );
2316 let disable = self.disable_probe_peer_access(e, &enabled);
2317 disable?;
2318 probe
2319 }
2320
2321 fn new_peer_probe_boundary(
2322 &self,
2323 src_stage: usize,
2324 dst_stage: usize,
2325 ) -> Result<BoundaryRt, Box<dyn std::error::Error>> {
2326 let tx = &self.stages[src_stage];
2327 let rx = &self.stages[dst_stage];
2328 let mk_slot = || -> Result<BoundarySlot, Box<dyn std::error::Error>> {
2329 Ok(BoundarySlot {
2330 buf: Mutex::new(None),
2331 ev_tx: tx.ctx.new_event(None)?,
2332 ev_rx: rx.ctx.new_event(None)?,
2333 })
2334 };
2335 Ok(BoundaryRt {
2336 slots: [mk_slot()?, mk_slot()?],
2337 step: AtomicUsize::new(0),
2338 cross: tx.dev != rx.dev,
2339 })
2340 }
2341
2342 fn production_probe_readback(
2343 &self,
2344 path: BoundaryPath,
2345 boundary: &BoundaryRt,
2346 expected: &[u8],
2347 n: usize,
2348 slot_idx: usize,
2349 ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
2350 debug_assert_eq!(expected.len(), n * std::mem::size_of::<f32>());
2351 let host = peer_probe_bytes_to_f32(expected);
2352 let poison_bytes: Vec<u8> = expected.iter().map(|byte| !byte).collect();
2353 let poison = peer_probe_bytes_to_f32(&poison_bytes);
2354 let src = &self.stages[path.src_stage];
2355 let dst = &self.stages[path.dst_stage];
2356
2357 dst.ctx.bind_to_thread()?;
2360 let poison_buf = dst.stream.clone_htod(&poison)?;
2361 dst.stream.synchronize()?;
2362 let replaced = boundary.slots[slot_idx]
2363 .buf
2364 .lock()
2365 .unwrap()
2366 .replace(poison_buf);
2367 drop(replaced);
2368 dst.stream.synchronize()?;
2369
2370 src.ctx.bind_to_thread()?;
2371 let x = src.stream.clone_htod(&host)?;
2372 self.tx_slot_path(path, boundary, &x, n, slot_idx)?;
2373
2374 dst.ctx.bind_to_thread()?;
2375 let work = self.rx_slot_path(path, boundary, slot_idx, n)?;
2376 let back = dst.stream.clone_dtoh(&work)?;
2377 dst.stream.synchronize()?;
2378 Ok(peer_probe_f32_to_bytes(&back))
2379 }
2380
2381 fn clear_peer_probe_boundary(
2382 &self,
2383 boundary: &BoundaryRt,
2384 src_stage: usize,
2385 dst_stage: usize,
2386 ) -> Result<(), Box<dyn std::error::Error>> {
2387 self.stages[dst_stage].ctx.bind_to_thread()?;
2388 for slot in &boundary.slots {
2389 let buffer = slot.buf.lock().unwrap().take();
2390 drop(buffer);
2391 }
2392 self.stages[src_stage].stream.synchronize()?;
2393 self.stages[dst_stage].stream.synchronize()?;
2394 Ok(())
2395 }
2396
2397 fn run_production_peer_probe_widths(
2398 &self,
2399 enabled_pairs: &[(usize, usize)],
2400 host_bounce: bool,
2401 n_embd: usize,
2402 widths: &[usize],
2403 ) -> Result<(), Box<dyn std::error::Error>> {
2404 let started = std::time::Instant::now();
2405 let mut copies = 0usize;
2406 let mut skipped = 0usize;
2407 let mut total_mismatches = 0usize;
2408 let mut largest_clean_payload = 0usize;
2409
2410 for boundary_idx in 0..self.stages.len() - 1 {
2411 if self.stages[boundary_idx].dev == self.stages[boundary_idx + 1].dev {
2412 continue;
2413 }
2414 for (src_stage, dst_stage) in [
2415 (boundary_idx, boundary_idx + 1),
2416 (boundary_idx + 1, boundary_idx),
2417 ] {
2418 let src_dev = self.stages[src_stage].dev;
2419 let dst_dev = self.stages[dst_stage].dev;
2420 if !enabled_pairs.contains(&(src_dev, dst_dev)) {
2421 if host_bounce {
2422 skipped += widths.len();
2423 eprintln!(
2424 "[pp] production-slot peer probe SKIP: boundary={boundary_idx} \
2425 dev{src_dev}->dev{dst_dev} widths_tokens={:?} \
2426 (peer or pool access unavailable; MEMRA_PP_HOST_BOUNCE=1 remains \
2427 fail-safe)",
2428 widths,
2429 );
2430 continue;
2431 }
2432 return Err(format!(
2433 "PP production-slot peer probe cannot run boundary={boundary_idx} \
2434 dev{src_dev}->dev{dst_dev}: peer/pool access is not enabled"
2435 )
2436 .into());
2437 }
2438
2439 let probe_boundary = self.new_peer_probe_boundary(src_stage, dst_stage)?;
2440 let path = BoundaryPath {
2441 boundary: boundary_idx,
2442 src_stage,
2443 dst_stage,
2444 transport: BoundaryTransport::Peer,
2445 };
2446 let mut direction_copies = 0usize;
2447 let mut direction_skipped = 0usize;
2448 let mut direction_mismatches = 0usize;
2449 let mut direction_largest_clean = 0usize;
2450 let mut failure = None;
2451
2452 for (width_idx, tokens) in widths.iter().copied().enumerate() {
2453 let n = n_embd.checked_mul(tokens).ok_or_else(|| {
2454 format!(
2455 "PP production-slot probe element count overflows for \
2456 n_embd={n_embd} tokens={tokens}"
2457 )
2458 })?;
2459 let bytes = n.checked_mul(std::mem::size_of::<f32>()).ok_or_else(|| {
2460 format!(
2461 "PP production-slot probe byte count overflows for \
2462 n_embd={n_embd} tokens={tokens}"
2463 )
2464 })?;
2465 let expected = peer_probe_pattern(bytes, boundary_idx, src_dev, dst_dev);
2466 let readback = match self.production_probe_readback(
2467 path,
2468 &probe_boundary,
2469 &expected,
2470 n,
2471 width_idx % 2,
2472 ) {
2473 Ok(readback) => readback,
2474 Err(err) if host_bounce => {
2475 skipped += 1;
2476 direction_skipped += 1;
2477 eprintln!(
2478 "[pp] production-slot peer probe ERROR: \
2479 boundary={boundary_idx} dev{src_dev}->dev{dst_dev} \
2480 tokens={tokens} bytes={bytes}: {err}; \
2481 MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path"
2482 );
2483 continue;
2484 }
2485 Err(err) => {
2486 failure = Some(format!(
2487 "PP production-slot peer probe FAILED: \
2488 boundary={boundary_idx} dev{src_dev}->dev{dst_dev} \
2489 tokens={tokens} bytes={bytes}: {err}; refusing native P2P \
2490 (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
2491 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer \
2492 transport)"
2493 ));
2494 break;
2495 }
2496 };
2497 copies += 1;
2498 direction_copies += 1;
2499 let mismatches = peer_probe_mismatch_count(&expected, &readback);
2500 if mismatches == 0 {
2501 largest_clean_payload = largest_clean_payload.max(bytes);
2502 direction_largest_clean = direction_largest_clean.max(bytes);
2503 } else if host_bounce {
2504 total_mismatches += mismatches;
2505 direction_mismatches += mismatches;
2506 eprintln!(
2507 "[pp] production-slot peer probe CORRUPTION: \
2508 boundary={boundary_idx} dev{src_dev}->dev{dst_dev} tokens={tokens} \
2509 bytes={bytes} mismatches={mismatches}; MEMRA_PP_HOST_BOUNCE=1, \
2510 proceeding on the host-staged path"
2511 );
2512 } else {
2513 failure = Some(format!(
2514 "PP production-slot peer probe FAILED: boundary={boundary_idx} \
2515 dev{src_dev}->dev{dst_dev} tokens={tokens} bytes={bytes}: \
2516 {mismatches} mismatched byte(s); refusing native P2P \
2517 (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
2518 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)"
2519 ));
2520 break;
2521 }
2522 }
2523
2524 self.clear_peer_probe_boundary(&probe_boundary, src_stage, dst_stage)?;
2525 if let Some(err) = failure {
2526 return Err(err.into());
2527 }
2528 eprintln!(
2529 "[pp] production-slot peer probe direction: boundary={boundary_idx} \
2530 dev{src_dev}->dev{dst_dev} copies={direction_copies} \
2531 skipped={direction_skipped} mismatches={direction_mismatches} \
2532 largest_clean_payload_bytes={direction_largest_clean}"
2533 );
2534 }
2535 }
2536
2537 let status = if total_mismatches > 0 {
2538 "BOUNCE"
2539 } else if skipped > 0 && copies > 0 {
2540 "PARTIAL"
2541 } else if skipped > 0 {
2542 "SKIP"
2543 } else {
2544 "PASS"
2545 };
2546 eprintln!(
2547 "[pp] production-slot peer probe {status}: widths_tokens={:?} copies={copies} \
2548 skipped={skipped} mismatches={total_mismatches} \
2549 largest_clean_payload_bytes={largest_clean_payload} elapsed_ms={:.3}",
2550 widths,
2551 started.elapsed().as_secs_f64() * 1e3,
2552 );
2553 Ok(())
2554 }
2555
2556 fn run_production_peer_probe(
2557 &self,
2558 enabled_pairs: &[(usize, usize)],
2559 host_bounce: bool,
2560 n_embd: usize,
2561 ) -> Result<(), Box<dyn std::error::Error>> {
2562 self.run_production_peer_probe_widths(
2563 enabled_pairs,
2564 host_bounce,
2565 n_embd,
2566 &PEER_PROBE_TOKEN_WIDTHS,
2567 )
2568 }
2569
2570 fn run_host_bounce_production_probe(
2571 &self,
2572 e: &Engine,
2573 n_embd: usize,
2574 ) -> Result<(), Box<dyn std::error::Error>> {
2575 let enabled = self.enable_probe_peer_access(e, &self.peer_capable)?;
2576 let granted = self.grant_probe_pool_access(e, &enabled)?;
2577 let probe = self.run_production_peer_probe(&granted, true, n_embd);
2578 let revoke = self.revoke_probe_pool_access(e, &granted);
2584 let disable = self.disable_probe_peer_access(e, &enabled);
2585 probe?;
2586 revoke?;
2587 disable?;
2588 Ok(())
2589 }
2590
2591 fn init_peer_probe_geometry(
2592 &self,
2593 e: &Engine,
2594 n_embd: usize,
2595 ) -> Result<(), Box<dyn std::error::Error>> {
2596 if !self.peer_probe || !self.cross_any {
2597 return Ok(());
2598 }
2599 let bytes = n_embd
2600 .checked_mul(std::mem::size_of::<f32>())
2601 .ok_or_else(|| format!("PP boundary-slot byte count overflows for n_embd={n_embd}"))?;
2602 let result = self.peer_probe_geometry.get_or_init(|| {
2603 let probe = if self.host_bounce_active() {
2604 self.run_host_bounce_production_probe(e, n_embd)
2605 } else {
2606 self.run_production_peer_probe(&self.peer_capable, false, n_embd)
2607 };
2608 let restore = e.ctx().bind_to_thread();
2609 match (probe, restore) {
2610 (Ok(()), Ok(())) => Ok(bytes),
2611 (Err(err), _) => Err(err.to_string()),
2612 (_, Err(err)) => Err(err.to_string()),
2613 }
2614 });
2615 let probed = result
2616 .as_ref()
2617 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
2618 if *probed != bytes {
2619 return Err(format!(
2620 "peer probe initialized for boundary-slot bytes={probed} but model requests \
2621 bytes={bytes}; one PP runtime supports one model geometry per process"
2622 )
2623 .into());
2624 }
2625 Ok(())
2626 }
2627
2628 fn init_host_bounce_staging(
2629 &self,
2630 e: &Engine,
2631 n_embd: usize,
2632 ) -> Result<(), Box<dyn std::error::Error>> {
2633 if !self.cross_any {
2634 return Ok(());
2635 }
2636 e.ctx().bind_to_thread()?;
2637 let result = self.bounce.get_or_init(|| {
2638 HostBounceRt::new(n_embd, &self.boundaries)
2639 .inspect(|rt| {
2640 let bytes = rt.capacity * std::mem::size_of::<f32>();
2641 eprintln!(
2642 "[pp] host-bounce staging ready: n_embd={n_embd} max_tokens={} \
2643 slot_bytes={bytes} slots_per_cross_boundary=2",
2644 crate::cache::PRIME_CHUNK_MAX_TOKENS,
2645 );
2646 })
2647 .map_err(|err| err.to_string())
2648 });
2649 let bounce = result
2650 .as_ref()
2651 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
2652 if bounce.n_embd != n_embd {
2653 return Err(format!(
2654 "host-bounce runtime initialized for n_embd={} but model requests n_embd={n_embd}; \
2655 one PP runtime supports one model geometry per process",
2656 bounce.n_embd,
2657 )
2658 .into());
2659 }
2660 Ok(())
2661 }
2662
2663 fn validate_host_bounce_staging(
2667 &self,
2668 e: &Engine,
2669 n_embd: usize,
2670 ) -> Result<(), Box<dyn std::error::Error>> {
2671 let bytes = n_embd
2672 .checked_mul(std::mem::size_of::<f32>())
2673 .ok_or_else(|| {
2674 format!("host-bounce validation byte count overflows for n_embd={n_embd}")
2675 })?;
2676 for boundary_idx in 0..self.stages.len() - 1 {
2677 if !self.boundaries[boundary_idx].cross {
2678 continue;
2679 }
2680 let src_stage = boundary_idx;
2681 let dst_stage = boundary_idx + 1;
2682 let probe_boundary = self.new_peer_probe_boundary(src_stage, dst_stage)?;
2683 let path = BoundaryPath {
2684 boundary: boundary_idx,
2685 src_stage,
2686 dst_stage,
2687 transport: BoundaryTransport::HostBounce,
2688 };
2689 let expected = peer_probe_pattern(
2690 bytes,
2691 boundary_idx,
2692 self.stages[src_stage].dev,
2693 self.stages[dst_stage].dev,
2694 );
2695 let readback =
2696 self.production_probe_readback(path, &probe_boundary, &expected, n_embd, 0);
2697 let clear = self.clear_peer_probe_boundary(&probe_boundary, src_stage, dst_stage);
2698 let readback = readback?;
2699 clear?;
2700 let mismatches = peer_probe_mismatch_count(&expected, &readback);
2701 if mismatches > 0 {
2702 return Err(format!(
2703 "runtime host-bounce staging validation FAILED: boundary={boundary_idx} \
2704 bytes={bytes} mismatches={mismatches}"
2705 )
2706 .into());
2707 }
2708 }
2709 e.ctx().bind_to_thread()?;
2710 eprintln!(
2711 "[pp] runtime host-bounce staging validation PASS: row_bytes={bytes} \
2712 cross_boundaries={}",
2713 self.boundaries
2714 .iter()
2715 .filter(|boundary| boundary.cross)
2716 .count(),
2717 );
2718 Ok(())
2719 }
2720
2721 fn arm_runtime_host_bounce(
2722 &self,
2723 e: &Engine,
2724 row_bytes: usize,
2725 ) -> Result<(), Box<dyn std::error::Error>> {
2726 if row_bytes == 0 || !row_bytes.is_multiple_of(std::mem::size_of::<f32>()) {
2727 return Err(format!(
2728 "runtime host-bounce cannot recover n_embd from row_bytes={row_bytes}"
2729 )
2730 .into());
2731 }
2732 let n_embd = row_bytes / std::mem::size_of::<f32>();
2733 self.init_host_bounce_staging(e, n_embd)?;
2734 self.validate_host_bounce_staging(e, n_embd)
2735 }
2736
2737 pub fn init_boundary_transport(
2743 &self,
2744 e: &Engine,
2745 n_embd: usize,
2746 ) -> Result<(), Box<dyn std::error::Error>> {
2747 if PEER_RUNTIME_PROBE_FAILED.load(Ordering::Acquire)
2748 && !PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire)
2749 {
2750 return Err(
2751 "PP runtime peer byte-integrity probe previously failed; refusing native P2P \
2752 reuse because runtime host-bounce staging could not be armed"
2753 .into(),
2754 );
2755 }
2756 self.init_peer_probe_geometry(e, n_embd)?;
2757 if !self.host_bounce_active() || !self.cross_any {
2758 return Ok(());
2759 }
2760 self.init_host_bounce_staging(e, n_embd)
2761 }
2762
2763 fn service_runtime_peer_probe(
2768 &self,
2769 e: &Engine,
2770 scheduler_idle: bool,
2771 probe_allowed: bool,
2772 ) -> Result<RuntimePeerProbeStatus, Box<dyn std::error::Error>> {
2773 if !self.peer_probe || !self.cross_any || self.host_bounce_active() {
2774 return Ok(RuntimePeerProbeStatus::NotRun);
2775 }
2776 if PEER_RUNTIME_PROBE_FAILED.load(Ordering::Acquire) {
2777 return Err(
2778 "PP runtime peer byte-integrity probe previously failed; native P2P is latched off"
2779 .into(),
2780 );
2781 }
2782 let row_bytes = match self.peer_probe_geometry.get() {
2783 Some(Ok(bytes)) => *bytes,
2784 _ => return Ok(RuntimePeerProbeStatus::NotRun),
2785 };
2786
2787 let copies = PEER_BOUNDARY_COPIES.load(Ordering::Relaxed);
2788 let (width_index, tokens) = loop {
2789 let next_probe_copy = std::array::from_fn(|width_index| {
2790 PEER_RUNTIME_NEXT_PROBE_COPY[width_index].load(Ordering::Relaxed)
2791 });
2792 let measured_cost_ns = std::array::from_fn(|width_index| {
2793 PEER_RUNTIME_PROBE_MAX_COST_NS[width_index].load(Ordering::Relaxed)
2794 });
2795 let Some(candidate) = runtime_peer_probe_candidate(
2796 copies,
2797 next_probe_copy,
2798 measured_cost_ns,
2799 scheduler_idle,
2800 ) else {
2801 return Ok(RuntimePeerProbeStatus::NotRun);
2802 };
2803 if !probe_allowed {
2808 return Ok(RuntimePeerProbeStatus::Deferred);
2809 }
2810 let due = next_probe_copy[candidate.0];
2811 let next = runtime_peer_probe_next_copy(due, copies);
2812 if PEER_RUNTIME_NEXT_PROBE_COPY[candidate.0]
2813 .compare_exchange(due, next, Ordering::AcqRel, Ordering::Relaxed)
2814 .is_ok()
2815 {
2816 break candidate;
2817 }
2818 };
2819 let probe_index = PEER_RUNTIME_PROBES.fetch_add(1, Ordering::Relaxed);
2820 let probe_bytes = row_bytes.checked_mul(tokens);
2821 let started = std::time::Instant::now();
2822 let probe = match probe_bytes {
2823 Some(_) => self.run_production_peer_probe_widths(
2824 &self.peer_capable,
2825 false,
2826 row_bytes / std::mem::size_of::<f32>(),
2827 &[tokens],
2828 ),
2829 None => Err(format!(
2830 "PP runtime peer probe byte count overflows for row_bytes={row_bytes} \
2831 tokens={tokens}"
2832 )
2833 .into()),
2834 };
2835 let restore = e.ctx().bind_to_thread();
2836 let elapsed_ns = started.elapsed().as_nanos().min(u64::MAX as u128) as u64;
2837 let previous_max =
2838 PEER_RUNTIME_PROBE_MAX_COST_NS[width_index].fetch_max(elapsed_ns, Ordering::Relaxed);
2839 let verdict = match (probe, restore) {
2840 (Ok(()), Ok(())) => Ok(()),
2841 (Err(err), _) => Err(err.to_string()),
2842 (_, Err(err)) => Err(err.to_string()),
2843 };
2844 if let Err(err) = verdict {
2845 PEER_RUNTIME_PROBE_FAILURES.fetch_add(1, Ordering::Relaxed);
2846 let arm = latch_runtime_host_bounce(
2847 &PEER_RUNTIME_PROBE_FAILED,
2848 &PEER_RUNTIME_HOST_BOUNCE,
2849 || {
2850 self.arm_runtime_host_bounce(e, row_bytes)
2851 .map_err(|arm_err| arm_err.to_string())
2852 },
2853 );
2854 if let Err(arm_err) = arm {
2855 let message = format!(
2856 "PP runtime peer byte-integrity re-probe FAILED after \
2857 boundary_copies={copies} rung={}/{} tokens={tokens}: {err}; native P2P is \
2858 latched off and host-bounce staging could not be armed: {arm_err}",
2859 width_index + 1,
2860 PEER_PROBE_TOKEN_WIDTHS.len(),
2861 );
2862 eprintln!("[pp] SECURITY RED: {message}; worker must stop");
2863 return Err(message.into());
2864 }
2865 eprintln!(
2866 "[pp] SECURITY RED: PP runtime peer byte-integrity re-probe FAILED after \
2867 boundary_copies={copies} rung={}/{} tokens={tokens}: {err}; native P2P is \
2868 latched off and the live transport DEGRADED to validated host bounce for the \
2869 remainder of this process",
2870 width_index + 1,
2871 PEER_PROBE_TOKEN_WIDTHS.len(),
2872 );
2873 return Ok(RuntimePeerProbeStatus::DegradedToHostBounce);
2874 }
2875 if width_index + 1 != PEER_PROBE_TOKEN_WIDTHS.len()
2876 && previous_max <= PEER_RUNTIME_PROBE_BUDGET_NS
2877 && elapsed_ns > PEER_RUNTIME_PROBE_BUDGET_NS
2878 {
2879 eprintln!(
2880 "[pp] runtime peer re-probe rung exceeded the {:.3}ms owner-thread budget: \
2881 tokens={tokens} measured_ms={:.3}; future runs are idle-only",
2882 PEER_RUNTIME_PROBE_BUDGET_NS as f64 / 1e6,
2883 elapsed_ns as f64 / 1e6,
2884 );
2885 }
2886 eprintln!(
2887 "[pp] runtime peer byte-integrity re-probe PASS: \
2888 boundary_copies={copies} interval_copies={PEER_RUNTIME_PROBE_INTERVAL_COPIES} \
2889 rung={}/{} tokens={tokens} bytes={} probe_index={probe_index} elapsed_ms={:.3} \
2890 scheduler_idle={scheduler_idle}",
2891 width_index + 1,
2892 PEER_PROBE_TOKEN_WIDTHS.len(),
2893 probe_bytes.unwrap(),
2894 elapsed_ns as f64 / 1e6,
2895 );
2896 Ok(RuntimePeerProbeStatus::Passed)
2897 }
2898
2899 fn bounce_rt(&self) -> Result<&HostBounceRt, Box<dyn std::error::Error>> {
2900 self.bounce
2901 .get()
2902 .ok_or_else(|| -> Box<dyn std::error::Error> {
2903 "MEMRA_PP_HOST_BOUNCE=1 staging was not initialized from model geometry".into()
2904 })?
2905 .as_ref()
2906 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })
2907 }
2908
2909 pub fn engine<'a>(&'a self, s: usize, primary: &'a Engine) -> &'a Engine {
2912 self.stages[s].engine.as_ref().unwrap_or(primary)
2913 }
2914
2915 pub fn bind_stage(&self, s: usize) -> Result<(), Box<dyn std::error::Error>> {
2917 self.stages[s].ctx.bind_to_thread()?;
2918 Ok(())
2919 }
2920
2921 pub fn enter(&self, s: usize) -> memra_runtime::StreamOverride {
2924 memra_runtime::push_stream_override(
2925 self.stages[s].stream.clone(),
2926 self.stages[s].blas.clone(),
2927 )
2928 }
2929
2930 pub fn prepare_overlap_slots(
2936 &self,
2937 b: usize,
2938 n: usize,
2939 ) -> Result<(), Box<dyn std::error::Error>> {
2940 let bd = &self.boundaries[b];
2941 let s_rx = &self.stages[b + 1].stream;
2942 let mut grew = false;
2943 for sl in &bd.slots {
2944 let mut guard = sl.buf.lock().unwrap();
2945 if guard.as_ref().map(|bf| bf.len() < n).unwrap_or(true) {
2946 *guard = Some(s_rx.alloc_zeros::<f32>(n)?);
2947 grew = true;
2948 }
2949 }
2950 if grew {
2951 s_rx.synchronize()?;
2952 }
2953 Ok(())
2954 }
2955
2956 pub fn boundary_slot_growth_bytes(
2960 &self,
2961 b: usize,
2962 n: usize,
2963 ) -> Result<usize, Box<dyn std::error::Error>> {
2964 let boundary = self
2965 .boundaries
2966 .get(b)
2967 .ok_or_else(|| format!("PP boundary {b} is outside the runtime"))?;
2968 let mut current = [0usize; 2];
2969 for (index, slot) in boundary.slots.iter().enumerate() {
2970 let guard = slot
2971 .buf
2972 .lock()
2973 .map_err(|_| format!("PP boundary {b} slot lock is poisoned"))?;
2974 current[index] = guard.as_ref().map_or(0, CudaSlice::len);
2975 }
2976 let elements = boundary_slot_growth_elements(current, n);
2977 Ok(elements.saturating_mul(std::mem::size_of::<f32>()))
2978 }
2979
2980 pub fn tx(
2994 &self,
2995 b: usize,
2996 x: &CudaSlice<f32>,
2997 n: usize,
2998 ) -> Result<usize, Box<dyn std::error::Error>> {
2999 assert_eq!(x.len(), n, "pp tx: residual length mismatch");
3000 let bd = &self.boundaries[b];
3001 let slot_idx = if pp2_overlap() {
3002 bd.step.fetch_add(1, Ordering::Relaxed) % 2
3003 } else {
3004 0
3005 };
3006 self.tx_slot(b, x, n, slot_idx)
3007 }
3008
3009 pub fn tx_pipelined(
3013 &self,
3014 b: usize,
3015 x: &CudaSlice<f32>,
3016 n: usize,
3017 ) -> Result<usize, Box<dyn std::error::Error>> {
3018 assert_eq!(x.len(), n, "pp tx: residual length mismatch");
3019 let slot_idx = self.boundaries[b].step.fetch_add(1, Ordering::Relaxed) % 2;
3020 self.tx_slot(b, x, n, slot_idx)
3021 }
3022
3023 fn tx_slot(
3024 &self,
3025 b: usize,
3026 x: &CudaSlice<f32>,
3027 n: usize,
3028 slot_idx: usize,
3029 ) -> Result<usize, Box<dyn std::error::Error>> {
3030 let bd = &self.boundaries[b];
3031 let path = BoundaryPath {
3032 boundary: b,
3033 src_stage: b,
3034 dst_stage: b + 1,
3035 transport: boundary_transport(bd.cross, self.host_bounce_active()),
3036 };
3037 let copied_slot = self.tx_slot_path(path, bd, x, n, slot_idx)?;
3038 if path.transport == BoundaryTransport::Peer {
3039 PEER_BOUNDARY_COPIES.fetch_add(1, Ordering::Relaxed);
3040 }
3041 Ok(copied_slot)
3042 }
3043
3044 fn tx_slot_path(
3045 &self,
3046 path: BoundaryPath,
3047 bd: &BoundaryRt,
3048 x: &CudaSlice<f32>,
3049 n: usize,
3050 slot_idx: usize,
3051 ) -> Result<usize, Box<dyn std::error::Error>> {
3052 debug_assert!(slot_idx < 2);
3053 let sl = &bd.slots[slot_idx];
3054 let s_tx = &self.stages[path.src_stage].stream;
3055 s_tx.wait(&sl.ev_rx)?;
3056 let mut guard = sl.buf.lock().unwrap();
3057 if guard.as_ref().map(|bf| bf.len() < n).unwrap_or(true) {
3058 let s_rx = &self.stages[path.dst_stage].stream;
3060 *guard = Some(s_rx.alloc_zeros::<f32>(n)?);
3061 s_rx.synchronize()?;
3071 }
3072 let buf = guard.as_mut().unwrap();
3073 match path.transport {
3074 BoundaryTransport::Local => s_tx.memcpy_dtod(x, buf)?,
3075 BoundaryTransport::HostBounce => {
3076 debug_assert_eq!(path.src_stage, path.boundary);
3077 debug_assert_eq!(path.dst_stage, path.boundary + 1);
3078 let bounce = self.bounce_rt()?;
3079 if n > bounce.capacity {
3080 return Err(format!(
3081 "pp host-bounce payload {n} exceeds geometry-sized capacity {} \
3082 (n_embd={}, max prime tokens={})",
3083 bounce.capacity,
3084 bounce.n_embd,
3085 crate::cache::PRIME_CHUNK_MAX_TOKENS,
3086 )
3087 .into());
3088 }
3089 let mut host = bounce.slot(path.boundary, slot_idx)?.lock().unwrap();
3090 s_tx.memcpy_dtoh(x, host.prefix_mut(n))?;
3094 }
3095 BoundaryTransport::Peer => {
3096 use cudarc::driver::{DevicePtr, DevicePtrMut};
3099 let (sp, _g0) = x.device_ptr(s_tx);
3100 let (dp, _g1) = buf.device_ptr_mut(s_tx);
3101 self.stages[path.src_stage].ctx.bind_to_thread()?;
3102 unsafe {
3103 cudarc::driver::result::memcpy_peer_async(
3104 self.stages[path.dst_stage].ctx.cu_ctx(),
3105 dp,
3106 self.stages[path.src_stage].ctx.cu_ctx(),
3107 sp,
3108 n * std::mem::size_of::<f32>(),
3109 s_tx.cu_stream(),
3110 )?;
3111 }
3112 }
3113 }
3114 sl.ev_tx.record(s_tx)?;
3115 Ok(slot_idx)
3116 }
3117
3118 pub fn rx(
3123 &self,
3124 b: usize,
3125 slot_idx: usize,
3126 n: usize,
3127 ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3128 let bd = &self.boundaries[b];
3129 let path = BoundaryPath {
3130 boundary: b,
3131 src_stage: b,
3132 dst_stage: b + 1,
3133 transport: boundary_transport(bd.cross, self.host_bounce_active()),
3134 };
3135 self.rx_slot_path(path, bd, slot_idx, n)
3136 }
3137
3138 fn rx_slot_path(
3139 &self,
3140 path: BoundaryPath,
3141 bd: &BoundaryRt,
3142 slot_idx: usize,
3143 n: usize,
3144 ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3145 let sl = &bd.slots[slot_idx];
3146 let s_rx = &self.stages[path.dst_stage].stream;
3147 s_rx.wait(&sl.ev_tx)?;
3148 let mut guard = sl.buf.lock().unwrap();
3149 let buf = guard.as_mut().expect("pp rx before tx");
3150 assert!(
3151 buf.len() >= n,
3152 "pp rx: slot holds {} < requested {n}",
3153 buf.len()
3154 );
3155 if path.transport == BoundaryTransport::HostBounce {
3156 debug_assert_eq!(path.src_stage, path.boundary);
3157 debug_assert_eq!(path.dst_stage, path.boundary + 1);
3158 let bounce = self.bounce_rt()?;
3159 let host = bounce.slot(path.boundary, slot_idx)?.lock().unwrap();
3160 let mut dst = buf.slice_mut(0..n);
3161 s_rx.memcpy_htod(host.prefix(n), &mut dst)?;
3164 }
3165 let mut work = unsafe { s_rx.alloc::<f32>(n)? };
3168 s_rx.memcpy_dtod(&buf.slice(0..n), &mut work)?;
3172 sl.ev_rx.record(s_rx)?;
3173 Ok(work)
3174 }
3175
3176 pub fn publish_to(
3203 &self,
3204 s: usize,
3205 dst: &Arc<CudaStream>,
3206 ) -> Result<(), Box<dyn std::error::Error>> {
3207 let st = &self.stages[s];
3208 if Arc::ptr_eq(&st.stream, dst) {
3211 return Ok(());
3212 }
3213 let ev = st.ctx.new_event(None)?;
3214 ev.record(&st.stream)?;
3215 dst.wait(&ev)?;
3216 Ok(())
3217 }
3218
3219 pub fn fence_stages_behind(
3241 &self,
3242 src: &Arc<CudaStream>,
3243 ) -> Result<(), Box<dyn std::error::Error>> {
3244 let ev = src.context().new_event(None)?;
3245 ev.record(src)?;
3246 for st in &self.stages {
3247 if Arc::ptr_eq(&st.stream, src) {
3248 continue;
3249 }
3250 st.stream.wait(&ev)?;
3251 }
3252 Ok(())
3253 }
3254
3255 pub fn record_done(&self) -> Result<CudaEvent, Box<dyn std::error::Error>> {
3258 let last = &self.stages[self.stages.len() - 1];
3259 let ev = last.ctx.new_event(None)?;
3260 ev.record(&last.stream)?;
3261 Ok(ev)
3262 }
3263
3264 pub fn readback_stream(&self) -> &Arc<CudaStream> {
3266 &self.readback
3267 }
3268}
3269
3270pub fn service_runtime_peer_probe(
3273 e: &Engine,
3274 scheduler_idle: bool,
3275 probe_allowed: bool,
3276) -> Result<RuntimePeerProbeStatus, Box<dyn std::error::Error>> {
3277 let Some(rt) = RTN.get() else {
3278 return Ok(RuntimePeerProbeStatus::NotRun);
3279 };
3280 let rt = rt
3281 .as_ref()
3282 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
3283 rt.service_runtime_peer_probe(e, scheduler_idle, probe_allowed)
3284}
3285
3286pub struct PendingLogits {
3291 logits: CudaSlice<f32>,
3292 ev: CudaEvent,
3293 rb: Arc<CudaStream>,
3294 _walk: PpWalkLease,
3295}
3296
3297impl PendingLogits {
3298 pub(crate) fn new(
3299 logits: CudaSlice<f32>,
3300 ev: CudaEvent,
3301 rb: Arc<CudaStream>,
3302 walk: PpWalkLease,
3303 ) -> Self {
3304 PendingLogits {
3305 logits,
3306 ev,
3307 rb,
3308 _walk: walk,
3309 }
3310 }
3311
3312 pub fn wait(self) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3316 self.rb.wait(&self.ev)?;
3317 let host = self.rb.clone_dtoh(&self.logits)?;
3318 self.rb.synchronize()?;
3319 Ok(host)
3322 }
3323}
3324
3325pub fn init_model_transport(
3328 e: &Engine,
3329 cfg: &memra_gguf::config::ModelConfig,
3330 n_trunk: usize,
3331) -> Result<(), Box<dyn std::error::Error>> {
3332 if pp2_streams_off() || pp2_devices_env().is_none() || pp_cuts(n_trunk).is_none() {
3333 return Ok(());
3334 }
3335 PpNRt::get(e)?.init_boundary_transport(e, cfg.n_embd as usize)
3336}
3337
3338pub fn new_cache(
3345 e: &Engine,
3346 cfg: &memra_gguf::config::ModelConfig,
3347 max_ctx: usize,
3348) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3349 new_cache_inner(e, cfg, None, max_ctx)
3350}
3351
3352pub fn new_cache_planned(
3353 e: &Engine,
3354 cfg: &memra_gguf::config::ModelConfig,
3355 plan: &memra_gguf::model_plan::ModelPlan,
3356 max_ctx: usize,
3357) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3358 new_cache_inner(e, cfg, Some(plan), max_ctx)
3359}
3360
3361fn new_cache_inner(
3362 e: &Engine,
3363 cfg: &memra_gguf::config::ModelConfig,
3364 plan: Option<&memra_gguf::model_plan::ModelPlan>,
3365 max_ctx: usize,
3366) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3367 let n_trunk = (cfg.n_layer - cfg.nextn_predict_layers) as usize;
3368 if let Some(fence) = pp_cuts(n_trunk) {
3369 if pp2_devices_env().is_some() && !pp2_streams_off() {
3370 let rt = PpNRt::get(e)?;
3371 rt.init_boundary_transport(e, cfg.n_embd as usize)?;
3372 let n_st = fence.len() - 1;
3373 assert_eq!(
3374 rt.n_stages(),
3375 n_st,
3376 "PpNRt stage count {} != fence stages {n_st}",
3377 rt.n_stages()
3378 );
3379 rt.fence_stages_behind(&e.stream())?;
3388 let devs: Vec<&dyn memra_kv::KvDev> = (0..n_st)
3389 .map(|s| rt.engine(s, e) as &dyn memra_kv::KvDev)
3390 .collect();
3391 let cache = match plan {
3392 Some(plan) => {
3393 crate::cache::Cache::new_ppn_planned(&devs, &fence, cfg, plan, max_ctx)?
3394 }
3395 None => crate::cache::Cache::new_ppn(&devs, &fence, cfg, max_ctx)?,
3396 };
3397 sync_stages_after_load(e, n_trunk)?;
3398 return Ok(cache);
3399 }
3400 if !pp2_streams_off() {
3401 let cache = match plan {
3409 Some(plan) => crate::cache::Cache::new_planned(e, cfg, plan, max_ctx)?,
3410 None => crate::cache::Cache::new(e, cfg, max_ctx)?,
3411 };
3412 sync_stages_after_load(e, n_trunk)?;
3413 return Ok(cache);
3414 }
3415 }
3416 match plan {
3417 Some(plan) => crate::cache::Cache::new_planned(e, cfg, plan, max_ctx),
3418 None => crate::cache::Cache::new(e, cfg, max_ctx),
3419 }
3420}
3421
3422pub fn sync_stages_after_load(
3431 e: &Engine,
3432 n_trunk: usize,
3433) -> Result<(), Box<dyn std::error::Error>> {
3434 if pp2_streams_off() || pp_cuts(n_trunk).is_none() {
3435 return Ok(());
3436 }
3437 let rt = PpNRt::get(e)?;
3438 for s in 0..rt.n_stages() {
3439 rt.stages[s].ctx.bind_to_thread()?;
3440 unsafe {
3441 cudarc::driver::sys::cuCtxSynchronize().result()?;
3442 }
3443 }
3444 e.ctx().bind_to_thread()?;
3445 unsafe {
3446 cudarc::driver::sys::cuCtxSynchronize().result()?;
3447 }
3448 Ok(())
3449}
3450
3451pub fn layer_engine(
3457 e: &Engine,
3458 n_trunk: usize,
3459 il: usize,
3460) -> Result<&Engine, Box<dyn std::error::Error>> {
3461 if pp_shard_off() || pp2_devices_env().is_none() || pp2_streams_off() {
3462 return Ok(e);
3463 }
3464 let Some(fence) = pp_cuts(n_trunk) else {
3465 return Ok(e);
3466 };
3467 let rt = PpNRt::get(e)?;
3468 let s = stage_of(&fence, il.min(n_trunk - 1));
3469 Ok(rt.engine(s, e))
3470}
3471
3472#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3474pub(crate) enum TpRestoreRefusal {
3475 TargetAbsent,
3477 SourceAbsent,
3479 GrowTargetNotFresh,
3481 TokenGraphDoorOpen,
3484}
3485
3486#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3488pub(crate) enum TpRestore {
3489 Nothing,
3491 Rewind(usize),
3493 Grow(usize),
3495 DropMirror,
3499 Refuse(TpRestoreRefusal),
3500}
3501
3502pub(crate) fn tp_restore_plan(
3543 snap_len: Option<usize>,
3544 source_has_tp: Option<bool>,
3545 target_has_tp: bool,
3546 token_graph_door: bool,
3547) -> TpRestore {
3548 match (source_has_tp, snap_len) {
3549 (None, Some(len)) => {
3550 if target_has_tp {
3551 TpRestore::Rewind(len)
3552 } else {
3553 TpRestore::Refuse(TpRestoreRefusal::TargetAbsent)
3554 }
3555 }
3556 (None, None) => {
3557 if !target_has_tp {
3558 TpRestore::Nothing
3559 } else if token_graph_door {
3560 TpRestore::Refuse(TpRestoreRefusal::TokenGraphDoorOpen)
3561 } else {
3562 TpRestore::DropMirror
3563 }
3564 }
3565 (Some(source_has_tp), Some(len)) => {
3566 if !source_has_tp {
3567 TpRestore::Refuse(TpRestoreRefusal::SourceAbsent)
3568 } else if target_has_tp {
3569 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
3570 } else {
3571 TpRestore::Grow(len)
3572 }
3573 }
3574 (Some(_), None) => {
3575 if target_has_tp {
3576 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
3578 } else {
3579 TpRestore::Nothing
3584 }
3585 }
3586 }
3587}
3588
3589pub fn restore_cache_checkpoint(
3601 e: &Engine,
3602 model: &crate::hybrid::HybridModel,
3603 source: Option<&crate::cache::Cache>,
3604 target: &mut crate::cache::Cache,
3605 snap: &crate::cache::CacheSnapshot,
3606) -> Result<(), Box<dyn std::error::Error>> {
3607 target.ensure_usable("restore_cache_checkpoint target")?;
3608 if let Some(source) = source {
3609 source.ensure_usable("restore_cache_checkpoint source")?;
3610 }
3611 let cfg = &model.cfg;
3612 let n = target.kv.len();
3613 if target.recur.len() != n
3614 || target.tp_kv.len() != n
3615 || snap.kv_len.len() != n
3616 || snap.tp_kv_len.len() != n
3617 || snap.conv.len() != n
3618 || snap.ssm.len() != n
3619 || source.is_some_and(|s| s.kv.len() != n || s.recur.len() != n || s.tp_kv.len() != n)
3620 {
3621 return Err("checkpoint cache layer-count mismatch".into());
3622 }
3623 if snap.pos > target.max_ctx {
3624 return Err(format!(
3625 "checkpoint pos {} exceeds target capacity {}",
3626 snap.pos, target.max_ctx,
3627 )
3628 .into());
3629 }
3630
3631 let n_trunk = (cfg.n_layer - cfg.nextn_predict_layers) as usize;
3632 let token_graph_door = crate::tp::step_tp_graph_enabled().unwrap_or(false);
3634 let mut dropped_mirrors = 0usize;
3635 for il in 0..n {
3636 let owner = layer_engine(e, n_trunk, il)?;
3637 let src_kv = source.map(|s| &s.kv[il]);
3638 match (src_kv, target.kv[il].as_mut(), snap.kv_len[il]) {
3639 (Some(Some(src)), Some(dst), Some(len)) => {
3640 if len > src.len || len > target.max_ctx {
3641 return Err(format!(
3642 "checkpoint layer {il} len {len} exceeds source {} or target {}",
3643 src.len, target.max_ctx,
3644 )
3645 .into());
3646 }
3647 if src.kv_dim_k != dst.kv_dim_k
3648 || src.kv_dim_v != dst.kv_dim_v
3649 || src.k_tok_bytes != dst.k_tok_bytes
3650 || src.v_tok_bytes != dst.v_tok_bytes
3651 {
3652 return Err(format!("checkpoint KV layout mismatch at layer {il}").into());
3653 }
3654 match (&src.ring, dst.ring.as_ref()) {
3655 (Some(sring), Some(dring)) => {
3656 if dring.base() != 0 {
3662 return Err(format!(
3663 "checkpoint SWA restore at layer {il} requires a fresh target \
3664 ring (base {}, expected 0)",
3665 dring.base(),
3666 )
3667 .into());
3668 }
3669 let (new_base, phys) = sring.restore_plan(len).map_err(|e| {
3670 format!("checkpoint SWA restore refused at layer {il}: {e}")
3671 })?;
3672 let rows = phys.len();
3673 let kb = rows * src.k_tok_bytes;
3674 let vb = rows * src.v_tok_bytes;
3675 if kb > 0 {
3676 owner.copy_u8_range_into(
3677 &mut dst.k,
3678 0,
3679 &src.k,
3680 phys.start * src.k_tok_bytes,
3681 kb,
3682 )?;
3683 }
3684 if vb > 0 {
3685 owner.copy_u8_range_into(
3686 &mut dst.v,
3687 0,
3688 &src.v,
3689 phys.start * src.v_tok_bytes,
3690 vb,
3691 )?;
3692 }
3693 dst.ring
3694 .as_mut()
3695 .expect("ring presence checked above")
3696 .apply_rebase(new_base);
3697 if let Some(base_d) = dst.base_d.as_mut() {
3698 owner.set_i32_one(base_d, new_base as i32)?;
3699 }
3700 }
3701 (None, None) => {
3702 let kb = len * src.k_tok_bytes;
3703 let vb = len * src.v_tok_bytes;
3704 if kb > 0 {
3705 owner.copy_u8_into(&mut dst.k, 0, &src.k, kb)?;
3706 }
3707 if vb > 0 {
3708 owner.copy_u8_into(&mut dst.v, 0, &src.v, vb)?;
3709 }
3710 }
3711 _ => {
3712 return Err(
3713 format!("checkpoint ring/flat KV mismatch at layer {il}").into()
3714 );
3715 }
3716 }
3717 dst.len = len;
3718 owner.set_i32_one(&mut dst.len_d, len as i32)?;
3719 }
3720 (None, Some(dst), Some(len)) => {
3721 if len > dst.len || len > target.max_ctx {
3722 return Err(format!(
3723 "checkpoint layer {il} len {len} exceeds live {} or target {}",
3724 dst.len, target.max_ctx,
3725 )
3726 .into());
3727 }
3728 if let Some(ring) = &dst.ring
3729 && !ring.can_rewind_to(len)
3730 {
3731 return Err(format!(
3732 "checkpoint SWA rewind at layer {il} has been lapped \
3733 (len {len}, ring base {}); full re-prime required",
3734 ring.base(),
3735 )
3736 .into());
3737 }
3738 dst.len = len;
3739 owner.set_i32_one(&mut dst.len_d, len as i32)?;
3740 }
3741 (Some(None), None, None) | (None, None, None) => {}
3742 _ => return Err(format!("checkpoint KV kind mismatch at layer {il}").into()),
3743 }
3744
3745 match tp_restore_plan(
3746 snap.tp_kv_len[il],
3747 source.map(|s| s.tp_kv[il].is_some()),
3748 target.tp_kv[il].is_some(),
3749 token_graph_door,
3750 ) {
3751 TpRestore::Nothing => {}
3752 TpRestore::Rewind(len) => target.tp_kv[il]
3753 .as_mut()
3754 .expect("tp_restore_plan::Rewind implies a present target mirror")
3755 .rewind_to(len)?,
3756 TpRestore::Grow(len) => {
3757 let src = source
3758 .and_then(|s| s.tp_kv[il].as_ref())
3759 .expect("tp_restore_plan::Grow implies a present source mirror");
3760 let runtime = model.step_tp_runtime_for_layer(il).ok_or_else(|| {
3761 format!("checkpoint TP KV layer {il} has no distributed runtime")
3762 })?;
3763 let grown = runtime.grow_tp_kv_cache(src, target.max_ctx, len)?;
3764 target.tp_kv[il] = Some(grown);
3765 }
3766 TpRestore::DropMirror => {
3767 if target.tp_kv[il].take().is_some() {
3771 dropped_mirrors += 1;
3772 }
3773 }
3774 TpRestore::Refuse(reason) => {
3775 return Err(format!(
3776 "checkpoint TP KV restore refused at layer {il}: {} \
3777 (snap.tp_kv_len={:?}, snap.kv_len={:?}, snap.pos={}, \
3778 source_has_tp={:?}, target_has_tp={}, target_committed={})",
3779 match reason {
3780 TpRestoreRefusal::TargetAbsent =>
3781 "the snapshot recorded a distributed length but the target holds no \
3782 distributed cache to rewind",
3783 TpRestoreRefusal::SourceAbsent =>
3784 "the snapshot recorded a distributed length the parked source cannot \
3785 supply",
3786 TpRestoreRefusal::GrowTargetNotFresh =>
3787 "the freshly allocated grow target already holds a distributed cache",
3788 TpRestoreRefusal::TokenGraphDoorOpen =>
3789 "MEMRA_STEP_TP_GRAPH is open, and its model-level whole-token graph \
3790 bakes the rank-cache pointers, so the stale mirror cannot be freed",
3791 },
3792 snap.tp_kv_len[il],
3793 snap.kv_len[il],
3794 snap.pos,
3795 source.map(|s| s.tp_kv[il].is_some()),
3796 target.tp_kv[il].is_some(),
3797 target.tp_kv[il]
3798 .as_ref()
3799 .map(|c| c.committed_len())
3800 .unwrap_or(0),
3801 )
3802 .into());
3803 }
3804 }
3805
3806 match (target.recur[il].as_mut(), &snap.conv[il], &snap.ssm[il]) {
3807 (Some(dst), Some(conv), Some(ssm)) => {
3808 if conv.len() != dst.conv_state.len() || ssm.len() != dst.ssm_state.len() {
3809 return Err(
3810 format!("checkpoint recurrent layout mismatch at layer {il}").into(),
3811 );
3812 }
3813 owner.copy_into(&mut dst.conv_state, 0, conv, conv.len())?;
3814 owner.copy_into(&mut dst.ssm_state, 0, ssm, ssm.len())?;
3815 }
3816 (None, None, None) => {}
3817 _ => {
3818 return Err(format!("checkpoint recurrent kind mismatch at layer {il}").into());
3819 }
3820 }
3821 }
3822 target.pos = snap.pos;
3823 if dropped_mirrors > 0 {
3824 eprintln!(
3828 "[pp] checkpoint restore: cleared {dropped_mirrors} stale distributed KV mirror(s) \
3829 at pos {} (snapshot predates lazy TP hydration); the next TP use rehydrates them \
3830 from the local plane",
3831 snap.pos,
3832 );
3833 }
3834
3835 sync_stages_after_load(e, n_trunk)?;
3838 if source.is_some() {
3839 e.stream().synchronize()?;
3842 }
3843 Ok(())
3844}
3845
3846#[cfg(test)]
3847mod host_bounce_tests {
3848 use super::{
3849 BoundaryTransport, DUAL_PP_HOST_BOUNCE_REFUSAL, DUAL_PP_SINGLE_SLOT_REFUSAL,
3850 PEER_PROBE_FIXED_BYTES, PEER_PROBE_REQUIRED_REFUSAL, PEER_PROBE_TOKEN_WIDTHS,
3851 PEER_RUNTIME_PROBE_BUDGET_NS, PEER_RUNTIME_PROBE_CYCLE_COPIES,
3852 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS, PEER_RUNTIME_PROBE_INTERVAL_COPIES,
3853 PP_WAVE_MAX_STAGES, PeerProbeDecision, PeerProbeStartupPolicy, acquire_pp_walk,
3854 boundary_slot_growth_elements, boundary_transport, dual_pp_eligibility,
3855 dual_pp_timing_dropped, dual_pp_timing_snapshot, dual_pp_wave_mid, enter_pp_wave_cell,
3856 host_bounce_capacity, latch_runtime_host_bounce, peer_probe_bytes_to_f32,
3857 peer_probe_decision, peer_probe_f32_to_bytes, peer_probe_mismatch_count,
3858 peer_probe_pattern, peer_probe_startup_policy, pp_devices_repeat, pp_wave_diagonal,
3859 pp_wave_eligibility, pp_wave_numeric_eligibility, pp_wave_on_value, pp_wave_ranges,
3860 pp_wave_route_enabled, pp_wave_snapshot, publish_runtime_peer_probe_deferral,
3861 record_dual_pp_stage_result, record_pp_wave_tick, runtime_peer_probe_candidate,
3862 runtime_peer_probe_next_copy,
3863 };
3864
3865 use super::{TpRestore, TpRestoreRefusal, tp_restore_plan};
3875
3876 #[test]
3877 fn mismatch_snapshot_predating_lazy_tp_drops_the_mirror_instead_of_refusing() {
3878 assert_eq!(
3880 tp_restore_plan(None, None, true, false),
3881 TpRestore::DropMirror
3882 );
3883 }
3884
3885 #[test]
3886 fn mismatch_on_the_grow_path_leaves_the_fresh_target_without_a_mirror() {
3887 assert_eq!(
3890 tp_restore_plan(None, Some(true), false, false),
3891 TpRestore::Nothing
3892 );
3893 }
3894
3895 #[test]
3896 fn drop_is_refused_while_the_token_graph_door_bakes_rank_pointers() {
3897 assert_eq!(
3898 tp_restore_plan(None, None, true, true),
3899 TpRestore::Refuse(TpRestoreRefusal::TokenGraphDoorOpen)
3900 );
3901 }
3902
3903 #[test]
3904 fn healthy_arms_are_untouched() {
3905 assert_eq!(
3906 tp_restore_plan(None, None, false, false),
3907 TpRestore::Nothing
3908 );
3909 assert_eq!(tp_restore_plan(None, None, false, true), TpRestore::Nothing);
3910 assert_eq!(
3911 tp_restore_plan(Some(15222), None, true, false),
3912 TpRestore::Rewind(15222)
3913 );
3914 assert_eq!(
3915 tp_restore_plan(Some(15222), Some(true), false, false),
3916 TpRestore::Grow(15222)
3917 );
3918 assert_eq!(
3919 tp_restore_plan(None, Some(false), false, false),
3920 TpRestore::Nothing
3921 );
3922 }
3923
3924 #[test]
3925 fn refuses_a_recorded_distributed_length_with_no_target_mirror() {
3926 assert_eq!(
3927 tp_restore_plan(Some(15222), None, false, false),
3928 TpRestore::Refuse(TpRestoreRefusal::TargetAbsent)
3929 );
3930 }
3931
3932 #[test]
3933 fn refuses_a_recorded_distributed_length_the_source_cannot_supply() {
3934 assert_eq!(
3935 tp_restore_plan(Some(15222), Some(false), false, false),
3936 TpRestore::Refuse(TpRestoreRefusal::SourceAbsent)
3937 );
3938 }
3939
3940 #[test]
3941 fn refuses_a_grow_target_that_is_not_fresh() {
3942 assert_eq!(
3943 tp_restore_plan(Some(15222), Some(true), true, false),
3944 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
3945 );
3946 assert_eq!(
3947 tp_restore_plan(None, Some(true), true, false),
3948 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
3949 );
3950 }
3951
3952 #[test]
3956 fn flip_default_is_dual_auto_with_explicit_off_and_forced_seams() {
3957 use super::{DualPpMode, dual_pp_mode_resolve};
3958 assert_eq!(dual_pp_mode_resolve(None), DualPpMode::Auto);
3959 assert_eq!(dual_pp_mode_resolve(Some("0")), DualPpMode::Off);
3960 assert_eq!(dual_pp_mode_resolve(Some("1")), DualPpMode::Forced);
3961 assert_eq!(dual_pp_mode_resolve(Some("2")), DualPpMode::Auto);
3963 assert_eq!(dual_pp_mode_resolve(Some("")), DualPpMode::Auto);
3964 }
3965
3966 #[test]
3967 fn flip_overlap_follows_mode_and_one_flag_restores_preflip_serial() {
3968 use super::{DualPpMode, pp2_overlap_resolve};
3969 assert!(pp2_overlap_resolve(None, DualPpMode::Auto));
3971 assert!(!pp2_overlap_resolve(None, DualPpMode::Off));
3973 assert!(!pp2_overlap_resolve(None, DualPpMode::Forced));
3975 for mode in [DualPpMode::Off, DualPpMode::Forced, DualPpMode::Auto] {
3977 assert!(pp2_overlap_resolve(Some("1"), mode));
3978 assert!(!pp2_overlap_resolve(Some("0"), mode));
3979 }
3980 }
3981
3982 #[test]
3983 fn flip_auto_routes_only_the_regated_regime_and_degrades_serially_elsewhere() {
3984 use super::{DualPpMode, dual_pp_route};
3985 assert!(dual_pp_route(DualPpMode::Auto, 2, 2, true, false));
3987 assert!(dual_pp_route(DualPpMode::Auto, 17, 2, true, false));
3988 assert!(!dual_pp_route(DualPpMode::Auto, 1, 2, true, false)); assert!(!dual_pp_route(DualPpMode::Auto, 2, 3, true, false)); assert!(!dual_pp_route(DualPpMode::Auto, 2, 2, false, false)); assert!(!dual_pp_route(DualPpMode::Auto, 2, 2, true, true)); assert!(dual_pp_route(DualPpMode::Forced, 2, 3, false, true));
3995 assert!(!dual_pp_route(DualPpMode::Forced, 1, 2, true, false));
3996 assert!(!dual_pp_route(DualPpMode::Off, 8, 2, true, false));
3998 }
3999
4000 #[test]
4001 fn pp_wave_flag_is_strict_and_does_not_inherit_the_pp2_default() {
4002 assert_eq!(pp_wave_on_value(None), Ok(false));
4003 assert!(pp_wave_on_value(Some("")).is_err());
4004 assert_eq!(pp_wave_on_value(Some("0")), Ok(false));
4005 assert_eq!(pp_wave_on_value(Some("1")), Ok(true));
4006 assert!(pp_wave_on_value(Some("auto")).is_err());
4007 assert!(pp_wave_on_value(Some("2")).is_err());
4008 }
4009
4010 #[test]
4011 fn pp_wave_route_treats_overlap_off_and_single_work_item_as_serial_rollback() {
4012 assert!(pp_wave_route_enabled(true, true, 3, 2));
4013 assert!(pp_wave_route_enabled(true, true, 4, 8));
4014 assert!(!pp_wave_route_enabled(true, false, 3, 8));
4015 assert!(!pp_wave_route_enabled(false, true, 3, 8));
4016 assert!(!pp_wave_route_enabled(true, true, 2, 8));
4017 assert!(!pp_wave_route_enabled(true, true, 4, 1));
4018 }
4019
4020 #[test]
4021 fn pp_wave_ranges_are_balanced_contiguous_and_priority_preserving() {
4022 assert!(pp_wave_ranges(0, 4).is_empty());
4023 assert!(pp_wave_ranges(8, 0).is_empty());
4024 assert_eq!(pp_wave_ranges(1, 4), vec![(0, 1)]);
4025 assert_eq!(pp_wave_ranges(2, 4), vec![(0, 1), (1, 2)]);
4026 assert_eq!(pp_wave_ranges(8, 4), vec![(0, 2), (2, 4), (4, 6), (6, 8)]);
4027 assert_eq!(
4028 pp_wave_ranges(17, 4),
4029 vec![(0, 5), (5, 9), (9, 13), (13, 17)]
4030 );
4031 for batch in 1..=64 {
4032 for stages in 2..=PP_WAVE_MAX_STAGES {
4033 let ranges = pp_wave_ranges(batch, stages);
4034 assert_eq!(ranges.len(), batch.min(stages));
4035 assert_eq!(ranges.first().copied().unwrap().0, 0);
4036 assert_eq!(ranges.last().copied().unwrap().1, batch);
4037 assert!(ranges.iter().all(|(lo, hi)| lo < hi));
4038 assert!(ranges.windows(2).all(|pair| pair[0].1 == pair[1].0));
4039 let widths: Vec<_> = ranges.iter().map(|(lo, hi)| hi - lo).collect();
4040 assert!(widths.windows(2).all(|pair| pair[0] >= pair[1]));
4041 assert!(widths.first().unwrap() - widths.last().unwrap() <= 1);
4042 }
4043 }
4044 }
4045
4046 #[test]
4047 fn pp_wave_diagonals_cover_the_grid_without_stage_or_wave_aliasing() {
4048 for stages in 3..=PP_WAVE_MAX_STAGES {
4049 for waves in 1..=stages {
4050 let mut seen = vec![vec![false; stages]; waves];
4051 for diagonal in 0..stages + waves - 1 {
4052 let cells = pp_wave_diagonal(stages, waves, diagonal);
4053 let mut stage_seen = vec![false; stages];
4054 let mut wave_seen = vec![false; waves];
4055 for (wave, stage) in cells {
4056 assert_eq!(wave + stage, diagonal);
4057 assert!(!stage_seen[stage]);
4058 assert!(!wave_seen[wave]);
4059 assert!(!seen[wave][stage]);
4060 stage_seen[stage] = true;
4061 wave_seen[wave] = true;
4062 seen[wave][stage] = true;
4063 }
4064 }
4065 assert!(seen.into_iter().flatten().all(|cell| cell));
4066 }
4067 }
4068 assert!(pp_wave_diagonal(4, 4, 7).is_empty());
4069 }
4070
4071 #[test]
4072 fn pp_wavefront_refuses_every_unqualified_transport_shape() {
4073 assert!(pp_wave_eligibility(3, true, false, false).is_ok());
4074 assert!(pp_wave_eligibility(4, true, false, false).is_ok());
4075 assert!(pp_wave_eligibility(2, true, false, false).is_err());
4076 assert!(pp_wave_eligibility(5, true, false, false).is_err());
4077 assert!(pp_wave_eligibility(3, false, false, false).is_err());
4078 assert!(pp_wave_eligibility(3, true, true, false).is_err());
4079 assert!(pp_wave_eligibility(3, true, false, true).is_err());
4080 }
4081
4082 #[test]
4083 fn pp_wavefront_requires_width_invariant_bf16_for_w4a16() {
4084 assert!(pp_wave_numeric_eligibility(false, false).is_ok());
4085 assert!(pp_wave_numeric_eligibility(false, true).is_ok());
4086 assert!(pp_wave_numeric_eligibility(true, true).is_ok());
4087 assert!(pp_wave_numeric_eligibility(true, false).is_err());
4088 }
4089
4090 #[test]
4091 fn pp_device_aliases_cannot_bypass_the_distinct_stage_gate() {
4092 assert!(!pp_devices_repeat("0,1,2,3"));
4093 assert!(pp_devices_repeat("0,00,1"));
4094 assert!(pp_devices_repeat("2,1,2"));
4095 assert!(pp_devices_repeat("0,nope,1"));
4096 }
4097
4098 #[test]
4099 fn pp_walk_owner_refuses_reentry_and_releases_at_scope_end() {
4100 let active = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
4101 let next = std::sync::atomic::AtomicU64::new(1);
4102 let first = acquire_pp_walk(&active, &next, 7, None, "first").unwrap();
4103 let held_clone = super::PpWalkLease {
4104 state: first.state.clone(),
4105 };
4106 let error = acquire_pp_walk(&active, &next, 7, None, "second").unwrap_err();
4107 assert!(error.contains("refused concurrent PP walk"));
4108 drop(first);
4109 assert!(acquire_pp_walk(&active, &next, 7, None, "third").is_err());
4110 drop(held_clone);
4111 assert!(acquire_pp_walk(&active, &next, 7, None, "fourth").is_ok());
4112 }
4113
4114 #[test]
4115 fn pp_walk_coordinator_borrow_is_explicit_and_thread_local() {
4116 let active = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
4117 let next = std::sync::atomic::AtomicU64::new(1);
4118 let lease = acquire_pp_walk(&active, &next, 11, None, "owner").unwrap();
4119 let state = lease.state.clone();
4120 super::PP_WALK_BORROWS.with(|borrows| borrows.borrow_mut().push(state.clone()));
4121 assert!(super::borrowed_pp_walk(11).is_some());
4122 std::thread::spawn(move || {
4123 assert!(super::borrowed_pp_walk(11).is_none());
4124 drop(state);
4125 })
4126 .join()
4127 .unwrap();
4128 super::PP_WALK_BORROWS.with(|borrows| borrows.borrow_mut().clear());
4129 drop(lease);
4130 assert_eq!(active.load(std::sync::atomic::Ordering::Acquire), 0);
4131 }
4132
4133 #[test]
4134 fn boundary_growth_charges_first_allocation_and_only_missing_high_water_afterward() {
4135 assert_eq!(boundary_slot_growth_elements([0, 0], 4096), 8192);
4136 assert_eq!(boundary_slot_growth_elements([4096, 4096], 4096), 0);
4137 assert_eq!(boundary_slot_growth_elements([4096, 2048], 4096), 2048);
4138 assert_eq!(boundary_slot_growth_elements([8192, 8192], 4096), 0);
4139 }
4140
4141 #[test]
4142 fn pp_wave_liveness_snapshot_counts_ticks_cells_and_real_overlap() {
4143 let before = pp_wave_snapshot();
4144 let first = enter_pp_wave_cell();
4145 let second = enter_pp_wave_cell();
4146 drop(second);
4147 drop(first);
4148 record_pp_wave_tick();
4149 let after = pp_wave_snapshot();
4150 assert!(after.0 > before.0);
4151 assert!(after.1 >= before.1 + 2);
4152 assert!(after.2 > before.2);
4153 }
4154
4155 #[test]
4156 fn dual_pp_split_is_honest_at_one_and_ceil_first_afterward() {
4157 assert_eq!(dual_pp_wave_mid(1), None);
4158 assert_eq!(dual_pp_wave_mid(2), Some(1));
4159 assert_eq!(dual_pp_wave_mid(3), Some(2));
4160 assert_eq!(dual_pp_wave_mid(8), Some(4));
4161 assert_eq!(dual_pp_wave_mid(16), Some(8));
4162 assert_eq!(dual_pp_wave_mid(31), Some(16));
4163 assert_eq!(dual_pp_wave_mid(32), Some(16));
4164 }
4165
4166 #[test]
4167 fn dual_pp_refuses_single_slot_and_non_pp2_shapes() {
4168 assert_eq!(
4169 dual_pp_eligibility(2, false, false),
4170 Err(DUAL_PP_SINGLE_SLOT_REFUSAL)
4171 );
4172 assert!(dual_pp_eligibility(2, true, false).is_ok());
4173 assert!(dual_pp_eligibility(3, true, false).is_err());
4174 }
4175
4176 #[test]
4177 fn dual_pp_refuses_unvalidated_host_bounce_transport() {
4178 assert_eq!(
4179 dual_pp_eligibility(2, true, true),
4180 Err(DUAL_PP_HOST_BOUNCE_REFUSAL),
4181 );
4182 }
4183
4184 #[test]
4185 #[allow(clippy::int_plus_one)] fn dual_pp_timing_error_is_counted_without_recording_a_sample() {
4187 let dropped_before = dual_pp_timing_dropped();
4188 let (_, samples_before) = dual_pp_timing_snapshot();
4189 record_dual_pp_stage_result(0, Err::<f32, _>("CUDA_ERROR_NOT_READY"));
4190 let (_, samples_after) = dual_pp_timing_snapshot();
4191 assert_eq!(samples_after[0], samples_before[0]);
4192 assert!(dual_pp_timing_dropped() >= dropped_before + 1);
4193 }
4194
4195 #[test]
4196 fn corrupted_peer_readback_fails_closed_unless_host_bounce_is_selected() {
4197 assert_eq!(
4198 PEER_PROBE_TOKEN_WIDTHS,
4199 [1, 8, 16, crate::cache::PRIME_CHUNK_MAX_TOKENS],
4200 );
4201 let largest_payload_bytes = PEER_PROBE_TOKEN_WIDTHS[3] * 4096 * std::mem::size_of::<f32>();
4202 assert_eq!(largest_payload_bytes, 64 * 1024 * 1024);
4203 assert!(largest_payload_bytes >= 1024 * 1024);
4204 let expected = peer_probe_pattern(PEER_PROBE_FIXED_BYTES, 2, 0, 1);
4205 assert_eq!(
4206 peer_probe_f32_to_bytes(&peer_probe_bytes_to_f32(&expected)),
4207 expected,
4208 );
4209 let mut corrupted = expected.clone();
4210 for offset in [0, 8_191, PEER_PROBE_FIXED_BYTES - 1] {
4211 corrupted[offset] ^= 0x5a;
4212 }
4213
4214 assert_eq!(peer_probe_mismatch_count(&expected, &corrupted), 3);
4215 assert_eq!(
4216 peer_probe_decision(&expected, &corrupted, false),
4217 Err("3 mismatched byte(s)".to_string()),
4218 );
4219 assert_eq!(
4220 peer_probe_decision(&expected, &corrupted, true),
4221 Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches: 3 }),
4222 );
4223 }
4224
4225 #[test]
4226 fn probe_off_refusal_matrix_is_fail_closed_only_for_sharded_native_peer() {
4227 for probe_on in [false, true] {
4228 for sharded in [false, true] {
4229 for host_bounce in [false, true] {
4230 let got = peer_probe_startup_policy(probe_on, sharded, host_bounce);
4231 let expected = match (probe_on, sharded, host_bounce) {
4232 (false, true, false) => Err(PEER_PROBE_REQUIRED_REFUSAL),
4233 (false, true, true) => Ok(PeerProbeStartupPolicy::BypassedWithHostBounce),
4234 _ => Ok(PeerProbeStartupPolicy::Allowed),
4235 };
4236 assert_eq!(
4237 got, expected,
4238 "probe_on={probe_on} sharded={sharded} host_bounce={host_bounce}",
4239 );
4240 }
4241 }
4242 }
4243 assert!(PEER_PROBE_REQUIRED_REFUSAL.contains("MEMRA_PEER_PROBE=0"));
4244 assert!(PEER_PROBE_REQUIRED_REFUSAL.contains("MEMRA_PP_HOST_BOUNCE!=1"));
4245 }
4246
4247 #[test]
4248 fn runtime_reprobe_keeps_cheap_deadlines_live_while_expensive_work_waits_for_idle() {
4249 let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4250 assert_eq!(PEER_RUNTIME_PROBE_CYCLE_COPIES, 4 * every);
4251 let mut next = [every, 2 * every, 3 * every, 4 * every];
4252 let measured_ns = [1_000_000, 2_000_000, 3_000_000, 0];
4253
4254 assert_eq!(
4255 runtime_peer_probe_candidate(every - 1, next, measured_ns, false),
4256 None,
4257 );
4258 assert_eq!(
4259 runtime_peer_probe_candidate(every, next, measured_ns, false),
4260 Some((0, 1)),
4261 );
4262
4263 next[..3].copy_from_slice(&[5 * every, 6 * every, 7 * every]);
4266 assert_eq!(
4267 runtime_peer_probe_candidate(4 * every, next, measured_ns, false),
4268 None,
4269 );
4270 assert_eq!(
4273 runtime_peer_probe_candidate(5 * every, next, measured_ns, false),
4274 Some((0, 1)),
4275 );
4276 assert_eq!(
4278 runtime_peer_probe_candidate(5 * every, next, measured_ns, true),
4279 Some((3, crate::cache::PRIME_CHUNK_MAX_TOKENS)),
4280 );
4281 }
4282
4283 #[test]
4284 fn runtime_reprobe_moves_any_measured_over_budget_rung_to_idle_only() {
4285 let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4286 let next = [u64::MAX, every, u64::MAX, u64::MAX];
4287 let mut measured_ns = [0; PEER_PROBE_TOKEN_WIDTHS.len()];
4288 measured_ns[1] = PEER_RUNTIME_PROBE_BUDGET_NS + 1;
4289 assert_eq!(
4290 runtime_peer_probe_candidate(every, next, measured_ns, false),
4291 None
4292 );
4293 assert_eq!(
4294 runtime_peer_probe_candidate(every, next, measured_ns, true),
4295 Some((1, 8)),
4296 );
4297 }
4298
4299 #[test]
4300 fn late_runtime_reprobe_advances_once_instead_of_bursting_catchup() {
4301 let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4302 let due = every;
4303 assert_eq!(runtime_peer_probe_next_copy(due, due), due + 4 * every);
4304 assert_eq!(runtime_peer_probe_next_copy(due, 20 * every), 21 * every);
4305 }
4306
4307 #[test]
4308 fn runtime_reprobe_deferral_metric_counts_intervals_and_publishes_bound_state() {
4309 use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
4310
4311 assert_eq!(
4312 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS * PEER_RUNTIME_PROBE_INTERVAL_COPIES,
4313 PEER_RUNTIME_PROBE_CYCLE_COPIES,
4314 );
4315 let deferred = AtomicU64::new(0);
4316 let degraded = AtomicBool::new(false);
4317 publish_runtime_peer_probe_deferral(&deferred, °raded, 1, false);
4318 assert_eq!(deferred.load(Ordering::Relaxed), 1);
4319 assert!(!degraded.load(Ordering::Acquire));
4320
4321 publish_runtime_peer_probe_deferral(
4322 &deferred,
4323 °raded,
4324 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS - 1,
4325 true,
4326 );
4327 assert_eq!(
4328 deferred.load(Ordering::Relaxed),
4329 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS,
4330 );
4331 assert!(degraded.load(Ordering::Acquire));
4332 }
4333
4334 #[test]
4335 fn runtime_probe_failure_latches_native_before_publishing_validated_bounce() {
4336 use std::sync::atomic::{AtomicBool, Ordering};
4337
4338 let failed = AtomicBool::new(false);
4339 let degraded = AtomicBool::new(false);
4340 let armed = latch_runtime_host_bounce(&failed, °raded, || Ok::<_, String>(()));
4341 assert!(armed.is_ok());
4342 assert!(failed.load(Ordering::Acquire));
4343 assert!(degraded.load(Ordering::Acquire));
4344
4345 let failed = AtomicBool::new(false);
4346 let degraded = AtomicBool::new(false);
4347 let refused = latch_runtime_host_bounce(&failed, °raded, || {
4348 Err::<(), _>("injected staging mismatch".to_string())
4349 });
4350 assert_eq!(refused, Err("injected staging mismatch".to_string()));
4351 assert!(failed.load(Ordering::Acquire));
4352 assert!(!degraded.load(Ordering::Acquire));
4353 }
4354
4355 #[test]
4356 fn transport_selection_keeps_peer_default_and_bounces_only_cross_device() {
4357 assert_eq!(boundary_transport(false, false), BoundaryTransport::Local);
4358 assert_eq!(boundary_transport(false, true), BoundaryTransport::Local);
4359 assert_eq!(boundary_transport(true, false), BoundaryTransport::Peer);
4360 assert_eq!(
4361 boundary_transport(true, true),
4362 BoundaryTransport::HostBounce
4363 );
4364 }
4365
4366 #[test]
4367 fn step37_geometry_sizes_each_slot_from_the_prime_cap() {
4368 let (elems, bytes) = host_bounce_capacity(4096).expect("valid Step-3.7 geometry");
4369 assert_eq!(elems, 4096 * crate::cache::PRIME_CHUNK_MAX_TOKENS);
4370 assert_eq!(bytes, 64 * 1024 * 1024);
4371 }
4372
4373 #[test]
4374 fn host_bounce_capacity_rejects_invalid_or_overflowing_geometry() {
4375 assert!(host_bounce_capacity(0).is_err());
4376 assert!(host_bounce_capacity(usize::MAX).is_err());
4377 }
4378}