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_exit_publish() -> bool {
239 !matches!(std::env::var("MEMRA_PP_EXIT_PUBLISH").as_deref(), Ok("0"))
240}
241
242pub fn pp_multi_stream_same_device() -> bool {
264 let stages_open = std::env::var("MEMRA_PP_STAGES")
265 .map(|v| v.parse::<usize>().map(|n| n >= 2).unwrap_or(false))
266 .unwrap_or(false);
267 let devices = std::env::var("MEMRA_PP_DEVICES")
268 .ok()
269 .filter(|v| !v.is_empty());
270 if (!stages_open && devices.is_none()) || pp2_streams_off() {
271 return false;
272 }
273 match devices {
274 None => true, Some(s) => pp_devices_repeat(&s),
276 }
277}
278
279fn pp_devices_repeat(raw: &str) -> bool {
280 let Ok(mut devices) = raw
281 .split(',')
282 .map(|part| part.trim().parse::<usize>())
283 .collect::<Result<Vec<_>, _>>()
284 else {
285 return true;
288 };
289 let count = devices.len();
290 devices.sort_unstable();
291 devices.dedup();
292 devices.len() < count
293}
294
295pub fn pp_sharded_cross_device() -> bool {
309 let stages_open = std::env::var("MEMRA_PP_STAGES")
310 .map(|v| v.parse::<usize>().map(|n| n >= 2).unwrap_or(false))
311 .unwrap_or(false);
312 if !stages_open || pp_shard_off() || pp2_streams_off() {
319 return false;
320 }
321 match pp2_devices_env() {
322 None => false, Some(s) => {
324 let mut v: Vec<&str> = s.split(',').map(|p| p.trim()).collect();
325 v.sort_unstable();
326 v.dedup();
327 v.len() >= 2
328 }
329 }
330}
331
332pub fn refuse_unsplit_if_remote(path: &str, alt: &str) -> Result<(), Box<dyn std::error::Error>> {
344 if pp_host_bounce_active() {
345 return Err(format!(
346 "{path}: refused with MEMRA_PP_HOST_BOUNCE=1 on sharded cross-device PP — \
347 this unsplit path peer-reads remote weights, while host bounce covers only \
348 explicit stage-boundary transfers. Use {alt}; the \
349 MEMRA_PP_ALLOW_UNSPLIT_BATCH override is unavailable on a broken-peer host."
350 )
351 .into());
352 }
353 if pp_sharded_cross_device()
354 && std::env::var("MEMRA_PP_ALLOW_UNSPLIT_BATCH").as_deref() != Ok("1")
355 {
356 return Err(format!(
357 "{path}: refused with the ppN door open across 2+ devices — this path has no pp \
358 stage split, so it would walk ALL layers on one stream and peer-read every \
359 remote stage's weights each step (measured 28x slower at B=1, 13.9x at B=8 on \
360 a PRO 6000 pair over PCIe Gen5 x16 P2P; research/pp2-hardening-20260806). \
361 Exactness is unaffected — peer reads return identical bytes and the exactness \
362 gates PASS on this config — which is exactly why it must refuse instead of \
363 being caught by a gate. Fixes, in order: {alt}; or MEMRA_PP_SHARD=0 (all \
364 weights home on the primary — full speed, forfeits the capacity PP-2 exists \
365 for); or close the pp door. MEMRA_PP_ALLOW_UNSPLIT_BATCH=1 overrides for \
366 measurement."
367 )
368 .into());
369 }
370 Ok(())
371}
372
373pub fn batch_pp_on() -> bool {
381 std::env::var("MEMRA_BATCH_PP").as_deref() != Ok("0")
382}
383
384pub const PP_WAVE_MAX_STAGES: usize = 4;
388
389pub fn pp_wave_on_value(value: Option<&str>) -> Result<bool, &'static str> {
393 match value {
394 None | Some("0") => Ok(false),
395 Some("1") => Ok(true),
396 Some(_) => Err("MEMRA_PP_WAVE must be 0 or 1"),
397 }
398}
399
400pub fn pp_wave_on() -> Result<bool, &'static str> {
401 match std::env::var_os("MEMRA_PP_WAVE") {
402 None => pp_wave_on_value(None),
403 Some(value) => value
404 .to_str()
405 .ok_or("MEMRA_PP_WAVE must be valid UTF-8 and exactly 0 or 1")
406 .and_then(|value| pp_wave_on_value(Some(value))),
407 }
408}
409
410pub fn pp_wave_ranges(batch: usize, stages: usize) -> Vec<(usize, usize)> {
414 if batch == 0 || stages == 0 {
415 return Vec::new();
416 }
417 let waves = batch.min(stages);
418 let base = batch / waves;
419 let extra = batch % waves;
420 let mut out = Vec::with_capacity(waves);
421 let mut start = 0usize;
422 for wave in 0..waves {
423 let len = base + usize::from(wave < extra);
424 out.push((start, start + len));
425 start += len;
426 }
427 debug_assert_eq!(start, batch);
428 out
429}
430
431pub fn pp_wave_diagonal(stages: usize, waves: usize, diagonal: usize) -> Vec<(usize, usize)> {
436 if stages == 0 || waves == 0 || diagonal >= stages + waves - 1 {
437 return Vec::new();
438 }
439 let first_stage = diagonal.saturating_sub(waves - 1);
440 let last_stage = diagonal.min(stages - 1);
441 (first_stage..=last_stage)
442 .map(|stage| (diagonal - stage, stage))
443 .collect()
444}
445
446pub fn pp_wave_eligibility(
450 stages: usize,
451 double_slot: bool,
452 host_bounce: bool,
453 repeated_device: bool,
454) -> Result<(), &'static str> {
455 if !(3..=PP_WAVE_MAX_STAGES).contains(&stages) {
456 return Err("PP wavefront requires 3 or 4 stages; PP2 is owned by MEMRA_DUAL_PP");
457 }
458 if !double_slot {
459 return Err("PP wavefront requires MEMRA_PP_OVERLAP=1 double-buffered boundaries");
460 }
461 if host_bounce {
462 return Err(
463 "PP wavefront is unqualified with MEMRA_PP_HOST_BOUNCE=1; use native peer transport",
464 );
465 }
466 if repeated_device {
467 return Err("PP wavefront requires one distinct CUDA device per stage");
468 }
469 Ok(())
470}
471
472pub const PP_WAVE_W4A16_BF16_REFUSAL: &str = "PP wavefront for a W4A16 artifact with preserved BF16 non-expert weights requires \
478 MEMRA_BF16_MMV=1; without the row-wise BF16 program, wave batch-width decomposition changes \
479 logits. Keep MEMRA_PP_WAVE=0 or enable and qualify MEMRA_BF16_MMV=1";
480
481pub fn pp_wave_numeric_eligibility(
482 weight_only_nvfp4: bool,
483 bf16_mmv: bool,
484) -> Result<(), &'static str> {
485 if weight_only_nvfp4 && !bf16_mmv {
486 return Err(PP_WAVE_W4A16_BF16_REFUSAL);
487 }
488 Ok(())
489}
490
491pub fn pp_wave_route_enabled(
494 requested: bool,
495 overlap: bool,
496 stages: usize,
497 work_items: usize,
498) -> bool {
499 requested && overlap && (3..=PP_WAVE_MAX_STAGES).contains(&stages) && work_items >= 2
500}
501
502static PP_WAVE_ACTIVE_CELLS: AtomicUsize = AtomicUsize::new(0);
503static PP_WAVE_OVERLAPS: AtomicUsize = AtomicUsize::new(0);
504static PP_WAVE_TICKS: AtomicUsize = AtomicUsize::new(0);
505static PP_WAVE_CELLS: AtomicUsize = AtomicUsize::new(0);
506
507pub(crate) struct PpWaveCellGuard;
508
509pub(crate) fn enter_pp_wave_cell() -> PpWaveCellGuard {
513 let active = PP_WAVE_ACTIVE_CELLS.fetch_add(1, Ordering::AcqRel);
514 if active > 0 {
515 PP_WAVE_OVERLAPS.fetch_add(1, Ordering::Relaxed);
516 }
517 PP_WAVE_CELLS.fetch_add(1, Ordering::Relaxed);
518 PpWaveCellGuard
519}
520
521impl Drop for PpWaveCellGuard {
522 fn drop(&mut self) {
523 let active = PP_WAVE_ACTIVE_CELLS.fetch_sub(1, Ordering::AcqRel);
524 debug_assert!(active > 0, "PP wave active-cell counter underflow");
525 }
526}
527
528pub(crate) fn record_pp_wave_tick() {
529 PP_WAVE_TICKS.fetch_add(1, Ordering::Relaxed);
530}
531
532pub fn pp_wave_snapshot() -> (usize, usize, usize) {
534 (
535 PP_WAVE_TICKS.load(Ordering::Relaxed),
536 PP_WAVE_CELLS.load(Ordering::Relaxed),
537 PP_WAVE_OVERLAPS.load(Ordering::Relaxed),
538 )
539}
540
541#[derive(Clone, Copy, PartialEq, Eq, Debug)]
559pub enum DualPpMode {
560 Off,
561 Forced,
562 Auto,
563}
564
565pub fn dual_pp_mode_resolve(v: Option<&str>) -> DualPpMode {
568 match v {
569 Some("0") => DualPpMode::Off,
570 Some("1") => DualPpMode::Forced,
571 _ => DualPpMode::Auto,
572 }
573}
574
575pub fn dual_pp_mode() -> DualPpMode {
576 dual_pp_mode_resolve(std::env::var("MEMRA_DUAL_PP").ok().as_deref())
577}
578
579pub fn dual_pp_on() -> bool {
582 dual_pp_mode() != DualPpMode::Off
583}
584
585pub fn dual_pp_route(
591 mode: DualPpMode,
592 batch: usize,
593 stages: usize,
594 double_slot: bool,
595 host_bounce: bool,
596) -> bool {
597 if batch < 2 {
598 return false;
599 }
600 match mode {
601 DualPpMode::Off => false,
602 DualPpMode::Forced => true,
603 DualPpMode::Auto => stages == 2 && double_slot && !host_bounce,
604 }
605}
606
607pub 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";
610pub 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";
611
612#[allow(clippy::manual_div_ceil)] pub fn dual_pp_wave_mid(batch: usize) -> Option<usize> {
616 (batch >= 2).then_some((batch + 1) / 2)
617}
618
619pub fn dual_pp_eligibility(
622 stages: usize,
623 double_slot: bool,
624 host_bounce: bool,
625) -> Result<(), &'static str> {
626 if stages != 2 {
627 return Err(
628 "decode_step_batch_dual: refused: dual-active decode requires exactly two PP stages",
629 );
630 }
631 if !double_slot {
632 return Err(DUAL_PP_SINGLE_SLOT_REFUSAL);
633 }
634 if host_bounce {
635 return Err(DUAL_PP_HOST_BOUNCE_REFUSAL);
636 }
637 Ok(())
638}
639
640static DUAL_PP_OVERLAPS: AtomicUsize = AtomicUsize::new(0);
643static DUAL_PP_ACTIVE_STAGES: AtomicUsize = AtomicUsize::new(0);
644static DUAL_PP_STAGE_NS: [AtomicU64; 4] = [
645 AtomicU64::new(0),
646 AtomicU64::new(0),
647 AtomicU64::new(0),
648 AtomicU64::new(0),
649];
650static DUAL_PP_STAGE_SAMPLES: [AtomicUsize; 4] = [
651 AtomicUsize::new(0),
652 AtomicUsize::new(0),
653 AtomicUsize::new(0),
654 AtomicUsize::new(0),
655];
656static DUAL_PP_TIMING_DROPPED: AtomicUsize = AtomicUsize::new(0);
657static DUAL_PP_SLOT_PAIRS: AtomicUsize = AtomicUsize::new(0);
658static DUAL_PP_SLOT_USES: [AtomicUsize; 2] = [AtomicUsize::new(0), AtomicUsize::new(0)];
659static DUAL_PP_SLOT_COLLISIONS: AtomicUsize = AtomicUsize::new(0);
660
661pub const DUAL_PP_STAGE_NAMES: [&str; 4] = [
662 "wave_a_stage0",
663 "wave_a_stage1",
664 "wave_b_stage0",
665 "wave_b_stage1",
666];
667
668pub fn dual_pp_overlaps() -> usize {
669 DUAL_PP_OVERLAPS.load(Ordering::Relaxed)
670}
671
672pub(crate) fn record_dual_pp_slot_pair(slot_a: usize, slot_b: usize) -> bool {
676 debug_assert!(slot_a < DUAL_PP_SLOT_USES.len());
677 debug_assert!(slot_b < DUAL_PP_SLOT_USES.len());
678 if slot_a == slot_b {
679 DUAL_PP_SLOT_COLLISIONS.fetch_add(1, Ordering::Relaxed);
680 return false;
681 }
682 DUAL_PP_SLOT_USES[slot_a].fetch_add(1, Ordering::Relaxed);
683 DUAL_PP_SLOT_USES[slot_b].fetch_add(1, Ordering::Relaxed);
684 DUAL_PP_SLOT_PAIRS.fetch_add(1, Ordering::Relaxed);
685 true
686}
687
688pub fn dual_pp_slot_snapshot() -> (usize, [usize; 2], usize) {
690 (
691 DUAL_PP_SLOT_PAIRS.load(Ordering::Relaxed),
692 std::array::from_fn(|i| DUAL_PP_SLOT_USES[i].load(Ordering::Relaxed)),
693 DUAL_PP_SLOT_COLLISIONS.load(Ordering::Relaxed),
694 )
695}
696
697pub fn dual_pp_timing_on() -> bool {
701 static ON: OnceLock<bool> = OnceLock::new();
702 *ON.get_or_init(|| std::env::var("MEMRA_DUAL_PP_TIMING").as_deref() == Ok("1"))
703}
704
705pub(crate) fn record_dual_pp_stage_ms(stage: usize, ms: f32) {
706 assert!(
707 stage < DUAL_PP_STAGE_NS.len(),
708 "dual PP timing stage out of range"
709 );
710 let ns = (f64::from(ms) * 1_000_000.0).round() as u64;
711 DUAL_PP_STAGE_NS[stage].fetch_add(ns, Ordering::Relaxed);
712 DUAL_PP_STAGE_SAMPLES[stage].fetch_add(1, Ordering::Relaxed);
713}
714
715pub(crate) fn record_dual_pp_timing_drop(context: &str, err: &dyn std::fmt::Display) {
718 let previous = DUAL_PP_TIMING_DROPPED.fetch_add(1, Ordering::Relaxed);
719 if previous == 0 {
720 eprintln!(
721 "[dual-pp] WARN: skipped diagnostic timing sample at {context}: {err}; decode continues"
722 );
723 }
724}
725
726pub(crate) fn record_dual_pp_stage_result<E: std::fmt::Display>(
727 stage: usize,
728 elapsed: Result<f32, E>,
729) {
730 match elapsed {
731 Ok(ms) => record_dual_pp_stage_ms(stage, ms),
732 Err(err) => record_dual_pp_timing_drop(DUAL_PP_STAGE_NAMES[stage], &err),
733 }
734}
735
736pub fn dual_pp_timing_dropped() -> usize {
737 DUAL_PP_TIMING_DROPPED.load(Ordering::Relaxed)
738}
739
740pub fn dual_pp_timing_snapshot() -> ([u64; 4], [usize; 4]) {
742 (
743 std::array::from_fn(|i| DUAL_PP_STAGE_NS[i].load(Ordering::Relaxed)),
744 std::array::from_fn(|i| DUAL_PP_STAGE_SAMPLES[i].load(Ordering::Relaxed)),
745 )
746}
747
748pub(crate) struct DualPpStageGuard;
749
750pub(crate) fn enter_dual_pp_stage() -> DualPpStageGuard {
751 let active = DUAL_PP_ACTIVE_STAGES.fetch_add(1, Ordering::AcqRel);
752 if active > 0 {
753 DUAL_PP_OVERLAPS.fetch_add(1, Ordering::Relaxed);
754 }
755 DualPpStageGuard
756}
757
758impl Drop for DualPpStageGuard {
759 fn drop(&mut self) {
760 let active = DUAL_PP_ACTIVE_STAGES.fetch_sub(1, Ordering::AcqRel);
761 debug_assert!(active > 0, "dual PP active-stage counter underflow");
762 }
763}
764
765pub fn prime_pp_on() -> bool {
775 std::env::var("MEMRA_PRIME_PP").as_deref() != Ok("0")
776}
777
778pub fn prime_pipe_on() -> bool {
783 std::env::var("MEMRA_PRIME_PIPE").as_deref() != Ok("0")
784}
785
786pub static PRIME_SPLIT_CHUNKS: AtomicUsize = AtomicUsize::new(0);
793
794pub fn prime_split_chunks() -> usize {
796 PRIME_SPLIT_CHUNKS.load(Ordering::Relaxed)
797}
798
799pub static PRIME_PIPE_OVERLAPS: AtomicUsize = AtomicUsize::new(0);
804
805pub fn prime_pipe_overlaps() -> usize {
807 PRIME_PIPE_OVERLAPS.load(Ordering::Relaxed)
808}
809
810static PRIME_PIPE_ACTIVE_STAGES: AtomicUsize = AtomicUsize::new(0);
811
812pub(crate) struct PrimePipeStageGuard;
813
814pub(crate) fn enter_prime_pipe_stage() -> PrimePipeStageGuard {
817 let active = PRIME_PIPE_ACTIVE_STAGES.fetch_add(1, Ordering::AcqRel);
818 if active > 0 {
819 PRIME_PIPE_OVERLAPS.fetch_add(1, Ordering::Relaxed);
820 }
821 PrimePipeStageGuard
822}
823
824impl Drop for PrimePipeStageGuard {
825 fn drop(&mut self) {
826 let active = PRIME_PIPE_ACTIVE_STAGES.fetch_sub(1, Ordering::AcqRel);
827 debug_assert!(active > 0, "prime pipeline active-stage counter underflow");
828 }
829}
830
831pub static STEP35_PRIME_BATCHES: AtomicUsize = AtomicUsize::new(0);
835pub static STEP35_PRIME_BATCH_SPLITS: AtomicUsize = AtomicUsize::new(0);
836
837pub fn step35_prime_batches() -> usize {
838 STEP35_PRIME_BATCHES.load(Ordering::Relaxed)
839}
840
841pub fn step35_prime_batch_splits() -> usize {
842 STEP35_PRIME_BATCH_SPLITS.load(Ordering::Relaxed)
843}
844
845pub fn spec_pp_on() -> bool {
853 std::env::var("MEMRA_SPEC_PP").as_deref() != Ok("0")
854}
855
856pub fn pp2_overlap() -> bool {
867 pp2_overlap_resolve(
868 std::env::var("MEMRA_PP_OVERLAP").ok().as_deref(),
869 dual_pp_mode(),
870 )
871}
872
873pub fn pp2_overlap_resolve(v: Option<&str>, mode: DualPpMode) -> bool {
876 match v {
877 Some("1") => true,
878 Some(_) => false,
879 None => mode == DualPpMode::Auto,
880 }
881}
882
883pub fn pp_host_bounce_on() -> bool {
886 matches!(std::env::var("MEMRA_PP_HOST_BOUNCE").as_deref(), Ok("1"))
887}
888
889pub fn pp_host_bounce_active() -> bool {
892 (pp_host_bounce_on() || PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire))
893 && pp_sharded_cross_device()
894}
895
896pub fn pp_shard_off() -> bool {
900 matches!(std::env::var("MEMRA_PP_SHARD").as_deref(), Ok("0"))
901}
902
903fn pp2_devices_env() -> Option<String> {
906 std::env::var("MEMRA_PP_DEVICES")
907 .ok()
908 .filter(|v| !v.is_empty())
909}
910
911static WARNED_BAD: AtomicBool = AtomicBool::new(false);
912fn warn_bad_once(msg: &str) {
913 if !WARNED_BAD.swap(true, Ordering::Relaxed) {
914 eprintln!("[pp] {msg}");
915 }
916}
917
918static WARNED_UNWIRED: AtomicBool = AtomicBool::new(false);
919pub fn warn_unwired_once(path: &str) {
922 let open = std::env::var("MEMRA_PP_STAGES")
923 .map(|v| !v.is_empty() && v != "0" && v != "1")
924 .unwrap_or(false);
925 if open && !WARNED_UNWIRED.swap(true, Ordering::Relaxed) {
926 eprintln!("[pp] MEMRA_PP_STAGES set but `{path}` has no pp arm at this N; running unsplit");
927 }
928}
929
930pub struct StageRt {
938 pub dev: usize,
939 pub ctx: Arc<CudaContext>,
940 pub stream: Arc<CudaStream>,
941 pub blas: Arc<cudarc::cublaslt::CudaBlasLT>,
942 engine: Option<Engine>,
944}
945
946struct BoundarySlot {
951 buf: Mutex<Option<CudaSlice<f32>>>,
952 ev_tx: CudaEvent,
955 ev_rx: CudaEvent,
959}
960
961struct BoundaryRt {
965 slots: [BoundarySlot; 2],
966 step: AtomicUsize,
967 cross: bool,
969}
970
971#[derive(Clone, Copy, Debug, PartialEq, Eq)]
972enum BoundaryTransport {
973 Local,
974 Peer,
975 HostBounce,
976}
977
978#[derive(Clone, Copy)]
979struct BoundaryPath {
980 boundary: usize,
981 src_stage: usize,
982 dst_stage: usize,
983 transport: BoundaryTransport,
984}
985
986fn boundary_transport(cross: bool, host_bounce: bool) -> BoundaryTransport {
987 match (cross, host_bounce) {
988 (false, _) => BoundaryTransport::Local,
989 (true, false) => BoundaryTransport::Peer,
990 (true, true) => BoundaryTransport::HostBounce,
991 }
992}
993
994const PEER_PROBE_FIXED_BYTES: usize = 16 * 1024;
995const PEER_PROBE_TOKEN_WIDTHS: [usize; 4] = [1, 8, 16, crate::cache::PRIME_CHUNK_MAX_TOKENS];
996
997pub const PEER_RUNTIME_PROBE_INTERVAL_COPIES: u64 = 8 * 1024;
1000pub const PEER_RUNTIME_PROBE_CYCLE_COPIES: u64 =
1002 PEER_RUNTIME_PROBE_INTERVAL_COPIES * PEER_PROBE_TOKEN_WIDTHS.len() as u64;
1003pub const PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS: u64 = PEER_PROBE_TOKEN_WIDTHS.len() as u64;
1006const PEER_RUNTIME_PROBE_BUDGET_NS: u64 = 5_000_000;
1008
1009pub const PEER_PROBE_REQUIRED_REFUSAL: &str = "PP bring-up refused: MEMRA_PEER_PROBE=0 cannot authorize native peer transport for a \
1010 sharded cross-device placement while MEMRA_PP_HOST_BOUNCE!=1; leave MEMRA_PEER_PROBE \
1011 enabled or set MEMRA_PP_HOST_BOUNCE=1";
1012
1013#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1014pub enum PeerProbeStartupPolicy {
1015 Allowed,
1016 BypassedWithHostBounce,
1017}
1018
1019pub fn peer_probe_startup_policy(
1022 probe_on: bool,
1023 sharded_cross_device: bool,
1024 host_bounce: bool,
1025) -> Result<PeerProbeStartupPolicy, &'static str> {
1026 match (probe_on, sharded_cross_device, host_bounce) {
1027 (false, true, false) => Err(PEER_PROBE_REQUIRED_REFUSAL),
1028 (false, true, true) => Ok(PeerProbeStartupPolicy::BypassedWithHostBounce),
1029 _ => Ok(PeerProbeStartupPolicy::Allowed),
1030 }
1031}
1032
1033static PEER_PROBE_BYPASSED: AtomicU64 = AtomicU64::new(0);
1034static PEER_BOUNDARY_COPIES: AtomicU64 = AtomicU64::new(0);
1035static PEER_RUNTIME_PROBES: AtomicU64 = AtomicU64::new(0);
1036static PEER_RUNTIME_PROBE_FAILURES: AtomicU64 = AtomicU64::new(0);
1037static PEER_RUNTIME_PROBE_DEFERRED: AtomicU64 = AtomicU64::new(0);
1038static PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED: AtomicBool = AtomicBool::new(false);
1039static PEER_RUNTIME_PROBE_FAILED: AtomicBool = AtomicBool::new(false);
1040static PEER_RUNTIME_HOST_BOUNCE: AtomicBool = AtomicBool::new(false);
1041static PEER_RUNTIME_NEXT_PROBE_COPY: [AtomicU64; PEER_PROBE_TOKEN_WIDTHS.len()] = [
1042 AtomicU64::new(PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1043 AtomicU64::new(2 * PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1044 AtomicU64::new(3 * PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1045 AtomicU64::new(4 * PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1046];
1047static PEER_RUNTIME_PROBE_MAX_COST_NS: [AtomicU64; PEER_PROBE_TOKEN_WIDTHS.len()] = [
1048 AtomicU64::new(0),
1049 AtomicU64::new(0),
1050 AtomicU64::new(0),
1051 AtomicU64::new(0),
1052];
1053
1054#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1055pub struct PeerProbeMetrics {
1056 pub bypassed: u64,
1057 pub boundary_copies: u64,
1058 pub runtime_probes: u64,
1059 pub runtime_failures: u64,
1060 pub deferred_total: u64,
1061 pub integrity_degraded: bool,
1062 pub degraded_to_host_bounce: bool,
1063}
1064
1065pub fn peer_probe_metrics() -> PeerProbeMetrics {
1066 PeerProbeMetrics {
1067 bypassed: PEER_PROBE_BYPASSED.load(Ordering::Relaxed),
1068 boundary_copies: PEER_BOUNDARY_COPIES.load(Ordering::Relaxed),
1069 runtime_probes: PEER_RUNTIME_PROBES.load(Ordering::Relaxed),
1070 runtime_failures: PEER_RUNTIME_PROBE_FAILURES.load(Ordering::Relaxed),
1071 deferred_total: PEER_RUNTIME_PROBE_DEFERRED.load(Ordering::Relaxed),
1072 integrity_degraded: PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED.load(Ordering::Acquire),
1073 degraded_to_host_bounce: PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire),
1074 }
1075}
1076
1077#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1078pub enum RuntimePeerProbeStatus {
1079 NotRun,
1080 Deferred,
1081 Passed,
1082 DegradedToHostBounce,
1083}
1084
1085impl RuntimePeerProbeStatus {
1086 pub fn ran(self) -> bool {
1087 matches!(self, Self::Passed | Self::DegradedToHostBounce)
1088 }
1089}
1090
1091fn publish_runtime_peer_probe_deferral(
1092 deferred_total: &AtomicU64,
1093 integrity_degraded: &AtomicBool,
1094 intervals: u64,
1095 bound_reached: bool,
1096) {
1097 deferred_total.fetch_add(intervals, Ordering::Relaxed);
1098 if bound_reached {
1099 integrity_degraded.store(true, Ordering::Release);
1100 }
1101}
1102
1103pub fn record_runtime_peer_probe_deferral(intervals: u64, bound_reached: bool) {
1106 publish_runtime_peer_probe_deferral(
1107 &PEER_RUNTIME_PROBE_DEFERRED,
1108 &PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED,
1109 intervals,
1110 bound_reached,
1111 );
1112}
1113
1114pub fn clear_runtime_peer_probe_integrity_degraded() {
1116 PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED.store(false, Ordering::Release);
1117}
1118
1119fn runtime_peer_probe_idle_only(width_index: usize, measured_cost_ns: u64) -> bool {
1120 width_index + 1 == PEER_PROBE_TOKEN_WIDTHS.len()
1121 || measured_cost_ns > PEER_RUNTIME_PROBE_BUDGET_NS
1122}
1123
1124fn runtime_peer_probe_candidate(
1127 copies: u64,
1128 next_probe_copy: [u64; PEER_PROBE_TOKEN_WIDTHS.len()],
1129 measured_cost_ns: [u64; PEER_PROBE_TOKEN_WIDTHS.len()],
1130 scheduler_idle: bool,
1131) -> Option<(usize, usize)> {
1132 let mut selected: Option<(usize, u64)> = None;
1133 for width_index in 0..PEER_PROBE_TOKEN_WIDTHS.len() {
1134 let due = next_probe_copy[width_index];
1135 if copies < due
1136 || (!scheduler_idle
1137 && runtime_peer_probe_idle_only(width_index, measured_cost_ns[width_index]))
1138 {
1139 continue;
1140 }
1141 if selected.is_none_or(|(_, selected_due)| due < selected_due) {
1142 selected = Some((width_index, due));
1143 }
1144 }
1145 selected.map(|(width_index, _)| (width_index, PEER_PROBE_TOKEN_WIDTHS[width_index]))
1146}
1147
1148fn runtime_peer_probe_next_copy(due: u64, copies: u64) -> u64 {
1151 let cycles = copies.saturating_sub(due) / PEER_RUNTIME_PROBE_CYCLE_COPIES + 1;
1152 due.saturating_add(PEER_RUNTIME_PROBE_CYCLE_COPIES.saturating_mul(cycles))
1153}
1154
1155fn latch_runtime_host_bounce<E>(
1158 native_failed: &AtomicBool,
1159 degraded_to_host_bounce: &AtomicBool,
1160 arm_and_validate: impl FnOnce() -> Result<(), E>,
1161) -> Result<(), E> {
1162 native_failed.store(true, Ordering::Release);
1163 arm_and_validate()?;
1164 degraded_to_host_bounce.store(true, Ordering::Release);
1165 Ok(())
1166}
1167
1168fn peer_probe_on() -> bool {
1169 std::env::var("MEMRA_PEER_PROBE").as_deref() != Ok("0")
1170}
1171
1172#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1173enum PeerProbeDecision {
1174 Clean,
1175 ProceedWithHostBounce { mismatches: usize },
1176}
1177
1178fn peer_probe_mismatch_count(expected: &[u8], readback: &[u8]) -> usize {
1179 expected
1180 .iter()
1181 .zip(readback)
1182 .filter(|(a, b)| a != b)
1183 .count()
1184 + expected.len().abs_diff(readback.len())
1185}
1186
1187fn peer_probe_decision(
1188 expected: &[u8],
1189 readback: &[u8],
1190 host_bounce: bool,
1191) -> Result<PeerProbeDecision, String> {
1192 let mismatches = peer_probe_mismatch_count(expected, readback);
1193 if mismatches == 0 {
1194 Ok(PeerProbeDecision::Clean)
1195 } else if host_bounce {
1196 Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches })
1197 } else {
1198 Err(format!("{mismatches} mismatched byte(s)"))
1199 }
1200}
1201
1202fn peer_probe_pattern(bytes: usize, boundary: usize, src_dev: usize, dst_dev: usize) -> Vec<u8> {
1203 let mut state = 0xD1B5_4A32_D192_ED03u64
1204 ^ (bytes as u64).rotate_left(7)
1205 ^ (boundary as u64).rotate_left(19)
1206 ^ (src_dev as u64).rotate_left(31)
1207 ^ (dst_dev as u64).rotate_left(43);
1208 (0..bytes)
1209 .map(|_| {
1210 state ^= state << 13;
1211 state ^= state >> 7;
1212 state ^= state << 17;
1213 state as u8
1214 })
1215 .collect()
1216}
1217
1218fn peer_probe_bytes_to_f32(bytes: &[u8]) -> Vec<f32> {
1219 assert_eq!(bytes.len() % std::mem::size_of::<f32>(), 0);
1220 bytes
1221 .chunks_exact(std::mem::size_of::<f32>())
1222 .map(|chunk| f32::from_bits(u32::from_ne_bytes(chunk.try_into().unwrap())))
1223 .collect()
1224}
1225
1226fn peer_probe_f32_to_bytes(values: &[f32]) -> Vec<u8> {
1227 values
1228 .iter()
1229 .flat_map(|value| value.to_bits().to_ne_bytes())
1230 .collect()
1231}
1232
1233struct PeerProbeBuffer {
1237 ctx: Arc<CudaContext>,
1238 ptr: cudarc::driver::sys::CUdeviceptr,
1239}
1240
1241impl PeerProbeBuffer {
1242 fn new(ctx: &Arc<CudaContext>, bytes: usize) -> Result<Self, Box<dyn std::error::Error>> {
1243 ctx.bind_to_thread()?;
1244 let ptr = unsafe { cudarc::driver::result::malloc_sync(bytes)? };
1245 Ok(Self {
1246 ctx: ctx.clone(),
1247 ptr,
1248 })
1249 }
1250}
1251
1252impl Drop for PeerProbeBuffer {
1253 fn drop(&mut self) {
1254 if self.ctx.bind_to_thread().is_ok() {
1255 let _ = unsafe { cudarc::driver::result::free_sync(self.ptr) };
1256 }
1257 }
1258}
1259
1260fn peer_probe_copy(
1261 src: &StageRt,
1262 dst: &StageRt,
1263 expected: &[u8],
1264) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
1265 let bytes = expected.len();
1266 let src_buf = PeerProbeBuffer::new(&src.ctx, bytes)?;
1267 unsafe {
1268 cudarc::driver::result::memcpy_htod_sync(src_buf.ptr, expected)?;
1269 }
1270
1271 let dst_buf = PeerProbeBuffer::new(&dst.ctx, bytes)?;
1272 let poison: Vec<u8> = expected.iter().map(|b| !b).collect();
1273 unsafe {
1274 cudarc::driver::result::memcpy_htod_sync(dst_buf.ptr, &poison)?;
1275 }
1276
1277 src.ctx.bind_to_thread()?;
1278 unsafe {
1279 cudarc::driver::result::memcpy_peer_async(
1280 dst.ctx.cu_ctx(),
1281 dst_buf.ptr,
1282 src.ctx.cu_ctx(),
1283 src_buf.ptr,
1284 bytes,
1285 src.stream.cu_stream(),
1286 )?;
1287 }
1288
1289 let published = src.ctx.new_event(None)?;
1295 published.record(&src.stream)?;
1296
1297 dst.ctx.bind_to_thread()?;
1298 dst.stream.wait(&published)?;
1299 dst.stream.synchronize()?;
1300 let mut readback = vec![0u8; bytes];
1301 unsafe {
1302 cudarc::driver::result::memcpy_dtoh_sync(&mut readback, dst_buf.ptr)?;
1303 }
1304 Ok(readback)
1305}
1306
1307fn run_peer_probe_pass(
1308 stages: &[StageRt],
1309 peer_capable: &[(usize, usize)],
1310 host_bounce: bool,
1311 label: &str,
1312 bytes: usize,
1313) -> Result<(), Box<dyn std::error::Error>> {
1314 if bytes == 0 {
1315 return Err(format!("PP peer byte-integrity probe {label} size is zero").into());
1316 }
1317 let started = std::time::Instant::now();
1318 let mut copies = 0usize;
1319 let mut skipped = 0usize;
1320 let mut total_mismatches = 0usize;
1321
1322 for boundary in 0..stages.len() - 1 {
1323 if stages[boundary].dev == stages[boundary + 1].dev {
1324 continue;
1325 }
1326 for (src_idx, dst_idx) in [(boundary, boundary + 1), (boundary + 1, boundary)] {
1327 let src = &stages[src_idx];
1328 let dst = &stages[dst_idx];
1329 if !peer_capable.contains(&(src.dev, dst.dev)) {
1330 if host_bounce {
1331 skipped += 1;
1332 eprintln!(
1333 "[pp] peer byte-integrity probe SKIP: boundary={boundary} \
1334 dev{}->dev{} label={label} bytes={bytes} (peer capability unavailable; \
1335 MEMRA_PP_HOST_BOUNCE=1 remains fail-safe)",
1336 src.dev, dst.dev,
1337 );
1338 continue;
1339 }
1340 return Err(format!(
1341 "PP peer byte-integrity probe cannot run boundary={boundary} \
1342 dev{}->dev{}: peer access was not enabled",
1343 src.dev, dst.dev,
1344 )
1345 .into());
1346 }
1347
1348 let expected = peer_probe_pattern(bytes, boundary, src.dev, dst.dev);
1349 let readback = match peer_probe_copy(src, dst, &expected) {
1350 Ok(readback) => readback,
1351 Err(err) if host_bounce => {
1352 skipped += 1;
1353 eprintln!(
1354 "[pp] peer byte-integrity probe ERROR: boundary={boundary} \
1355 dev{}->dev{} label={label} bytes={bytes}: {err}; \
1356 MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path",
1357 src.dev, dst.dev,
1358 );
1359 continue;
1360 }
1361 Err(err) => {
1362 return Err(format!(
1363 "PP peer byte-integrity probe FAILED: boundary={boundary} \
1364 dev{}->dev{} label={label} bytes={bytes}: {err}; refusing native P2P \
1365 (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
1366 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)",
1367 src.dev, dst.dev,
1368 )
1369 .into());
1370 }
1371 };
1372 copies += 1;
1373 match peer_probe_decision(&expected, &readback, host_bounce) {
1374 Ok(PeerProbeDecision::Clean) => {}
1375 Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches }) => {
1376 total_mismatches += mismatches;
1377 eprintln!(
1378 "[pp] peer byte-integrity probe CORRUPTION: boundary={boundary} \
1379 dev{}->dev{} label={label} bytes={bytes} mismatches={mismatches}; \
1380 MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path",
1381 src.dev, dst.dev,
1382 );
1383 }
1384 Err(mismatch) => {
1385 return Err(format!(
1386 "PP peer byte-integrity probe FAILED: boundary={boundary} \
1387 dev{}->dev{} label={label} bytes={bytes}: {mismatch}; refusing native \
1388 P2P (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
1389 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)",
1390 src.dev, dst.dev,
1391 )
1392 .into());
1393 }
1394 }
1395 }
1396 }
1397
1398 let status = if total_mismatches > 0 {
1399 "BOUNCE"
1400 } else if skipped > 0 && copies > 0 {
1401 "PARTIAL"
1402 } else if skipped > 0 {
1403 "SKIP"
1404 } else {
1405 "PASS"
1406 };
1407 eprintln!(
1408 "[pp] peer byte-integrity probe {}: label={label} bytes={bytes} copies={copies} \
1409 skipped={skipped} mismatches={total_mismatches} elapsed_ms={:.3}",
1410 status,
1411 started.elapsed().as_secs_f64() * 1e3,
1412 );
1413 Ok(())
1414}
1415
1416fn host_bounce_capacity(n_embd: usize) -> Result<(usize, usize), String> {
1417 if n_embd == 0 {
1418 return Err("MEMRA_PP_HOST_BOUNCE needs non-zero model n_embd".into());
1419 }
1420 let elems = n_embd
1421 .checked_mul(crate::cache::PRIME_CHUNK_MAX_TOKENS)
1422 .ok_or_else(|| format!("host-bounce element count overflows for n_embd={n_embd}"))?;
1423 let bytes = elems
1424 .checked_mul(std::mem::size_of::<f32>())
1425 .ok_or_else(|| format!("host-bounce byte count overflows for n_embd={n_embd}"))?;
1426 Ok((elems, bytes))
1427}
1428
1429fn boundary_slot_growth_elements(current: [usize; 2], required: usize) -> usize {
1430 current.into_iter().fold(0usize, |total, len| {
1431 total.saturating_add(required.saturating_sub(len))
1432 })
1433}
1434
1435struct PinnedHostBounce {
1440 ptr: *mut f32,
1441 len: usize,
1442}
1443
1444unsafe impl Send for PinnedHostBounce {}
1445unsafe impl Sync for PinnedHostBounce {}
1446
1447impl PinnedHostBounce {
1448 fn new(len: usize) -> Result<Self, Box<dyn std::error::Error>> {
1449 let bytes = len
1450 .checked_mul(std::mem::size_of::<f32>())
1451 .ok_or("host-bounce pinned allocation size overflow")?;
1452 let ptr = unsafe {
1453 cudarc::driver::result::malloc_host(
1454 bytes,
1455 cudarc::driver::sys::CU_MEMHOSTALLOC_PORTABLE,
1456 )?
1457 } as *mut f32;
1458 if ptr.is_null() {
1459 return Err("cuMemHostAlloc returned a null host-bounce pointer".into());
1460 }
1461 Ok(Self { ptr, len })
1462 }
1463
1464 fn prefix(&self, n: usize) -> &[f32] {
1465 assert!(
1466 n <= self.len,
1467 "host-bounce source {n} > capacity {}",
1468 self.len
1469 );
1470 unsafe { std::slice::from_raw_parts(self.ptr, n) }
1471 }
1472
1473 fn prefix_mut(&mut self, n: usize) -> &mut [f32] {
1474 assert!(
1475 n <= self.len,
1476 "host-bounce destination {n} > capacity {}",
1477 self.len
1478 );
1479 unsafe { std::slice::from_raw_parts_mut(self.ptr, n) }
1480 }
1481}
1482
1483impl Drop for PinnedHostBounce {
1484 fn drop(&mut self) {
1485 let _ = unsafe { cudarc::driver::result::free_host(self.ptr.cast()) };
1486 }
1487}
1488
1489struct HostBounceRt {
1490 n_embd: usize,
1491 capacity: usize,
1492 slots: Vec<Option<[Mutex<PinnedHostBounce>; 2]>>,
1493}
1494
1495impl HostBounceRt {
1496 fn new(n_embd: usize, boundaries: &[BoundaryRt]) -> Result<Self, Box<dyn std::error::Error>> {
1497 let (capacity, _) = host_bounce_capacity(n_embd)?;
1498 let mut slots = Vec::with_capacity(boundaries.len());
1499 for boundary in boundaries {
1500 slots.push(if boundary.cross {
1501 Some([
1502 Mutex::new(PinnedHostBounce::new(capacity)?),
1503 Mutex::new(PinnedHostBounce::new(capacity)?),
1504 ])
1505 } else {
1506 None
1507 });
1508 }
1509 Ok(Self {
1510 n_embd,
1511 capacity,
1512 slots,
1513 })
1514 }
1515
1516 fn slot(
1517 &self,
1518 boundary: usize,
1519 slot: usize,
1520 ) -> Result<&Mutex<PinnedHostBounce>, Box<dyn std::error::Error>> {
1521 self.slots
1522 .get(boundary)
1523 .and_then(Option::as_ref)
1524 .and_then(|slots| slots.get(slot))
1525 .ok_or_else(|| format!("host-bounce slot {boundary}:{slot} is not initialized").into())
1526 }
1527}
1528
1529pub struct PpNRt {
1530 stages: Vec<StageRt>,
1531 boundaries: Vec<BoundaryRt>,
1532 walk_active: Arc<AtomicU64>,
1536 walk_next: AtomicU64,
1537 deferred_walk: Mutex<Weak<PpWalkState>>,
1541 cross_any: bool,
1543 host_bounce: bool,
1546 peer_probe: bool,
1548 peer_capable: Vec<(usize, usize)>,
1550 peer_probe_geometry: OnceLock<Result<usize, String>>,
1552 bounce: OnceLock<Result<HostBounceRt, String>>,
1554 readback: Arc<CudaStream>,
1557}
1558
1559#[derive(Debug)]
1560struct PpWalkState {
1561 active: Arc<AtomicU64>,
1562 generation: u64,
1563 runtime_id: usize,
1564 deferred_owner: Option<std::thread::ThreadId>,
1565}
1566
1567impl PpWalkState {
1568 fn is_active(&self) -> bool {
1569 self.active.load(Ordering::Acquire) == self.generation
1570 }
1571}
1572
1573impl Drop for PpWalkState {
1574 fn drop(&mut self) {
1575 let _ =
1576 self.active
1577 .compare_exchange(self.generation, 0, Ordering::AcqRel, Ordering::Acquire);
1578 }
1579}
1580
1581#[derive(Debug)]
1585pub struct PpWalkLease {
1586 state: Arc<PpWalkState>,
1587}
1588
1589#[derive(Clone, Debug)]
1591pub(crate) struct PpWalkPermit {
1592 state: Arc<PpWalkState>,
1593}
1594
1595thread_local! {
1596 static PP_WALK_BORROWS: RefCell<Vec<Arc<PpWalkState>>> = const { RefCell::new(Vec::new()) };
1597}
1598
1599pub(crate) struct PpWalkBorrowGuard {
1602 prior_len: usize,
1603 _not_send: PhantomData<Rc<()>>,
1604}
1605
1606impl Drop for PpWalkBorrowGuard {
1607 fn drop(&mut self) {
1608 PP_WALK_BORROWS.with(|borrows| borrows.borrow_mut().truncate(self.prior_len));
1609 }
1610}
1611
1612fn next_pp_walk_generation(next: &AtomicU64) -> u64 {
1613 loop {
1614 let generation = next.fetch_add(1, Ordering::Relaxed);
1615 if generation != 0 {
1616 return generation;
1617 }
1618 }
1619}
1620
1621fn acquire_pp_walk(
1622 active: &Arc<AtomicU64>,
1623 next: &AtomicU64,
1624 runtime_id: usize,
1625 deferred_owner: Option<std::thread::ThreadId>,
1626 path: &str,
1627) -> Result<PpWalkLease, String> {
1628 let generation = next_pp_walk_generation(next);
1629 active
1630 .compare_exchange(0, generation, Ordering::AcqRel, Ordering::Acquire)
1631 .map_err(|_| {
1632 format!(
1633 "{path}: refused concurrent PP walk; shared boundary slots already have an owner"
1634 )
1635 })?;
1636 Ok(PpWalkLease {
1637 state: Arc::new(PpWalkState {
1638 active: active.clone(),
1639 generation,
1640 runtime_id,
1641 deferred_owner,
1642 }),
1643 })
1644}
1645
1646fn borrowed_pp_walk(runtime_id: usize) -> Option<PpWalkLease> {
1647 PP_WALK_BORROWS.with(|borrows| {
1648 borrows
1649 .borrow()
1650 .iter()
1651 .rev()
1652 .find(|state| state.runtime_id == runtime_id && state.is_active())
1653 .cloned()
1654 .map(|state| PpWalkLease { state })
1655 })
1656}
1657
1658fn lock_deferred_walk<'a>(
1659 deferred: &'a Mutex<Weak<PpWalkState>>,
1660 path: &str,
1661) -> Result<std::sync::MutexGuard<'a, Weak<PpWalkState>>, String> {
1662 deferred
1663 .lock()
1664 .map_err(|_| format!("{path}: deferred PP walk owner lock is poisoned"))
1665}
1666
1667fn validate_walk_state(state: &PpWalkState, runtime_id: usize, path: &str) -> Result<(), String> {
1668 if state.runtime_id != runtime_id {
1669 return Err(format!(
1670 "{path}: PP walk permit belongs to a different runtime"
1671 ));
1672 }
1673 if !state.is_active() {
1674 return Err(format!(
1675 "{path}: PP walk permit generation is no longer active"
1676 ));
1677 }
1678 Ok(())
1679}
1680
1681pub type Pp2Rt = PpNRt;
1683
1684static RTN: OnceLock<Result<PpNRt, String>> = OnceLock::new();
1685
1686impl PpNRt {
1687 pub fn get(e: &Engine) -> Result<&'static PpNRt, Box<dyn std::error::Error>> {
1691 RTN.get_or_init(|| Self::build(e).map_err(|err| err.to_string()))
1692 .as_ref()
1693 .map_err(|s| -> Box<dyn std::error::Error> { s.clone().into() })
1694 }
1695
1696 fn build(e: &Engine) -> Result<PpNRt, Box<dyn std::error::Error>> {
1697 pp_wave_on().map_err(|reason| -> Box<dyn std::error::Error> { reason.into() })?;
1700 let primary_dev = e.ctx().ordinal();
1701 let devices: Vec<usize> =
1704 match pp2_devices_env() {
1705 Some(s) => {
1706 let parts: Result<Vec<usize>, _> =
1707 s.split(',').map(|p| p.trim().parse::<usize>()).collect();
1708 match parts {
1709 Ok(v) if v.len() >= 2 => v,
1710 _ => return Err(format!(
1711 "MEMRA_PP_DEVICES={s} unparseable (want <d0>,..,<dN-1> e.g. 0,1,2,3)"
1712 )
1713 .into()),
1714 }
1715 }
1716 None => {
1717 let n_st = std::env::var("MEMRA_PP_STAGES")
1718 .ok()
1719 .and_then(|v| v.parse::<usize>().ok())
1720 .filter(|&n| n >= 2)
1721 .unwrap_or(2);
1722 vec![primary_dev; n_st]
1723 }
1724 };
1725 if let Ok(v) = std::env::var("MEMRA_PP_STAGES")
1726 && let Ok(n) = v.parse::<usize>()
1727 && n >= 2
1728 && n != devices.len()
1729 {
1730 return Err(format!(
1731 "MEMRA_PP_DEVICES lists {} devices but MEMRA_PP_STAGES={n} — \
1732 refusing an ambiguous placement",
1733 devices.len()
1734 )
1735 .into());
1736 }
1737 let n_st = devices.len();
1738 let cross_any = devices.iter().any(|&d| d != devices[0]);
1739 let host_bounce = pp_host_bounce_on();
1740 let peer_probe = peer_probe_on();
1741 let sharded_cross_device = cross_any && !pp_shard_off();
1742 if host_bounce && cross_any {
1743 if pp_shard_off() {
1744 return Err(
1745 "MEMRA_PP_HOST_BOUNCE=1 refuses MEMRA_PP_SHARD=0: the boundary can bounce, \
1746 but remote stages would still peer-read primary-device weights"
1747 .into(),
1748 );
1749 }
1750 if devices.last().copied() != Some(primary_dev) {
1751 return Err(format!(
1752 "MEMRA_PP_HOST_BOUNCE=1 requires the primary engine on the last/head stage \
1753 (primary dev{primary_dev}, placement {devices:?}); otherwise returned \
1754 logits/hidden state remain peer reads"
1755 )
1756 .into());
1757 }
1758 }
1759 let peer_probe_policy =
1760 peer_probe_startup_policy(peer_probe, sharded_cross_device, host_bounce)?;
1761 if peer_probe_policy == PeerProbeStartupPolicy::BypassedWithHostBounce {
1762 PEER_PROBE_BYPASSED.fetch_add(1, Ordering::Relaxed);
1763 eprintln!(
1764 "[pp] SECURITY RED: peer_probe_bypassed: MEMRA_PEER_PROBE=0 on a sharded \
1765 cross-device placement; MEMRA_PP_HOST_BOUNCE=1 is the only enabled transport"
1766 );
1767 }
1768
1769 let mut used: Vec<usize> = devices.clone();
1773 used.push(primary_dev);
1774 used.sort_unstable();
1775 used.dedup();
1776 let mut peer_capable = Vec::new();
1777 if used.len() > 1 {
1778 let n = cudarc::driver::result::device::get_count()? as usize;
1779 for &d in &used {
1780 if d >= n {
1781 return Err(format!(
1782 "MEMRA_PP_DEVICES={devices:?} but only {n} CUDA device(s) present"
1783 )
1784 .into());
1785 }
1786 }
1787 if !host_bounce || peer_probe {
1788 for &a in &used {
1789 for &b in &used {
1790 if a == b {
1791 continue;
1792 }
1793 let da = cudarc::driver::result::device::get(a as i32)?;
1794 let db = cudarc::driver::result::device::get(b as i32)?;
1795 let mut can: i32 = 0;
1796 let capability = unsafe {
1797 cudarc::driver::sys::cuDeviceCanAccessPeer(&mut can, da, db).result()
1798 };
1799 if let Err(err) = capability {
1800 if host_bounce {
1801 eprintln!(
1802 "[pp] peer byte-integrity probe capability query failed for \
1803 dev{a}->dev{b}: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
1804 );
1805 continue;
1806 }
1807 return Err(err.into());
1808 }
1809 if can == 0 {
1810 if !host_bounce {
1811 return Err(format!(
1812 "device {a} cannot peer-access device {b} \
1813 (cuDeviceCanAccessPeer=0); ppN cross-device needs P2P — \
1814 refusing a silently-staged path"
1815 )
1816 .into());
1817 }
1818 } else {
1819 peer_capable.push((a, b));
1820 }
1821 }
1822 }
1823 }
1824 }
1825
1826 let mk_stage = |dev: usize, s: usize| -> Result<StageRt, Box<dyn std::error::Error>> {
1839 if dev == primary_dev && s == 0 {
1840 let ctx = e.ctx().clone();
1841 let stream = ctx.new_stream()?;
1842 let blas = Arc::new(cudarc::cublaslt::CudaBlasLT::new(stream.clone())?);
1843 Ok(StageRt {
1844 dev,
1845 ctx,
1846 stream,
1847 blas,
1848 engine: None,
1849 })
1850 } else {
1851 let eng = Engine::new(dev)?;
1852 let ctx = eng.ctx().clone();
1853 let stream = ctx.new_stream()?;
1854 let blas = Arc::new(cudarc::cublaslt::CudaBlasLT::new(stream.clone())?);
1855 Ok(StageRt {
1856 dev,
1857 ctx,
1858 stream,
1859 blas,
1860 engine: Some(eng),
1861 })
1862 }
1863 };
1864 let mut stages = Vec::with_capacity(n_st);
1865 for (s, &d) in devices.iter().enumerate() {
1866 stages.push(mk_stage(d, s)?);
1867 }
1868
1869 if cross_any
1870 && !peer_probe
1871 && peer_probe_policy != PeerProbeStartupPolicy::BypassedWithHostBounce
1872 {
1873 eprintln!(
1874 "[pp] WARNING: MEMRA_PEER_PROBE=0 skips the boot-time peer byte-integrity \
1875 gate; diagnostics escape hatch active"
1876 );
1877 }
1878
1879 if used.len() > 1 {
1880 if !host_bounce {
1881 let ctx_of = |d: usize| -> &Arc<CudaContext> {
1884 if d == primary_dev {
1885 e.ctx()
1886 } else {
1887 &stages.iter().find(|s| s.dev == d).unwrap().ctx
1888 }
1889 };
1890 for &a in &used {
1893 for &b in &used {
1894 if a == b {
1895 continue;
1896 }
1897 ctx_of(a).bind_to_thread()?;
1898 let rc = unsafe {
1899 cudarc::driver::sys::cuCtxEnablePeerAccess(ctx_of(b).cu_ctx(), 0)
1900 };
1901 use cudarc::driver::sys::cudaError_enum as E;
1902 if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED
1903 {
1904 return Err(format!(
1905 "cuCtxEnablePeerAccess(dev{a} -> dev{b}) failed: {rc:?}"
1906 )
1907 .into());
1908 }
1909 }
1910 }
1911 if peer_probe && cross_any {
1915 let probe = run_peer_probe_pass(
1916 &stages,
1917 &peer_capable,
1918 host_bounce,
1919 "fixed-16KiB",
1920 PEER_PROBE_FIXED_BYTES,
1921 );
1922 e.ctx().bind_to_thread()?;
1923 probe?;
1924 }
1925 for &owner in &used {
1934 for &accessor in &used {
1935 if owner == accessor {
1936 continue;
1937 }
1938 let dev = cudarc::driver::result::device::get(owner as i32)?;
1939 let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
1940 unsafe {
1941 cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev)
1942 .result()?;
1943 }
1944 let desc = cudarc::driver::sys::CUmemAccessDesc {
1945 location: cudarc::driver::sys::CUmemLocation {
1946 type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
1947 id: accessor as i32,
1948 },
1949 flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
1950 };
1951 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
1952 if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
1953 return Err(format!(
1954 "cuMemPoolSetAccess(dev{owner} pool -> dev{accessor}) failed: {rc:?}"
1955 )
1956 .into());
1957 }
1958 }
1959 }
1960 for (owner, accessor) in [
1969 (stages[0].dev, stages[1].dev),
1970 (stages[1].dev, stages[0].dev),
1971 ] {
1972 let dev = cudarc::driver::result::device::get(owner as i32)?;
1973 let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
1974 unsafe {
1975 cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
1976 }
1977 let desc = cudarc::driver::sys::CUmemAccessDesc {
1978 location: cudarc::driver::sys::CUmemLocation {
1979 type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
1980 id: accessor as i32,
1981 },
1982 flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
1983 };
1984 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
1985 if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
1986 return Err(format!(
1987 "cuMemPoolSetAccess(dev{owner} pool -> dev{accessor}) failed: {rc:?}"
1988 )
1989 .into());
1990 }
1991 }
1992 e.ctx().bind_to_thread()?;
1994 eprintln!(
1995 "[pp] cross-device transport: {} (cudaMemcpyPeerAsync per cross boundary; \
1996 peer + default-pool access granted all pairs over {used:?}; weight home: {})",
1997 devices
1998 .iter()
1999 .enumerate()
2000 .map(|(s, d)| format!("stage{s}=dev{d}"))
2001 .collect::<Vec<_>>()
2002 .join(" "),
2003 if pp_shard_off() {
2004 format!("dev{primary_dev} (MEMRA_PP_SHARD=0 bring-up placement)")
2005 } else {
2006 "per-stage (sharded loader)".to_string()
2007 }
2008 );
2009 } else {
2010 e.ctx().bind_to_thread()?;
2011 eprintln!(
2012 "[pp] cross-device transport: {} (HOST-STAGED pinned D2H -> H2D per cross \
2013 boundary; MEMRA_PP_HOST_BOUNCE=1; peer-pool grants bypassed; \
2014 diagnostic peer access is removed before host-staged serving; \
2015 weight home: per-stage (sharded loader))",
2016 devices
2017 .iter()
2018 .enumerate()
2019 .map(|(s, d)| format!("stage{s}=dev{d}"))
2020 .collect::<Vec<_>>()
2021 .join(" "),
2022 );
2023 }
2024 }
2025
2026 let mk_slot =
2027 |tx: &StageRt, rx: &StageRt| -> Result<BoundarySlot, Box<dyn std::error::Error>> {
2028 Ok(BoundarySlot {
2029 buf: Mutex::new(None),
2030 ev_tx: tx.ctx.new_event(None)?,
2031 ev_rx: rx.ctx.new_event(None)?,
2032 })
2033 };
2034 let mut boundaries = Vec::with_capacity(n_st - 1);
2035 for b in 0..n_st - 1 {
2036 let (tx, rx) = (&stages[b], &stages[b + 1]);
2037 boundaries.push(BoundaryRt {
2038 slots: [mk_slot(tx, rx)?, mk_slot(tx, rx)?],
2039 step: AtomicUsize::new(0),
2040 cross: tx.dev != rx.dev,
2041 });
2042 }
2043 let readback = stages[n_st - 1].ctx.new_stream()?;
2044 let rt = PpNRt {
2045 stages,
2046 boundaries,
2047 walk_active: Arc::new(AtomicU64::new(0)),
2048 walk_next: AtomicU64::new(1),
2049 deferred_walk: Mutex::new(Weak::new()),
2050 cross_any,
2051 host_bounce,
2052 peer_probe,
2053 peer_capable,
2054 peer_probe_geometry: OnceLock::new(),
2055 bounce: OnceLock::new(),
2056 readback,
2057 };
2058 if rt.peer_probe && rt.cross_any && rt.host_bounce {
2059 rt.run_host_bounce_legacy_probe(e)?;
2060 }
2061 Ok(rt)
2062 }
2063
2064 pub fn n_stages(&self) -> usize {
2065 self.stages.len()
2066 }
2067
2068 pub fn acquire_walk(
2072 &'static self,
2073 path: &str,
2074 ) -> Result<PpWalkLease, Box<dyn std::error::Error>> {
2075 let runtime_id = self as *const Self as usize;
2076 if let Some(lease) = borrowed_pp_walk(runtime_id) {
2077 return Ok(lease);
2078 }
2079 acquire_pp_walk(&self.walk_active, &self.walk_next, runtime_id, None, path)
2080 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })
2081 }
2082
2083 pub(crate) fn acquire_deferred_walk(
2086 &'static self,
2087 path: &str,
2088 ) -> Result<PpWalkLease, Box<dyn std::error::Error>> {
2089 let runtime_id = self as *const Self as usize;
2090 let current_thread = std::thread::current().id();
2091 let mut weak = lock_deferred_walk(&self.deferred_walk, path)
2092 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2093 if let Some(state) = weak.upgrade() {
2094 validate_walk_state(&state, runtime_id, path)
2095 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2096 if state.deferred_owner.as_ref() != Some(¤t_thread) {
2097 return Err(format!(
2098 "{path}: refused cross-thread join of the active deferred PP window"
2099 )
2100 .into());
2101 }
2102 return Ok(PpWalkLease { state });
2103 }
2104 let lease = acquire_pp_walk(
2105 &self.walk_active,
2106 &self.walk_next,
2107 runtime_id,
2108 Some(current_thread),
2109 path,
2110 )
2111 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2112 *weak = Arc::downgrade(&lease.state);
2113 Ok(lease)
2114 }
2115
2116 pub(crate) fn walk_permit(
2119 &'static self,
2120 lease: &PpWalkLease,
2121 path: &str,
2122 ) -> Result<PpWalkPermit, Box<dyn std::error::Error>> {
2123 let runtime_id = self as *const Self as usize;
2124 validate_walk_state(&lease.state, runtime_id, path)
2125 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2126 if lease.state.deferred_owner.is_some() {
2127 return Err(
2128 format!("{path}: deferred PP windows cannot mint coordinator permits").into(),
2129 );
2130 }
2131 Ok(PpWalkPermit {
2132 state: lease.state.clone(),
2133 })
2134 }
2135
2136 pub(crate) fn borrow_walk(
2138 &'static self,
2139 permit: &PpWalkPermit,
2140 path: &str,
2141 ) -> Result<PpWalkBorrowGuard, Box<dyn std::error::Error>> {
2142 let runtime_id = self as *const Self as usize;
2143 validate_walk_state(&permit.state, runtime_id, path)
2144 .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2145 let prior_len = PP_WALK_BORROWS.with(|borrows| {
2146 let mut borrows = borrows.borrow_mut();
2147 let prior_len = borrows.len();
2148 borrows.push(permit.state.clone());
2149 prior_len
2150 });
2151 Ok(PpWalkBorrowGuard {
2152 prior_len,
2153 _not_send: PhantomData,
2154 })
2155 }
2156
2157 pub fn cross_device(&self) -> bool {
2159 self.cross_any
2160 }
2161
2162 pub fn host_bounce_active(&self) -> bool {
2163 self.host_bounce || PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire)
2164 }
2165
2166 pub fn repeated_stage_device(&self) -> bool {
2169 let mut devices: Vec<_> = self.stages.iter().map(|stage| stage.dev).collect();
2170 devices.sort_unstable();
2171 devices.dedup();
2172 devices.len() != self.stages.len()
2173 }
2174
2175 fn context_for_dev<'a>(
2176 &'a self,
2177 e: &'a Engine,
2178 dev: usize,
2179 ) -> Result<&'a Arc<CudaContext>, Box<dyn std::error::Error>> {
2180 if dev == e.ctx().ordinal() {
2181 return Ok(e.ctx());
2182 }
2183 self.stages
2184 .iter()
2185 .find(|stage| stage.dev == dev)
2186 .map(|stage| &stage.ctx)
2187 .ok_or_else(|| format!("PP peer probe has no CUDA context for dev{dev}").into())
2188 }
2189
2190 fn enable_probe_peer_access(
2191 &self,
2192 e: &Engine,
2193 pairs: &[(usize, usize)],
2194 ) -> Result<Vec<(usize, usize)>, Box<dyn std::error::Error>> {
2195 let mut enabled = Vec::new();
2196 for &(src_dev, dst_dev) in pairs {
2197 let enable = (|| -> Result<(), Box<dyn std::error::Error>> {
2198 let src_ctx = self.context_for_dev(e, src_dev)?;
2199 let dst_ctx = self.context_for_dev(e, dst_dev)?;
2200 src_ctx.bind_to_thread()?;
2201 let rc = unsafe { cudarc::driver::sys::cuCtxEnablePeerAccess(dst_ctx.cu_ctx(), 0) };
2202 use cudarc::driver::sys::cudaError_enum as E;
2203 if rc == E::CUDA_SUCCESS || rc == E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
2204 Ok(())
2205 } else {
2206 Err(format!("{rc:?}").into())
2207 }
2208 })();
2209 if let Err(err) = enable {
2210 eprintln!(
2211 "[pp] peer byte-integrity probe could not enable \
2212 dev{src_dev}->dev{dst_dev}: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
2213 );
2214 } else {
2215 enabled.push((src_dev, dst_dev));
2216 }
2217 }
2218 Ok(enabled)
2219 }
2220
2221 fn disable_probe_peer_access(
2222 &self,
2223 e: &Engine,
2224 pairs: &[(usize, usize)],
2225 ) -> Result<(), Box<dyn std::error::Error>> {
2226 let mut failures = Vec::new();
2227 for &(src_dev, dst_dev) in pairs {
2228 let disable = (|| -> Result<(), Box<dyn std::error::Error>> {
2229 let src_ctx = self.context_for_dev(e, src_dev)?;
2230 let dst_ctx = self.context_for_dev(e, dst_dev)?;
2231 src_ctx.bind_to_thread()?;
2232 let rc = unsafe { cudarc::driver::sys::cuCtxDisablePeerAccess(dst_ctx.cu_ctx()) };
2233 use cudarc::driver::sys::cudaError_enum as E;
2234 if rc == E::CUDA_SUCCESS || rc == E::CUDA_ERROR_PEER_ACCESS_NOT_ENABLED {
2235 Ok(())
2236 } else {
2237 Err(format!("{rc:?}").into())
2238 }
2239 })();
2240 if let Err(err) = disable {
2241 failures.push(format!("dev{src_dev}->dev{dst_dev}: {err}"));
2242 }
2243 }
2244 e.ctx().bind_to_thread()?;
2245 if failures.is_empty() {
2246 eprintln!(
2247 "[pp] peer byte-integrity probe teardown: disabled {} diagnostic pair(s); \
2248 host-bounce serving has no probe-enabled peer access",
2249 pairs.len(),
2250 );
2251 Ok(())
2252 } else {
2253 Err(format!(
2254 "PP peer probe could not disable diagnostic peer access ({}); \
2255 refusing host-bounce serving",
2256 failures.join(", "),
2257 )
2258 .into())
2259 }
2260 }
2261
2262 fn grant_probe_pool_access(
2263 &self,
2264 e: &Engine,
2265 pairs: &[(usize, usize)],
2266 ) -> Result<Vec<(usize, usize)>, Box<dyn std::error::Error>> {
2267 let mut granted = Vec::new();
2268 for &(src_dev, dst_dev) in pairs {
2269 let grant = (|| -> 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:
2282 cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
2283 };
2284 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
2285 if rc == cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
2286 Ok(())
2287 } else {
2288 Err(format!("{rc:?}").into())
2289 }
2290 })();
2291 if let Err(err) = grant {
2292 eprintln!(
2293 "[pp] production-slot probe could not grant dev{src_dev} access to \
2294 dev{dst_dev}'s default pool: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
2295 );
2296 } else {
2297 granted.push((src_dev, dst_dev));
2298 }
2299 }
2300 Ok(granted)
2301 }
2302
2303 fn revoke_probe_pool_access(
2304 &self,
2305 e: &Engine,
2306 pairs: &[(usize, usize)],
2307 ) -> Result<(), Box<dyn std::error::Error>> {
2308 let mut failures = Vec::new();
2309 for &(src_dev, dst_dev) in pairs {
2310 let revoke = (|| -> Result<(), Box<dyn std::error::Error>> {
2311 self.context_for_dev(e, dst_dev)?.bind_to_thread()?;
2312 let dev = cudarc::driver::result::device::get(dst_dev as i32)?;
2313 let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
2314 unsafe {
2315 cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
2316 }
2317 let desc = cudarc::driver::sys::CUmemAccessDesc {
2318 location: cudarc::driver::sys::CUmemLocation {
2319 type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
2320 id: src_dev as i32,
2321 },
2322 flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_NONE,
2323 };
2324 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
2325 if rc == cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
2326 Ok(())
2327 } else {
2328 Err(format!("{rc:?}").into())
2329 }
2330 })();
2331 if let Err(err) = revoke {
2332 failures.push(format!("dev{src_dev}->dev{dst_dev}: {err}"));
2333 }
2334 }
2335 e.ctx().bind_to_thread()?;
2336 if failures.is_empty() {
2337 Ok(())
2338 } else {
2339 Err(format!(
2340 "PP peer probe could not revoke diagnostic pool access ({}); \
2341 refusing host-bounce serving",
2342 failures.join(", "),
2343 )
2344 .into())
2345 }
2346 }
2347
2348 fn run_host_bounce_legacy_probe(&self, e: &Engine) -> Result<(), Box<dyn std::error::Error>> {
2349 let enabled = self.enable_probe_peer_access(e, &self.peer_capable)?;
2350 let probe = run_peer_probe_pass(
2351 &self.stages,
2352 &enabled,
2353 true,
2354 "fixed-16KiB-legacy-preflight",
2355 PEER_PROBE_FIXED_BYTES,
2356 );
2357 let disable = self.disable_probe_peer_access(e, &enabled);
2358 disable?;
2359 probe
2360 }
2361
2362 fn new_peer_probe_boundary(
2363 &self,
2364 src_stage: usize,
2365 dst_stage: usize,
2366 ) -> Result<BoundaryRt, Box<dyn std::error::Error>> {
2367 let tx = &self.stages[src_stage];
2368 let rx = &self.stages[dst_stage];
2369 let mk_slot = || -> Result<BoundarySlot, Box<dyn std::error::Error>> {
2370 Ok(BoundarySlot {
2371 buf: Mutex::new(None),
2372 ev_tx: tx.ctx.new_event(None)?,
2373 ev_rx: rx.ctx.new_event(None)?,
2374 })
2375 };
2376 Ok(BoundaryRt {
2377 slots: [mk_slot()?, mk_slot()?],
2378 step: AtomicUsize::new(0),
2379 cross: tx.dev != rx.dev,
2380 })
2381 }
2382
2383 fn production_probe_readback(
2384 &self,
2385 path: BoundaryPath,
2386 boundary: &BoundaryRt,
2387 expected: &[u8],
2388 n: usize,
2389 slot_idx: usize,
2390 ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
2391 debug_assert_eq!(expected.len(), n * std::mem::size_of::<f32>());
2392 let host = peer_probe_bytes_to_f32(expected);
2393 let poison_bytes: Vec<u8> = expected.iter().map(|byte| !byte).collect();
2394 let poison = peer_probe_bytes_to_f32(&poison_bytes);
2395 let src = &self.stages[path.src_stage];
2396 let dst = &self.stages[path.dst_stage];
2397
2398 dst.ctx.bind_to_thread()?;
2401 let poison_buf = dst.stream.clone_htod(&poison)?;
2402 dst.stream.synchronize()?;
2403 let replaced = boundary.slots[slot_idx]
2404 .buf
2405 .lock()
2406 .unwrap()
2407 .replace(poison_buf);
2408 drop(replaced);
2409 dst.stream.synchronize()?;
2410
2411 src.ctx.bind_to_thread()?;
2412 let x = src.stream.clone_htod(&host)?;
2413 self.tx_slot_path(path, boundary, &x, n, slot_idx)?;
2414
2415 dst.ctx.bind_to_thread()?;
2416 let work = self.rx_slot_path(path, boundary, slot_idx, n)?;
2417 let back = dst.stream.clone_dtoh(&work)?;
2418 dst.stream.synchronize()?;
2419 Ok(peer_probe_f32_to_bytes(&back))
2420 }
2421
2422 fn clear_peer_probe_boundary(
2423 &self,
2424 boundary: &BoundaryRt,
2425 src_stage: usize,
2426 dst_stage: usize,
2427 ) -> Result<(), Box<dyn std::error::Error>> {
2428 self.stages[dst_stage].ctx.bind_to_thread()?;
2429 for slot in &boundary.slots {
2430 let buffer = slot.buf.lock().unwrap().take();
2431 drop(buffer);
2432 }
2433 self.stages[src_stage].stream.synchronize()?;
2434 self.stages[dst_stage].stream.synchronize()?;
2435 Ok(())
2436 }
2437
2438 fn run_production_peer_probe_widths(
2439 &self,
2440 enabled_pairs: &[(usize, usize)],
2441 host_bounce: bool,
2442 n_embd: usize,
2443 widths: &[usize],
2444 ) -> Result<(), Box<dyn std::error::Error>> {
2445 let started = std::time::Instant::now();
2446 let mut copies = 0usize;
2447 let mut skipped = 0usize;
2448 let mut total_mismatches = 0usize;
2449 let mut largest_clean_payload = 0usize;
2450
2451 for boundary_idx in 0..self.stages.len() - 1 {
2452 if self.stages[boundary_idx].dev == self.stages[boundary_idx + 1].dev {
2453 continue;
2454 }
2455 for (src_stage, dst_stage) in [
2456 (boundary_idx, boundary_idx + 1),
2457 (boundary_idx + 1, boundary_idx),
2458 ] {
2459 let src_dev = self.stages[src_stage].dev;
2460 let dst_dev = self.stages[dst_stage].dev;
2461 if !enabled_pairs.contains(&(src_dev, dst_dev)) {
2462 if host_bounce {
2463 skipped += widths.len();
2464 eprintln!(
2465 "[pp] production-slot peer probe SKIP: boundary={boundary_idx} \
2466 dev{src_dev}->dev{dst_dev} widths_tokens={:?} \
2467 (peer or pool access unavailable; MEMRA_PP_HOST_BOUNCE=1 remains \
2468 fail-safe)",
2469 widths,
2470 );
2471 continue;
2472 }
2473 return Err(format!(
2474 "PP production-slot peer probe cannot run boundary={boundary_idx} \
2475 dev{src_dev}->dev{dst_dev}: peer/pool access is not enabled"
2476 )
2477 .into());
2478 }
2479
2480 let probe_boundary = self.new_peer_probe_boundary(src_stage, dst_stage)?;
2481 let path = BoundaryPath {
2482 boundary: boundary_idx,
2483 src_stage,
2484 dst_stage,
2485 transport: BoundaryTransport::Peer,
2486 };
2487 let mut direction_copies = 0usize;
2488 let mut direction_skipped = 0usize;
2489 let mut direction_mismatches = 0usize;
2490 let mut direction_largest_clean = 0usize;
2491 let mut failure = None;
2492
2493 for (width_idx, tokens) in widths.iter().copied().enumerate() {
2494 let n = n_embd.checked_mul(tokens).ok_or_else(|| {
2495 format!(
2496 "PP production-slot probe element count overflows for \
2497 n_embd={n_embd} tokens={tokens}"
2498 )
2499 })?;
2500 let bytes = n.checked_mul(std::mem::size_of::<f32>()).ok_or_else(|| {
2501 format!(
2502 "PP production-slot probe byte count overflows for \
2503 n_embd={n_embd} tokens={tokens}"
2504 )
2505 })?;
2506 let expected = peer_probe_pattern(bytes, boundary_idx, src_dev, dst_dev);
2507 let readback = match self.production_probe_readback(
2508 path,
2509 &probe_boundary,
2510 &expected,
2511 n,
2512 width_idx % 2,
2513 ) {
2514 Ok(readback) => readback,
2515 Err(err) if host_bounce => {
2516 skipped += 1;
2517 direction_skipped += 1;
2518 eprintln!(
2519 "[pp] production-slot peer probe ERROR: \
2520 boundary={boundary_idx} dev{src_dev}->dev{dst_dev} \
2521 tokens={tokens} bytes={bytes}: {err}; \
2522 MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path"
2523 );
2524 continue;
2525 }
2526 Err(err) => {
2527 failure = Some(format!(
2528 "PP production-slot peer probe FAILED: \
2529 boundary={boundary_idx} dev{src_dev}->dev{dst_dev} \
2530 tokens={tokens} bytes={bytes}: {err}; refusing native P2P \
2531 (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
2532 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer \
2533 transport)"
2534 ));
2535 break;
2536 }
2537 };
2538 copies += 1;
2539 direction_copies += 1;
2540 let mismatches = peer_probe_mismatch_count(&expected, &readback);
2541 if mismatches == 0 {
2542 largest_clean_payload = largest_clean_payload.max(bytes);
2543 direction_largest_clean = direction_largest_clean.max(bytes);
2544 } else if host_bounce {
2545 total_mismatches += mismatches;
2546 direction_mismatches += mismatches;
2547 eprintln!(
2548 "[pp] production-slot peer probe CORRUPTION: \
2549 boundary={boundary_idx} dev{src_dev}->dev{dst_dev} tokens={tokens} \
2550 bytes={bytes} mismatches={mismatches}; MEMRA_PP_HOST_BOUNCE=1, \
2551 proceeding on the host-staged path"
2552 );
2553 } else {
2554 failure = Some(format!(
2555 "PP production-slot peer probe FAILED: boundary={boundary_idx} \
2556 dev{src_dev}->dev{dst_dev} tokens={tokens} bytes={bytes}: \
2557 {mismatches} mismatched byte(s); refusing native P2P \
2558 (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
2559 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)"
2560 ));
2561 break;
2562 }
2563 }
2564
2565 self.clear_peer_probe_boundary(&probe_boundary, src_stage, dst_stage)?;
2566 if let Some(err) = failure {
2567 return Err(err.into());
2568 }
2569 eprintln!(
2570 "[pp] production-slot peer probe direction: boundary={boundary_idx} \
2571 dev{src_dev}->dev{dst_dev} copies={direction_copies} \
2572 skipped={direction_skipped} mismatches={direction_mismatches} \
2573 largest_clean_payload_bytes={direction_largest_clean}"
2574 );
2575 }
2576 }
2577
2578 let status = if total_mismatches > 0 {
2579 "BOUNCE"
2580 } else if skipped > 0 && copies > 0 {
2581 "PARTIAL"
2582 } else if skipped > 0 {
2583 "SKIP"
2584 } else {
2585 "PASS"
2586 };
2587 eprintln!(
2588 "[pp] production-slot peer probe {status}: widths_tokens={:?} copies={copies} \
2589 skipped={skipped} mismatches={total_mismatches} \
2590 largest_clean_payload_bytes={largest_clean_payload} elapsed_ms={:.3}",
2591 widths,
2592 started.elapsed().as_secs_f64() * 1e3,
2593 );
2594 Ok(())
2595 }
2596
2597 fn run_production_peer_probe(
2598 &self,
2599 enabled_pairs: &[(usize, usize)],
2600 host_bounce: bool,
2601 n_embd: usize,
2602 ) -> Result<(), Box<dyn std::error::Error>> {
2603 self.run_production_peer_probe_widths(
2604 enabled_pairs,
2605 host_bounce,
2606 n_embd,
2607 &PEER_PROBE_TOKEN_WIDTHS,
2608 )
2609 }
2610
2611 fn run_host_bounce_production_probe(
2612 &self,
2613 e: &Engine,
2614 n_embd: usize,
2615 ) -> Result<(), Box<dyn std::error::Error>> {
2616 let enabled = self.enable_probe_peer_access(e, &self.peer_capable)?;
2617 let granted = self.grant_probe_pool_access(e, &enabled)?;
2618 let probe = self.run_production_peer_probe(&granted, true, n_embd);
2619 let revoke = self.revoke_probe_pool_access(e, &granted);
2625 let disable = self.disable_probe_peer_access(e, &enabled);
2626 probe?;
2627 revoke?;
2628 disable?;
2629 Ok(())
2630 }
2631
2632 fn init_peer_probe_geometry(
2633 &self,
2634 e: &Engine,
2635 n_embd: usize,
2636 ) -> Result<(), Box<dyn std::error::Error>> {
2637 if !self.peer_probe || !self.cross_any {
2638 return Ok(());
2639 }
2640 let bytes = n_embd
2641 .checked_mul(std::mem::size_of::<f32>())
2642 .ok_or_else(|| format!("PP boundary-slot byte count overflows for n_embd={n_embd}"))?;
2643 let result = self.peer_probe_geometry.get_or_init(|| {
2644 let probe = if self.host_bounce_active() {
2645 self.run_host_bounce_production_probe(e, n_embd)
2646 } else {
2647 self.run_production_peer_probe(&self.peer_capable, false, n_embd)
2648 };
2649 let restore = e.ctx().bind_to_thread();
2650 match (probe, restore) {
2651 (Ok(()), Ok(())) => Ok(bytes),
2652 (Err(err), _) => Err(err.to_string()),
2653 (_, Err(err)) => Err(err.to_string()),
2654 }
2655 });
2656 let probed = result
2657 .as_ref()
2658 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
2659 if *probed != bytes {
2660 return Err(format!(
2661 "peer probe initialized for boundary-slot bytes={probed} but model requests \
2662 bytes={bytes}; one PP runtime supports one model geometry per process"
2663 )
2664 .into());
2665 }
2666 Ok(())
2667 }
2668
2669 fn init_host_bounce_staging(
2670 &self,
2671 e: &Engine,
2672 n_embd: usize,
2673 ) -> Result<(), Box<dyn std::error::Error>> {
2674 if !self.cross_any {
2675 return Ok(());
2676 }
2677 e.ctx().bind_to_thread()?;
2678 let result = self.bounce.get_or_init(|| {
2679 HostBounceRt::new(n_embd, &self.boundaries)
2680 .inspect(|rt| {
2681 let bytes = rt.capacity * std::mem::size_of::<f32>();
2682 eprintln!(
2683 "[pp] host-bounce staging ready: n_embd={n_embd} max_tokens={} \
2684 slot_bytes={bytes} slots_per_cross_boundary=2",
2685 crate::cache::PRIME_CHUNK_MAX_TOKENS,
2686 );
2687 })
2688 .map_err(|err| err.to_string())
2689 });
2690 let bounce = result
2691 .as_ref()
2692 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
2693 if bounce.n_embd != n_embd {
2694 return Err(format!(
2695 "host-bounce runtime initialized for n_embd={} but model requests n_embd={n_embd}; \
2696 one PP runtime supports one model geometry per process",
2697 bounce.n_embd,
2698 )
2699 .into());
2700 }
2701 Ok(())
2702 }
2703
2704 fn validate_host_bounce_staging(
2708 &self,
2709 e: &Engine,
2710 n_embd: usize,
2711 ) -> Result<(), Box<dyn std::error::Error>> {
2712 let bytes = n_embd
2713 .checked_mul(std::mem::size_of::<f32>())
2714 .ok_or_else(|| {
2715 format!("host-bounce validation byte count overflows for n_embd={n_embd}")
2716 })?;
2717 for boundary_idx in 0..self.stages.len() - 1 {
2718 if !self.boundaries[boundary_idx].cross {
2719 continue;
2720 }
2721 let src_stage = boundary_idx;
2722 let dst_stage = boundary_idx + 1;
2723 let probe_boundary = self.new_peer_probe_boundary(src_stage, dst_stage)?;
2724 let path = BoundaryPath {
2725 boundary: boundary_idx,
2726 src_stage,
2727 dst_stage,
2728 transport: BoundaryTransport::HostBounce,
2729 };
2730 let expected = peer_probe_pattern(
2731 bytes,
2732 boundary_idx,
2733 self.stages[src_stage].dev,
2734 self.stages[dst_stage].dev,
2735 );
2736 let readback =
2737 self.production_probe_readback(path, &probe_boundary, &expected, n_embd, 0);
2738 let clear = self.clear_peer_probe_boundary(&probe_boundary, src_stage, dst_stage);
2739 let readback = readback?;
2740 clear?;
2741 let mismatches = peer_probe_mismatch_count(&expected, &readback);
2742 if mismatches > 0 {
2743 return Err(format!(
2744 "runtime host-bounce staging validation FAILED: boundary={boundary_idx} \
2745 bytes={bytes} mismatches={mismatches}"
2746 )
2747 .into());
2748 }
2749 }
2750 e.ctx().bind_to_thread()?;
2751 eprintln!(
2752 "[pp] runtime host-bounce staging validation PASS: row_bytes={bytes} \
2753 cross_boundaries={}",
2754 self.boundaries
2755 .iter()
2756 .filter(|boundary| boundary.cross)
2757 .count(),
2758 );
2759 Ok(())
2760 }
2761
2762 fn arm_runtime_host_bounce(
2763 &self,
2764 e: &Engine,
2765 row_bytes: usize,
2766 ) -> Result<(), Box<dyn std::error::Error>> {
2767 if row_bytes == 0 || !row_bytes.is_multiple_of(std::mem::size_of::<f32>()) {
2768 return Err(format!(
2769 "runtime host-bounce cannot recover n_embd from row_bytes={row_bytes}"
2770 )
2771 .into());
2772 }
2773 let n_embd = row_bytes / std::mem::size_of::<f32>();
2774 self.init_host_bounce_staging(e, n_embd)?;
2775 self.validate_host_bounce_staging(e, n_embd)
2776 }
2777
2778 pub fn init_boundary_transport(
2784 &self,
2785 e: &Engine,
2786 n_embd: usize,
2787 ) -> Result<(), Box<dyn std::error::Error>> {
2788 if PEER_RUNTIME_PROBE_FAILED.load(Ordering::Acquire)
2789 && !PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire)
2790 {
2791 return Err(
2792 "PP runtime peer byte-integrity probe previously failed; refusing native P2P \
2793 reuse because runtime host-bounce staging could not be armed"
2794 .into(),
2795 );
2796 }
2797 self.init_peer_probe_geometry(e, n_embd)?;
2798 if !self.host_bounce_active() || !self.cross_any {
2799 return Ok(());
2800 }
2801 self.init_host_bounce_staging(e, n_embd)
2802 }
2803
2804 fn service_runtime_peer_probe(
2809 &self,
2810 e: &Engine,
2811 scheduler_idle: bool,
2812 probe_allowed: bool,
2813 ) -> Result<RuntimePeerProbeStatus, Box<dyn std::error::Error>> {
2814 if !self.peer_probe || !self.cross_any || self.host_bounce_active() {
2815 return Ok(RuntimePeerProbeStatus::NotRun);
2816 }
2817 if PEER_RUNTIME_PROBE_FAILED.load(Ordering::Acquire) {
2818 return Err(
2819 "PP runtime peer byte-integrity probe previously failed; native P2P is latched off"
2820 .into(),
2821 );
2822 }
2823 let row_bytes = match self.peer_probe_geometry.get() {
2824 Some(Ok(bytes)) => *bytes,
2825 _ => return Ok(RuntimePeerProbeStatus::NotRun),
2826 };
2827
2828 let copies = PEER_BOUNDARY_COPIES.load(Ordering::Relaxed);
2829 let (width_index, tokens) = loop {
2830 let next_probe_copy = std::array::from_fn(|width_index| {
2831 PEER_RUNTIME_NEXT_PROBE_COPY[width_index].load(Ordering::Relaxed)
2832 });
2833 let measured_cost_ns = std::array::from_fn(|width_index| {
2834 PEER_RUNTIME_PROBE_MAX_COST_NS[width_index].load(Ordering::Relaxed)
2835 });
2836 let Some(candidate) = runtime_peer_probe_candidate(
2837 copies,
2838 next_probe_copy,
2839 measured_cost_ns,
2840 scheduler_idle,
2841 ) else {
2842 return Ok(RuntimePeerProbeStatus::NotRun);
2843 };
2844 if !probe_allowed {
2849 return Ok(RuntimePeerProbeStatus::Deferred);
2850 }
2851 let due = next_probe_copy[candidate.0];
2852 let next = runtime_peer_probe_next_copy(due, copies);
2853 if PEER_RUNTIME_NEXT_PROBE_COPY[candidate.0]
2854 .compare_exchange(due, next, Ordering::AcqRel, Ordering::Relaxed)
2855 .is_ok()
2856 {
2857 break candidate;
2858 }
2859 };
2860 let probe_index = PEER_RUNTIME_PROBES.fetch_add(1, Ordering::Relaxed);
2861 let probe_bytes = row_bytes.checked_mul(tokens);
2862 let started = std::time::Instant::now();
2863 let probe = match probe_bytes {
2864 Some(_) => self.run_production_peer_probe_widths(
2865 &self.peer_capable,
2866 false,
2867 row_bytes / std::mem::size_of::<f32>(),
2868 &[tokens],
2869 ),
2870 None => Err(format!(
2871 "PP runtime peer probe byte count overflows for row_bytes={row_bytes} \
2872 tokens={tokens}"
2873 )
2874 .into()),
2875 };
2876 let restore = e.ctx().bind_to_thread();
2877 let elapsed_ns = started.elapsed().as_nanos().min(u64::MAX as u128) as u64;
2878 let previous_max =
2879 PEER_RUNTIME_PROBE_MAX_COST_NS[width_index].fetch_max(elapsed_ns, Ordering::Relaxed);
2880 let verdict = match (probe, restore) {
2881 (Ok(()), Ok(())) => Ok(()),
2882 (Err(err), _) => Err(err.to_string()),
2883 (_, Err(err)) => Err(err.to_string()),
2884 };
2885 if let Err(err) = verdict {
2886 PEER_RUNTIME_PROBE_FAILURES.fetch_add(1, Ordering::Relaxed);
2887 let arm = latch_runtime_host_bounce(
2888 &PEER_RUNTIME_PROBE_FAILED,
2889 &PEER_RUNTIME_HOST_BOUNCE,
2890 || {
2891 self.arm_runtime_host_bounce(e, row_bytes)
2892 .map_err(|arm_err| arm_err.to_string())
2893 },
2894 );
2895 if let Err(arm_err) = arm {
2896 let message = format!(
2897 "PP runtime peer byte-integrity re-probe FAILED after \
2898 boundary_copies={copies} rung={}/{} tokens={tokens}: {err}; native P2P is \
2899 latched off and host-bounce staging could not be armed: {arm_err}",
2900 width_index + 1,
2901 PEER_PROBE_TOKEN_WIDTHS.len(),
2902 );
2903 eprintln!("[pp] SECURITY RED: {message}; worker must stop");
2904 return Err(message.into());
2905 }
2906 eprintln!(
2907 "[pp] SECURITY RED: PP runtime peer byte-integrity re-probe FAILED after \
2908 boundary_copies={copies} rung={}/{} tokens={tokens}: {err}; native P2P is \
2909 latched off and the live transport DEGRADED to validated host bounce for the \
2910 remainder of this process",
2911 width_index + 1,
2912 PEER_PROBE_TOKEN_WIDTHS.len(),
2913 );
2914 return Ok(RuntimePeerProbeStatus::DegradedToHostBounce);
2915 }
2916 if width_index + 1 != PEER_PROBE_TOKEN_WIDTHS.len()
2917 && previous_max <= PEER_RUNTIME_PROBE_BUDGET_NS
2918 && elapsed_ns > PEER_RUNTIME_PROBE_BUDGET_NS
2919 {
2920 eprintln!(
2921 "[pp] runtime peer re-probe rung exceeded the {:.3}ms owner-thread budget: \
2922 tokens={tokens} measured_ms={:.3}; future runs are idle-only",
2923 PEER_RUNTIME_PROBE_BUDGET_NS as f64 / 1e6,
2924 elapsed_ns as f64 / 1e6,
2925 );
2926 }
2927 eprintln!(
2928 "[pp] runtime peer byte-integrity re-probe PASS: \
2929 boundary_copies={copies} interval_copies={PEER_RUNTIME_PROBE_INTERVAL_COPIES} \
2930 rung={}/{} tokens={tokens} bytes={} probe_index={probe_index} elapsed_ms={:.3} \
2931 scheduler_idle={scheduler_idle}",
2932 width_index + 1,
2933 PEER_PROBE_TOKEN_WIDTHS.len(),
2934 probe_bytes.unwrap(),
2935 elapsed_ns as f64 / 1e6,
2936 );
2937 Ok(RuntimePeerProbeStatus::Passed)
2938 }
2939
2940 fn bounce_rt(&self) -> Result<&HostBounceRt, Box<dyn std::error::Error>> {
2941 self.bounce
2942 .get()
2943 .ok_or_else(|| -> Box<dyn std::error::Error> {
2944 "MEMRA_PP_HOST_BOUNCE=1 staging was not initialized from model geometry".into()
2945 })?
2946 .as_ref()
2947 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })
2948 }
2949
2950 pub fn engine<'a>(&'a self, s: usize, primary: &'a Engine) -> &'a Engine {
2953 self.stages[s].engine.as_ref().unwrap_or(primary)
2954 }
2955
2956 pub fn bind_stage(&self, s: usize) -> Result<(), Box<dyn std::error::Error>> {
2958 self.stages[s].ctx.bind_to_thread()?;
2959 Ok(())
2960 }
2961
2962 pub fn enter(&self, s: usize) -> memra_runtime::StreamOverride {
2965 memra_runtime::push_stream_override(
2966 self.stages[s].stream.clone(),
2967 self.stages[s].blas.clone(),
2968 )
2969 }
2970
2971 pub fn prepare_overlap_slots(
2977 &self,
2978 b: usize,
2979 n: usize,
2980 ) -> Result<(), Box<dyn std::error::Error>> {
2981 let bd = &self.boundaries[b];
2982 let s_rx = &self.stages[b + 1].stream;
2983 let mut grew = false;
2984 for sl in &bd.slots {
2985 let mut guard = sl.buf.lock().unwrap();
2986 if guard.as_ref().map(|bf| bf.len() < n).unwrap_or(true) {
2987 *guard = Some(s_rx.alloc_zeros::<f32>(n)?);
2988 grew = true;
2989 }
2990 }
2991 if grew {
2992 s_rx.synchronize()?;
2993 }
2994 Ok(())
2995 }
2996
2997 pub fn boundary_slot_growth_bytes(
3001 &self,
3002 b: usize,
3003 n: usize,
3004 ) -> Result<usize, Box<dyn std::error::Error>> {
3005 let boundary = self
3006 .boundaries
3007 .get(b)
3008 .ok_or_else(|| format!("PP boundary {b} is outside the runtime"))?;
3009 let mut current = [0usize; 2];
3010 for (index, slot) in boundary.slots.iter().enumerate() {
3011 let guard = slot
3012 .buf
3013 .lock()
3014 .map_err(|_| format!("PP boundary {b} slot lock is poisoned"))?;
3015 current[index] = guard.as_ref().map_or(0, CudaSlice::len);
3016 }
3017 let elements = boundary_slot_growth_elements(current, n);
3018 Ok(elements.saturating_mul(std::mem::size_of::<f32>()))
3019 }
3020
3021 pub fn tx(
3035 &self,
3036 b: usize,
3037 x: &CudaSlice<f32>,
3038 n: usize,
3039 ) -> Result<usize, Box<dyn std::error::Error>> {
3040 assert_eq!(x.len(), n, "pp tx: residual length mismatch");
3041 let bd = &self.boundaries[b];
3042 let slot_idx = if pp2_overlap() {
3043 bd.step.fetch_add(1, Ordering::Relaxed) % 2
3044 } else {
3045 0
3046 };
3047 self.tx_slot(b, x, n, slot_idx)
3048 }
3049
3050 pub fn tx_pipelined(
3054 &self,
3055 b: usize,
3056 x: &CudaSlice<f32>,
3057 n: usize,
3058 ) -> Result<usize, Box<dyn std::error::Error>> {
3059 assert_eq!(x.len(), n, "pp tx: residual length mismatch");
3060 let slot_idx = self.boundaries[b].step.fetch_add(1, Ordering::Relaxed) % 2;
3061 self.tx_slot(b, x, n, slot_idx)
3062 }
3063
3064 fn tx_slot(
3065 &self,
3066 b: usize,
3067 x: &CudaSlice<f32>,
3068 n: usize,
3069 slot_idx: usize,
3070 ) -> Result<usize, Box<dyn std::error::Error>> {
3071 let bd = &self.boundaries[b];
3072 let path = BoundaryPath {
3073 boundary: b,
3074 src_stage: b,
3075 dst_stage: b + 1,
3076 transport: boundary_transport(bd.cross, self.host_bounce_active()),
3077 };
3078 let copied_slot = self.tx_slot_path(path, bd, x, n, slot_idx)?;
3079 if path.transport == BoundaryTransport::Peer {
3080 PEER_BOUNDARY_COPIES.fetch_add(1, Ordering::Relaxed);
3081 }
3082 Ok(copied_slot)
3083 }
3084
3085 fn tx_slot_path(
3086 &self,
3087 path: BoundaryPath,
3088 bd: &BoundaryRt,
3089 x: &CudaSlice<f32>,
3090 n: usize,
3091 slot_idx: usize,
3092 ) -> Result<usize, Box<dyn std::error::Error>> {
3093 debug_assert!(slot_idx < 2);
3094 let sl = &bd.slots[slot_idx];
3095 let s_tx = &self.stages[path.src_stage].stream;
3096 s_tx.wait(&sl.ev_rx)?;
3097 let mut guard = sl.buf.lock().unwrap();
3098 if guard.as_ref().map(|bf| bf.len() < n).unwrap_or(true) {
3099 let s_rx = &self.stages[path.dst_stage].stream;
3101 *guard = Some(s_rx.alloc_zeros::<f32>(n)?);
3102 s_rx.synchronize()?;
3112 }
3113 let buf = guard.as_mut().unwrap();
3114 match path.transport {
3115 BoundaryTransport::Local => s_tx.memcpy_dtod(x, buf)?,
3116 BoundaryTransport::HostBounce => {
3117 debug_assert_eq!(path.src_stage, path.boundary);
3118 debug_assert_eq!(path.dst_stage, path.boundary + 1);
3119 let bounce = self.bounce_rt()?;
3120 if n > bounce.capacity {
3121 return Err(format!(
3122 "pp host-bounce payload {n} exceeds geometry-sized capacity {} \
3123 (n_embd={}, max prime tokens={})",
3124 bounce.capacity,
3125 bounce.n_embd,
3126 crate::cache::PRIME_CHUNK_MAX_TOKENS,
3127 )
3128 .into());
3129 }
3130 let mut host = bounce.slot(path.boundary, slot_idx)?.lock().unwrap();
3131 s_tx.memcpy_dtoh(x, host.prefix_mut(n))?;
3135 }
3136 BoundaryTransport::Peer => {
3137 use cudarc::driver::{DevicePtr, DevicePtrMut};
3140 let (sp, _g0) = x.device_ptr(s_tx);
3141 let (dp, _g1) = buf.device_ptr_mut(s_tx);
3142 self.stages[path.src_stage].ctx.bind_to_thread()?;
3143 unsafe {
3144 cudarc::driver::result::memcpy_peer_async(
3145 self.stages[path.dst_stage].ctx.cu_ctx(),
3146 dp,
3147 self.stages[path.src_stage].ctx.cu_ctx(),
3148 sp,
3149 n * std::mem::size_of::<f32>(),
3150 s_tx.cu_stream(),
3151 )?;
3152 }
3153 }
3154 }
3155 sl.ev_tx.record(s_tx)?;
3156 Ok(slot_idx)
3157 }
3158
3159 pub fn rx(
3164 &self,
3165 b: usize,
3166 slot_idx: usize,
3167 n: usize,
3168 ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3169 let bd = &self.boundaries[b];
3170 let path = BoundaryPath {
3171 boundary: b,
3172 src_stage: b,
3173 dst_stage: b + 1,
3174 transport: boundary_transport(bd.cross, self.host_bounce_active()),
3175 };
3176 self.rx_slot_path(path, bd, slot_idx, n)
3177 }
3178
3179 fn rx_slot_path(
3180 &self,
3181 path: BoundaryPath,
3182 bd: &BoundaryRt,
3183 slot_idx: usize,
3184 n: usize,
3185 ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3186 let sl = &bd.slots[slot_idx];
3187 let s_rx = &self.stages[path.dst_stage].stream;
3188 s_rx.wait(&sl.ev_tx)?;
3189 let mut guard = sl.buf.lock().unwrap();
3190 let buf = guard.as_mut().expect("pp rx before tx");
3191 assert!(
3192 buf.len() >= n,
3193 "pp rx: slot holds {} < requested {n}",
3194 buf.len()
3195 );
3196 if path.transport == BoundaryTransport::HostBounce {
3197 debug_assert_eq!(path.src_stage, path.boundary);
3198 debug_assert_eq!(path.dst_stage, path.boundary + 1);
3199 let bounce = self.bounce_rt()?;
3200 let host = bounce.slot(path.boundary, slot_idx)?.lock().unwrap();
3201 let mut dst = buf.slice_mut(0..n);
3202 s_rx.memcpy_htod(host.prefix(n), &mut dst)?;
3205 }
3206 let mut work = unsafe { s_rx.alloc::<f32>(n)? };
3209 s_rx.memcpy_dtod(&buf.slice(0..n), &mut work)?;
3213 sl.ev_rx.record(s_rx)?;
3214 Ok(work)
3215 }
3216
3217 pub fn publish_to(
3244 &self,
3245 s: usize,
3246 dst: &Arc<CudaStream>,
3247 ) -> Result<(), Box<dyn std::error::Error>> {
3248 let st = &self.stages[s];
3249 if Arc::ptr_eq(&st.stream, dst) {
3252 return Ok(());
3253 }
3254 let ev = st.ctx.new_event(None)?;
3255 ev.record(&st.stream)?;
3256 dst.wait(&ev)?;
3257 Ok(())
3258 }
3259
3260 pub fn publish_all_to(&self, dst: &Arc<CudaStream>) -> Result<(), Box<dyn std::error::Error>> {
3291 if !pp_exit_publish() {
3292 return Ok(());
3293 }
3294 for s in 0..self.stages.len() {
3295 self.publish_to(s, dst)?;
3296 }
3297 Ok(())
3298 }
3299
3300 pub fn fence_stages_behind(
3322 &self,
3323 src: &Arc<CudaStream>,
3324 ) -> Result<(), Box<dyn std::error::Error>> {
3325 let ev = src.context().new_event(None)?;
3326 ev.record(src)?;
3327 for st in &self.stages {
3328 if Arc::ptr_eq(&st.stream, src) {
3329 continue;
3330 }
3331 st.stream.wait(&ev)?;
3332 }
3333 Ok(())
3334 }
3335
3336 pub fn record_done(&self) -> Result<CudaEvent, Box<dyn std::error::Error>> {
3339 let last = &self.stages[self.stages.len() - 1];
3340 let ev = last.ctx.new_event(None)?;
3341 ev.record(&last.stream)?;
3342 Ok(ev)
3343 }
3344
3345 pub fn readback_stream(&self) -> &Arc<CudaStream> {
3347 &self.readback
3348 }
3349}
3350
3351pub fn service_runtime_peer_probe(
3354 e: &Engine,
3355 scheduler_idle: bool,
3356 probe_allowed: bool,
3357) -> Result<RuntimePeerProbeStatus, Box<dyn std::error::Error>> {
3358 let Some(rt) = RTN.get() else {
3359 return Ok(RuntimePeerProbeStatus::NotRun);
3360 };
3361 let rt = rt
3362 .as_ref()
3363 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
3364 rt.service_runtime_peer_probe(e, scheduler_idle, probe_allowed)
3365}
3366
3367pub struct PendingLogits {
3372 logits: CudaSlice<f32>,
3373 ev: CudaEvent,
3374 rb: Arc<CudaStream>,
3375 _walk: PpWalkLease,
3376}
3377
3378impl PendingLogits {
3379 pub(crate) fn new(
3380 logits: CudaSlice<f32>,
3381 ev: CudaEvent,
3382 rb: Arc<CudaStream>,
3383 walk: PpWalkLease,
3384 ) -> Self {
3385 PendingLogits {
3386 logits,
3387 ev,
3388 rb,
3389 _walk: walk,
3390 }
3391 }
3392
3393 pub fn wait(self) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3397 self.rb.wait(&self.ev)?;
3398 let host = self.rb.clone_dtoh(&self.logits)?;
3399 self.rb.synchronize()?;
3400 Ok(host)
3403 }
3404}
3405
3406pub fn init_model_transport(
3409 e: &Engine,
3410 cfg: &memra_gguf::config::ModelConfig,
3411 n_trunk: usize,
3412) -> Result<(), Box<dyn std::error::Error>> {
3413 if pp2_streams_off() || pp2_devices_env().is_none() || pp_cuts(n_trunk).is_none() {
3414 return Ok(());
3415 }
3416 PpNRt::get(e)?.init_boundary_transport(e, cfg.n_embd as usize)
3417}
3418
3419pub fn new_cache(
3426 e: &Engine,
3427 cfg: &memra_gguf::config::ModelConfig,
3428 max_ctx: usize,
3429) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3430 new_cache_inner(e, cfg, None, max_ctx)
3431}
3432
3433pub fn new_cache_planned(
3434 e: &Engine,
3435 cfg: &memra_gguf::config::ModelConfig,
3436 plan: &memra_gguf::model_plan::ModelPlan,
3437 max_ctx: usize,
3438) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3439 new_cache_inner(e, cfg, Some(plan), max_ctx)
3440}
3441
3442fn new_cache_inner(
3443 e: &Engine,
3444 cfg: &memra_gguf::config::ModelConfig,
3445 plan: Option<&memra_gguf::model_plan::ModelPlan>,
3446 max_ctx: usize,
3447) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3448 let n_trunk = (cfg.n_layer - cfg.nextn_predict_layers) as usize;
3449 if let Some(fence) = pp_cuts(n_trunk) {
3450 if pp2_devices_env().is_some() && !pp2_streams_off() {
3451 let rt = PpNRt::get(e)?;
3452 rt.init_boundary_transport(e, cfg.n_embd as usize)?;
3453 let n_st = fence.len() - 1;
3454 assert_eq!(
3455 rt.n_stages(),
3456 n_st,
3457 "PpNRt stage count {} != fence stages {n_st}",
3458 rt.n_stages()
3459 );
3460 rt.fence_stages_behind(&e.stream())?;
3469 let devs: Vec<&dyn memra_kv::KvDev> = (0..n_st)
3470 .map(|s| rt.engine(s, e) as &dyn memra_kv::KvDev)
3471 .collect();
3472 let cache = match plan {
3473 Some(plan) => {
3474 crate::cache::Cache::new_ppn_planned(&devs, &fence, cfg, plan, max_ctx)?
3475 }
3476 None => crate::cache::Cache::new_ppn(&devs, &fence, cfg, max_ctx)?,
3477 };
3478 sync_stages_after_load(e, n_trunk)?;
3479 return Ok(cache);
3480 }
3481 if !pp2_streams_off() {
3482 let cache = match plan {
3490 Some(plan) => crate::cache::Cache::new_planned(e, cfg, plan, max_ctx)?,
3491 None => crate::cache::Cache::new(e, cfg, max_ctx)?,
3492 };
3493 sync_stages_after_load(e, n_trunk)?;
3494 return Ok(cache);
3495 }
3496 }
3497 match plan {
3498 Some(plan) => crate::cache::Cache::new_planned(e, cfg, plan, max_ctx),
3499 None => crate::cache::Cache::new(e, cfg, max_ctx),
3500 }
3501}
3502
3503pub fn sync_stages_after_load(
3512 e: &Engine,
3513 n_trunk: usize,
3514) -> Result<(), Box<dyn std::error::Error>> {
3515 if pp2_streams_off() || pp_cuts(n_trunk).is_none() {
3516 return Ok(());
3517 }
3518 let rt = PpNRt::get(e)?;
3519 for s in 0..rt.n_stages() {
3520 rt.stages[s].ctx.bind_to_thread()?;
3521 unsafe {
3522 cudarc::driver::sys::cuCtxSynchronize().result()?;
3523 }
3524 }
3525 e.ctx().bind_to_thread()?;
3526 unsafe {
3527 cudarc::driver::sys::cuCtxSynchronize().result()?;
3528 }
3529 Ok(())
3530}
3531
3532pub fn layer_engine(
3538 e: &Engine,
3539 n_trunk: usize,
3540 il: usize,
3541) -> Result<&Engine, Box<dyn std::error::Error>> {
3542 if pp_shard_off() || pp2_devices_env().is_none() || pp2_streams_off() {
3543 return Ok(e);
3544 }
3545 let Some(fence) = pp_cuts(n_trunk) else {
3546 return Ok(e);
3547 };
3548 let rt = PpNRt::get(e)?;
3549 let s = stage_of(&fence, il.min(n_trunk - 1));
3550 Ok(rt.engine(s, e))
3551}
3552
3553#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3555pub(crate) enum TpRestoreRefusal {
3556 TargetAbsent,
3558 SourceAbsent,
3560 GrowTargetNotFresh,
3562 TokenGraphDoorOpen,
3565}
3566
3567#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3569pub(crate) enum TpRestore {
3570 Nothing,
3572 Rewind(usize),
3574 Grow(usize),
3576 DropMirror,
3580 Refuse(TpRestoreRefusal),
3581}
3582
3583pub(crate) fn tp_restore_plan(
3624 snap_len: Option<usize>,
3625 source_has_tp: Option<bool>,
3626 target_has_tp: bool,
3627 token_graph_door: bool,
3628) -> TpRestore {
3629 match (source_has_tp, snap_len) {
3630 (None, Some(len)) => {
3631 if target_has_tp {
3632 TpRestore::Rewind(len)
3633 } else {
3634 TpRestore::Refuse(TpRestoreRefusal::TargetAbsent)
3635 }
3636 }
3637 (None, None) => {
3638 if !target_has_tp {
3639 TpRestore::Nothing
3640 } else if token_graph_door {
3641 TpRestore::Refuse(TpRestoreRefusal::TokenGraphDoorOpen)
3642 } else {
3643 TpRestore::DropMirror
3644 }
3645 }
3646 (Some(source_has_tp), Some(len)) => {
3647 if !source_has_tp {
3648 TpRestore::Refuse(TpRestoreRefusal::SourceAbsent)
3649 } else if target_has_tp {
3650 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
3651 } else {
3652 TpRestore::Grow(len)
3653 }
3654 }
3655 (Some(_), None) => {
3656 if target_has_tp {
3657 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
3659 } else {
3660 TpRestore::Nothing
3665 }
3666 }
3667 }
3668}
3669
3670pub fn restore_cache_checkpoint(
3682 e: &Engine,
3683 model: &crate::hybrid::HybridModel,
3684 source: Option<&crate::cache::Cache>,
3685 target: &mut crate::cache::Cache,
3686 snap: &crate::cache::CacheSnapshot,
3687) -> Result<(), Box<dyn std::error::Error>> {
3688 target.ensure_usable("restore_cache_checkpoint target")?;
3689 if let Some(source) = source {
3690 source.ensure_usable("restore_cache_checkpoint source")?;
3691 }
3692 let cfg = &model.cfg;
3693 let n = target.kv.len();
3694 if target.recur.len() != n
3695 || target.tp_kv.len() != n
3696 || snap.kv_len.len() != n
3697 || snap.tp_kv_len.len() != n
3698 || snap.conv.len() != n
3699 || snap.ssm.len() != n
3700 || source.is_some_and(|s| s.kv.len() != n || s.recur.len() != n || s.tp_kv.len() != n)
3701 {
3702 return Err("checkpoint cache layer-count mismatch".into());
3703 }
3704 if snap.pos > target.max_ctx {
3705 return Err(format!(
3706 "checkpoint pos {} exceeds target capacity {}",
3707 snap.pos, target.max_ctx,
3708 )
3709 .into());
3710 }
3711
3712 let n_trunk = (cfg.n_layer - cfg.nextn_predict_layers) as usize;
3713 let token_graph_door = crate::tp::step_tp_graph_enabled().unwrap_or(false);
3715 let mut dropped_mirrors = 0usize;
3716 for il in 0..n {
3717 let owner = layer_engine(e, n_trunk, il)?;
3718 let src_kv = source.map(|s| &s.kv[il]);
3719 match (src_kv, target.kv[il].as_mut(), snap.kv_len[il]) {
3720 (Some(Some(src)), Some(dst), Some(len)) => {
3721 if len > src.len || len > target.max_ctx {
3722 return Err(format!(
3723 "checkpoint layer {il} len {len} exceeds source {} or target {}",
3724 src.len, target.max_ctx,
3725 )
3726 .into());
3727 }
3728 if src.kv_dim_k != dst.kv_dim_k
3729 || src.kv_dim_v != dst.kv_dim_v
3730 || src.k_tok_bytes != dst.k_tok_bytes
3731 || src.v_tok_bytes != dst.v_tok_bytes
3732 {
3733 return Err(format!("checkpoint KV layout mismatch at layer {il}").into());
3734 }
3735 match (&src.ring, dst.ring.as_ref()) {
3736 (Some(sring), Some(dring)) => {
3737 if dring.base() != 0 {
3743 return Err(format!(
3744 "checkpoint SWA restore at layer {il} requires a fresh target \
3745 ring (base {}, expected 0)",
3746 dring.base(),
3747 )
3748 .into());
3749 }
3750 let (new_base, phys) = sring.restore_plan(len).map_err(|e| {
3751 format!("checkpoint SWA restore refused at layer {il}: {e}")
3752 })?;
3753 let rows = phys.len();
3754 let kb = rows * src.k_tok_bytes;
3755 let vb = rows * src.v_tok_bytes;
3756 if kb > 0 {
3757 owner.copy_u8_range_into(
3758 &mut dst.k,
3759 0,
3760 &src.k,
3761 phys.start * src.k_tok_bytes,
3762 kb,
3763 )?;
3764 }
3765 if vb > 0 {
3766 owner.copy_u8_range_into(
3767 &mut dst.v,
3768 0,
3769 &src.v,
3770 phys.start * src.v_tok_bytes,
3771 vb,
3772 )?;
3773 }
3774 dst.ring
3775 .as_mut()
3776 .expect("ring presence checked above")
3777 .apply_rebase(new_base);
3778 if let Some(base_d) = dst.base_d.as_mut() {
3779 owner.set_i32_one(base_d, new_base as i32)?;
3780 }
3781 }
3782 (None, None) => {
3783 let kb = len * src.k_tok_bytes;
3784 let vb = len * src.v_tok_bytes;
3785 if kb > 0 {
3786 owner.copy_u8_into(&mut dst.k, 0, &src.k, kb)?;
3787 }
3788 if vb > 0 {
3789 owner.copy_u8_into(&mut dst.v, 0, &src.v, vb)?;
3790 }
3791 }
3792 _ => {
3793 return Err(
3794 format!("checkpoint ring/flat KV mismatch at layer {il}").into()
3795 );
3796 }
3797 }
3798 dst.len = len;
3799 owner.set_i32_one(&mut dst.len_d, len as i32)?;
3800 }
3801 (None, Some(dst), Some(len)) => {
3802 if len > dst.len || len > target.max_ctx {
3803 return Err(format!(
3804 "checkpoint layer {il} len {len} exceeds live {} or target {}",
3805 dst.len, target.max_ctx,
3806 )
3807 .into());
3808 }
3809 if let Some(ring) = &dst.ring
3810 && !ring.can_rewind_to(len)
3811 {
3812 return Err(format!(
3813 "checkpoint SWA rewind at layer {il} has been lapped \
3814 (len {len}, ring base {}); full re-prime required",
3815 ring.base(),
3816 )
3817 .into());
3818 }
3819 dst.len = len;
3820 owner.set_i32_one(&mut dst.len_d, len as i32)?;
3821 }
3822 (Some(None), None, None) | (None, None, None) => {}
3823 _ => return Err(format!("checkpoint KV kind mismatch at layer {il}").into()),
3824 }
3825
3826 match tp_restore_plan(
3827 snap.tp_kv_len[il],
3828 source.map(|s| s.tp_kv[il].is_some()),
3829 target.tp_kv[il].is_some(),
3830 token_graph_door,
3831 ) {
3832 TpRestore::Nothing => {}
3833 TpRestore::Rewind(len) => target.tp_kv[il]
3834 .as_mut()
3835 .expect("tp_restore_plan::Rewind implies a present target mirror")
3836 .rewind_to(len)?,
3837 TpRestore::Grow(len) => {
3838 let src = source
3839 .and_then(|s| s.tp_kv[il].as_ref())
3840 .expect("tp_restore_plan::Grow implies a present source mirror");
3841 let runtime = model.step_tp_runtime_for_layer(il).ok_or_else(|| {
3842 format!("checkpoint TP KV layer {il} has no distributed runtime")
3843 })?;
3844 let grown = runtime.grow_tp_kv_cache(src, target.max_ctx, len)?;
3845 target.tp_kv[il] = Some(grown);
3846 }
3847 TpRestore::DropMirror => {
3848 if target.tp_kv[il].take().is_some() {
3852 dropped_mirrors += 1;
3853 }
3854 }
3855 TpRestore::Refuse(reason) => {
3856 return Err(format!(
3857 "checkpoint TP KV restore refused at layer {il}: {} \
3858 (snap.tp_kv_len={:?}, snap.kv_len={:?}, snap.pos={}, \
3859 source_has_tp={:?}, target_has_tp={}, target_committed={})",
3860 match reason {
3861 TpRestoreRefusal::TargetAbsent =>
3862 "the snapshot recorded a distributed length but the target holds no \
3863 distributed cache to rewind",
3864 TpRestoreRefusal::SourceAbsent =>
3865 "the snapshot recorded a distributed length the parked source cannot \
3866 supply",
3867 TpRestoreRefusal::GrowTargetNotFresh =>
3868 "the freshly allocated grow target already holds a distributed cache",
3869 TpRestoreRefusal::TokenGraphDoorOpen =>
3870 "MEMRA_STEP_TP_GRAPH is open, and its model-level whole-token graph \
3871 bakes the rank-cache pointers, so the stale mirror cannot be freed",
3872 },
3873 snap.tp_kv_len[il],
3874 snap.kv_len[il],
3875 snap.pos,
3876 source.map(|s| s.tp_kv[il].is_some()),
3877 target.tp_kv[il].is_some(),
3878 target.tp_kv[il]
3879 .as_ref()
3880 .map(|c| c.committed_len())
3881 .unwrap_or(0),
3882 )
3883 .into());
3884 }
3885 }
3886
3887 match (target.recur[il].as_mut(), &snap.conv[il], &snap.ssm[il]) {
3888 (Some(dst), Some(conv), Some(ssm)) => {
3889 if conv.len() != dst.conv_state.len() || ssm.len() != dst.ssm_state.len() {
3890 return Err(
3891 format!("checkpoint recurrent layout mismatch at layer {il}").into(),
3892 );
3893 }
3894 owner.copy_into(&mut dst.conv_state, 0, conv, conv.len())?;
3895 owner.copy_into(&mut dst.ssm_state, 0, ssm, ssm.len())?;
3896 }
3897 (None, None, None) => {}
3898 _ => {
3899 return Err(format!("checkpoint recurrent kind mismatch at layer {il}").into());
3900 }
3901 }
3902 }
3903 target.pos = snap.pos;
3904 if dropped_mirrors > 0 {
3905 eprintln!(
3909 "[pp] checkpoint restore: cleared {dropped_mirrors} stale distributed KV mirror(s) \
3910 at pos {} (snapshot predates lazy TP hydration); the next TP use rehydrates them \
3911 from the local plane",
3912 snap.pos,
3913 );
3914 }
3915
3916 sync_stages_after_load(e, n_trunk)?;
3919 if source.is_some() {
3920 e.stream().synchronize()?;
3923 }
3924 Ok(())
3925}
3926
3927#[cfg(test)]
3928mod host_bounce_tests {
3929 use super::{
3930 BoundaryTransport, DUAL_PP_HOST_BOUNCE_REFUSAL, DUAL_PP_SINGLE_SLOT_REFUSAL,
3931 PEER_PROBE_FIXED_BYTES, PEER_PROBE_REQUIRED_REFUSAL, PEER_PROBE_TOKEN_WIDTHS,
3932 PEER_RUNTIME_PROBE_BUDGET_NS, PEER_RUNTIME_PROBE_CYCLE_COPIES,
3933 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS, PEER_RUNTIME_PROBE_INTERVAL_COPIES,
3934 PP_WAVE_MAX_STAGES, PeerProbeDecision, PeerProbeStartupPolicy, acquire_pp_walk,
3935 boundary_slot_growth_elements, boundary_transport, dual_pp_eligibility,
3936 dual_pp_timing_dropped, dual_pp_timing_snapshot, dual_pp_wave_mid, enter_pp_wave_cell,
3937 host_bounce_capacity, latch_runtime_host_bounce, peer_probe_bytes_to_f32,
3938 peer_probe_decision, peer_probe_f32_to_bytes, peer_probe_mismatch_count,
3939 peer_probe_pattern, peer_probe_startup_policy, pp_devices_repeat, pp_wave_diagonal,
3940 pp_wave_eligibility, pp_wave_numeric_eligibility, pp_wave_on_value, pp_wave_ranges,
3941 pp_wave_route_enabled, pp_wave_snapshot, publish_runtime_peer_probe_deferral,
3942 record_dual_pp_stage_result, record_pp_wave_tick, runtime_peer_probe_candidate,
3943 runtime_peer_probe_next_copy,
3944 };
3945
3946 use super::{TpRestore, TpRestoreRefusal, tp_restore_plan};
3956
3957 #[test]
3958 fn mismatch_snapshot_predating_lazy_tp_drops_the_mirror_instead_of_refusing() {
3959 assert_eq!(
3961 tp_restore_plan(None, None, true, false),
3962 TpRestore::DropMirror
3963 );
3964 }
3965
3966 #[test]
3967 fn mismatch_on_the_grow_path_leaves_the_fresh_target_without_a_mirror() {
3968 assert_eq!(
3971 tp_restore_plan(None, Some(true), false, false),
3972 TpRestore::Nothing
3973 );
3974 }
3975
3976 #[test]
3977 fn drop_is_refused_while_the_token_graph_door_bakes_rank_pointers() {
3978 assert_eq!(
3979 tp_restore_plan(None, None, true, true),
3980 TpRestore::Refuse(TpRestoreRefusal::TokenGraphDoorOpen)
3981 );
3982 }
3983
3984 #[test]
3985 fn healthy_arms_are_untouched() {
3986 assert_eq!(
3987 tp_restore_plan(None, None, false, false),
3988 TpRestore::Nothing
3989 );
3990 assert_eq!(tp_restore_plan(None, None, false, true), TpRestore::Nothing);
3991 assert_eq!(
3992 tp_restore_plan(Some(15222), None, true, false),
3993 TpRestore::Rewind(15222)
3994 );
3995 assert_eq!(
3996 tp_restore_plan(Some(15222), Some(true), false, false),
3997 TpRestore::Grow(15222)
3998 );
3999 assert_eq!(
4000 tp_restore_plan(None, Some(false), false, false),
4001 TpRestore::Nothing
4002 );
4003 }
4004
4005 #[test]
4006 fn refuses_a_recorded_distributed_length_with_no_target_mirror() {
4007 assert_eq!(
4008 tp_restore_plan(Some(15222), None, false, false),
4009 TpRestore::Refuse(TpRestoreRefusal::TargetAbsent)
4010 );
4011 }
4012
4013 #[test]
4014 fn refuses_a_recorded_distributed_length_the_source_cannot_supply() {
4015 assert_eq!(
4016 tp_restore_plan(Some(15222), Some(false), false, false),
4017 TpRestore::Refuse(TpRestoreRefusal::SourceAbsent)
4018 );
4019 }
4020
4021 #[test]
4022 fn refuses_a_grow_target_that_is_not_fresh() {
4023 assert_eq!(
4024 tp_restore_plan(Some(15222), Some(true), true, false),
4025 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
4026 );
4027 assert_eq!(
4028 tp_restore_plan(None, Some(true), true, false),
4029 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
4030 );
4031 }
4032
4033 #[test]
4037 fn flip_default_is_dual_auto_with_explicit_off_and_forced_seams() {
4038 use super::{DualPpMode, dual_pp_mode_resolve};
4039 assert_eq!(dual_pp_mode_resolve(None), DualPpMode::Auto);
4040 assert_eq!(dual_pp_mode_resolve(Some("0")), DualPpMode::Off);
4041 assert_eq!(dual_pp_mode_resolve(Some("1")), DualPpMode::Forced);
4042 assert_eq!(dual_pp_mode_resolve(Some("2")), DualPpMode::Auto);
4044 assert_eq!(dual_pp_mode_resolve(Some("")), DualPpMode::Auto);
4045 }
4046
4047 #[test]
4048 fn flip_overlap_follows_mode_and_one_flag_restores_preflip_serial() {
4049 use super::{DualPpMode, pp2_overlap_resolve};
4050 assert!(pp2_overlap_resolve(None, DualPpMode::Auto));
4052 assert!(!pp2_overlap_resolve(None, DualPpMode::Off));
4054 assert!(!pp2_overlap_resolve(None, DualPpMode::Forced));
4056 for mode in [DualPpMode::Off, DualPpMode::Forced, DualPpMode::Auto] {
4058 assert!(pp2_overlap_resolve(Some("1"), mode));
4059 assert!(!pp2_overlap_resolve(Some("0"), mode));
4060 }
4061 }
4062
4063 #[test]
4064 fn flip_auto_routes_only_the_regated_regime_and_degrades_serially_elsewhere() {
4065 use super::{DualPpMode, dual_pp_route};
4066 assert!(dual_pp_route(DualPpMode::Auto, 2, 2, true, false));
4068 assert!(dual_pp_route(DualPpMode::Auto, 17, 2, true, false));
4069 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));
4076 assert!(!dual_pp_route(DualPpMode::Forced, 1, 2, true, false));
4077 assert!(!dual_pp_route(DualPpMode::Off, 8, 2, true, false));
4079 }
4080
4081 #[test]
4082 fn pp_wave_flag_is_strict_and_does_not_inherit_the_pp2_default() {
4083 assert_eq!(pp_wave_on_value(None), Ok(false));
4084 assert!(pp_wave_on_value(Some("")).is_err());
4085 assert_eq!(pp_wave_on_value(Some("0")), Ok(false));
4086 assert_eq!(pp_wave_on_value(Some("1")), Ok(true));
4087 assert!(pp_wave_on_value(Some("auto")).is_err());
4088 assert!(pp_wave_on_value(Some("2")).is_err());
4089 }
4090
4091 #[test]
4092 fn pp_wave_route_treats_overlap_off_and_single_work_item_as_serial_rollback() {
4093 assert!(pp_wave_route_enabled(true, true, 3, 2));
4094 assert!(pp_wave_route_enabled(true, true, 4, 8));
4095 assert!(!pp_wave_route_enabled(true, false, 3, 8));
4096 assert!(!pp_wave_route_enabled(false, true, 3, 8));
4097 assert!(!pp_wave_route_enabled(true, true, 2, 8));
4098 assert!(!pp_wave_route_enabled(true, true, 4, 1));
4099 }
4100
4101 #[test]
4102 fn pp_wave_ranges_are_balanced_contiguous_and_priority_preserving() {
4103 assert!(pp_wave_ranges(0, 4).is_empty());
4104 assert!(pp_wave_ranges(8, 0).is_empty());
4105 assert_eq!(pp_wave_ranges(1, 4), vec![(0, 1)]);
4106 assert_eq!(pp_wave_ranges(2, 4), vec![(0, 1), (1, 2)]);
4107 assert_eq!(pp_wave_ranges(8, 4), vec![(0, 2), (2, 4), (4, 6), (6, 8)]);
4108 assert_eq!(
4109 pp_wave_ranges(17, 4),
4110 vec![(0, 5), (5, 9), (9, 13), (13, 17)]
4111 );
4112 for batch in 1..=64 {
4113 for stages in 2..=PP_WAVE_MAX_STAGES {
4114 let ranges = pp_wave_ranges(batch, stages);
4115 assert_eq!(ranges.len(), batch.min(stages));
4116 assert_eq!(ranges.first().copied().unwrap().0, 0);
4117 assert_eq!(ranges.last().copied().unwrap().1, batch);
4118 assert!(ranges.iter().all(|(lo, hi)| lo < hi));
4119 assert!(ranges.windows(2).all(|pair| pair[0].1 == pair[1].0));
4120 let widths: Vec<_> = ranges.iter().map(|(lo, hi)| hi - lo).collect();
4121 assert!(widths.windows(2).all(|pair| pair[0] >= pair[1]));
4122 assert!(widths.first().unwrap() - widths.last().unwrap() <= 1);
4123 }
4124 }
4125 }
4126
4127 #[test]
4128 fn pp_wave_diagonals_cover_the_grid_without_stage_or_wave_aliasing() {
4129 for stages in 3..=PP_WAVE_MAX_STAGES {
4130 for waves in 1..=stages {
4131 let mut seen = vec![vec![false; stages]; waves];
4132 for diagonal in 0..stages + waves - 1 {
4133 let cells = pp_wave_diagonal(stages, waves, diagonal);
4134 let mut stage_seen = vec![false; stages];
4135 let mut wave_seen = vec![false; waves];
4136 for (wave, stage) in cells {
4137 assert_eq!(wave + stage, diagonal);
4138 assert!(!stage_seen[stage]);
4139 assert!(!wave_seen[wave]);
4140 assert!(!seen[wave][stage]);
4141 stage_seen[stage] = true;
4142 wave_seen[wave] = true;
4143 seen[wave][stage] = true;
4144 }
4145 }
4146 assert!(seen.into_iter().flatten().all(|cell| cell));
4147 }
4148 }
4149 assert!(pp_wave_diagonal(4, 4, 7).is_empty());
4150 }
4151
4152 #[test]
4153 fn pp_wavefront_refuses_every_unqualified_transport_shape() {
4154 assert!(pp_wave_eligibility(3, true, false, false).is_ok());
4155 assert!(pp_wave_eligibility(4, true, false, false).is_ok());
4156 assert!(pp_wave_eligibility(2, true, false, false).is_err());
4157 assert!(pp_wave_eligibility(5, true, false, false).is_err());
4158 assert!(pp_wave_eligibility(3, false, false, false).is_err());
4159 assert!(pp_wave_eligibility(3, true, true, false).is_err());
4160 assert!(pp_wave_eligibility(3, true, false, true).is_err());
4161 }
4162
4163 #[test]
4164 fn pp_wavefront_requires_width_invariant_bf16_for_w4a16() {
4165 assert!(pp_wave_numeric_eligibility(false, false).is_ok());
4166 assert!(pp_wave_numeric_eligibility(false, true).is_ok());
4167 assert!(pp_wave_numeric_eligibility(true, true).is_ok());
4168 assert!(pp_wave_numeric_eligibility(true, false).is_err());
4169 }
4170
4171 #[test]
4172 fn pp_device_aliases_cannot_bypass_the_distinct_stage_gate() {
4173 assert!(!pp_devices_repeat("0,1,2,3"));
4174 assert!(pp_devices_repeat("0,00,1"));
4175 assert!(pp_devices_repeat("2,1,2"));
4176 assert!(pp_devices_repeat("0,nope,1"));
4177 }
4178
4179 #[test]
4180 fn pp_walk_owner_refuses_reentry_and_releases_at_scope_end() {
4181 let active = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
4182 let next = std::sync::atomic::AtomicU64::new(1);
4183 let first = acquire_pp_walk(&active, &next, 7, None, "first").unwrap();
4184 let held_clone = super::PpWalkLease {
4185 state: first.state.clone(),
4186 };
4187 let error = acquire_pp_walk(&active, &next, 7, None, "second").unwrap_err();
4188 assert!(error.contains("refused concurrent PP walk"));
4189 drop(first);
4190 assert!(acquire_pp_walk(&active, &next, 7, None, "third").is_err());
4191 drop(held_clone);
4192 assert!(acquire_pp_walk(&active, &next, 7, None, "fourth").is_ok());
4193 }
4194
4195 #[test]
4196 fn pp_walk_coordinator_borrow_is_explicit_and_thread_local() {
4197 let active = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
4198 let next = std::sync::atomic::AtomicU64::new(1);
4199 let lease = acquire_pp_walk(&active, &next, 11, None, "owner").unwrap();
4200 let state = lease.state.clone();
4201 super::PP_WALK_BORROWS.with(|borrows| borrows.borrow_mut().push(state.clone()));
4202 assert!(super::borrowed_pp_walk(11).is_some());
4203 std::thread::spawn(move || {
4204 assert!(super::borrowed_pp_walk(11).is_none());
4205 drop(state);
4206 })
4207 .join()
4208 .unwrap();
4209 super::PP_WALK_BORROWS.with(|borrows| borrows.borrow_mut().clear());
4210 drop(lease);
4211 assert_eq!(active.load(std::sync::atomic::Ordering::Acquire), 0);
4212 }
4213
4214 #[test]
4215 fn boundary_growth_charges_first_allocation_and_only_missing_high_water_afterward() {
4216 assert_eq!(boundary_slot_growth_elements([0, 0], 4096), 8192);
4217 assert_eq!(boundary_slot_growth_elements([4096, 4096], 4096), 0);
4218 assert_eq!(boundary_slot_growth_elements([4096, 2048], 4096), 2048);
4219 assert_eq!(boundary_slot_growth_elements([8192, 8192], 4096), 0);
4220 }
4221
4222 #[test]
4223 fn pp_wave_liveness_snapshot_counts_ticks_cells_and_real_overlap() {
4224 let before = pp_wave_snapshot();
4225 let first = enter_pp_wave_cell();
4226 let second = enter_pp_wave_cell();
4227 drop(second);
4228 drop(first);
4229 record_pp_wave_tick();
4230 let after = pp_wave_snapshot();
4231 assert!(after.0 > before.0);
4232 assert!(after.1 >= before.1 + 2);
4233 assert!(after.2 > before.2);
4234 }
4235
4236 #[test]
4237 fn dual_pp_split_is_honest_at_one_and_ceil_first_afterward() {
4238 assert_eq!(dual_pp_wave_mid(1), None);
4239 assert_eq!(dual_pp_wave_mid(2), Some(1));
4240 assert_eq!(dual_pp_wave_mid(3), Some(2));
4241 assert_eq!(dual_pp_wave_mid(8), Some(4));
4242 assert_eq!(dual_pp_wave_mid(16), Some(8));
4243 assert_eq!(dual_pp_wave_mid(31), Some(16));
4244 assert_eq!(dual_pp_wave_mid(32), Some(16));
4245 }
4246
4247 #[test]
4248 fn dual_pp_refuses_single_slot_and_non_pp2_shapes() {
4249 assert_eq!(
4250 dual_pp_eligibility(2, false, false),
4251 Err(DUAL_PP_SINGLE_SLOT_REFUSAL)
4252 );
4253 assert!(dual_pp_eligibility(2, true, false).is_ok());
4254 assert!(dual_pp_eligibility(3, true, false).is_err());
4255 }
4256
4257 #[test]
4258 fn dual_pp_refuses_unvalidated_host_bounce_transport() {
4259 assert_eq!(
4260 dual_pp_eligibility(2, true, true),
4261 Err(DUAL_PP_HOST_BOUNCE_REFUSAL),
4262 );
4263 }
4264
4265 #[test]
4266 #[allow(clippy::int_plus_one)] fn dual_pp_timing_error_is_counted_without_recording_a_sample() {
4268 let dropped_before = dual_pp_timing_dropped();
4269 let (_, samples_before) = dual_pp_timing_snapshot();
4270 record_dual_pp_stage_result(0, Err::<f32, _>("CUDA_ERROR_NOT_READY"));
4271 let (_, samples_after) = dual_pp_timing_snapshot();
4272 assert_eq!(samples_after[0], samples_before[0]);
4273 assert!(dual_pp_timing_dropped() >= dropped_before + 1);
4274 }
4275
4276 #[test]
4277 fn corrupted_peer_readback_fails_closed_unless_host_bounce_is_selected() {
4278 assert_eq!(
4279 PEER_PROBE_TOKEN_WIDTHS,
4280 [1, 8, 16, crate::cache::PRIME_CHUNK_MAX_TOKENS],
4281 );
4282 let largest_payload_bytes = PEER_PROBE_TOKEN_WIDTHS[3] * 4096 * std::mem::size_of::<f32>();
4283 assert_eq!(largest_payload_bytes, 64 * 1024 * 1024);
4284 assert!(largest_payload_bytes >= 1024 * 1024);
4285 let expected = peer_probe_pattern(PEER_PROBE_FIXED_BYTES, 2, 0, 1);
4286 assert_eq!(
4287 peer_probe_f32_to_bytes(&peer_probe_bytes_to_f32(&expected)),
4288 expected,
4289 );
4290 let mut corrupted = expected.clone();
4291 for offset in [0, 8_191, PEER_PROBE_FIXED_BYTES - 1] {
4292 corrupted[offset] ^= 0x5a;
4293 }
4294
4295 assert_eq!(peer_probe_mismatch_count(&expected, &corrupted), 3);
4296 assert_eq!(
4297 peer_probe_decision(&expected, &corrupted, false),
4298 Err("3 mismatched byte(s)".to_string()),
4299 );
4300 assert_eq!(
4301 peer_probe_decision(&expected, &corrupted, true),
4302 Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches: 3 }),
4303 );
4304 }
4305
4306 #[test]
4307 fn probe_off_refusal_matrix_is_fail_closed_only_for_sharded_native_peer() {
4308 for probe_on in [false, true] {
4309 for sharded in [false, true] {
4310 for host_bounce in [false, true] {
4311 let got = peer_probe_startup_policy(probe_on, sharded, host_bounce);
4312 let expected = match (probe_on, sharded, host_bounce) {
4313 (false, true, false) => Err(PEER_PROBE_REQUIRED_REFUSAL),
4314 (false, true, true) => Ok(PeerProbeStartupPolicy::BypassedWithHostBounce),
4315 _ => Ok(PeerProbeStartupPolicy::Allowed),
4316 };
4317 assert_eq!(
4318 got, expected,
4319 "probe_on={probe_on} sharded={sharded} host_bounce={host_bounce}",
4320 );
4321 }
4322 }
4323 }
4324 assert!(PEER_PROBE_REQUIRED_REFUSAL.contains("MEMRA_PEER_PROBE=0"));
4325 assert!(PEER_PROBE_REQUIRED_REFUSAL.contains("MEMRA_PP_HOST_BOUNCE!=1"));
4326 }
4327
4328 #[test]
4329 fn runtime_reprobe_keeps_cheap_deadlines_live_while_expensive_work_waits_for_idle() {
4330 let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4331 assert_eq!(PEER_RUNTIME_PROBE_CYCLE_COPIES, 4 * every);
4332 let mut next = [every, 2 * every, 3 * every, 4 * every];
4333 let measured_ns = [1_000_000, 2_000_000, 3_000_000, 0];
4334
4335 assert_eq!(
4336 runtime_peer_probe_candidate(every - 1, next, measured_ns, false),
4337 None,
4338 );
4339 assert_eq!(
4340 runtime_peer_probe_candidate(every, next, measured_ns, false),
4341 Some((0, 1)),
4342 );
4343
4344 next[..3].copy_from_slice(&[5 * every, 6 * every, 7 * every]);
4347 assert_eq!(
4348 runtime_peer_probe_candidate(4 * every, next, measured_ns, false),
4349 None,
4350 );
4351 assert_eq!(
4354 runtime_peer_probe_candidate(5 * every, next, measured_ns, false),
4355 Some((0, 1)),
4356 );
4357 assert_eq!(
4359 runtime_peer_probe_candidate(5 * every, next, measured_ns, true),
4360 Some((3, crate::cache::PRIME_CHUNK_MAX_TOKENS)),
4361 );
4362 }
4363
4364 #[test]
4365 fn runtime_reprobe_moves_any_measured_over_budget_rung_to_idle_only() {
4366 let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4367 let next = [u64::MAX, every, u64::MAX, u64::MAX];
4368 let mut measured_ns = [0; PEER_PROBE_TOKEN_WIDTHS.len()];
4369 measured_ns[1] = PEER_RUNTIME_PROBE_BUDGET_NS + 1;
4370 assert_eq!(
4371 runtime_peer_probe_candidate(every, next, measured_ns, false),
4372 None
4373 );
4374 assert_eq!(
4375 runtime_peer_probe_candidate(every, next, measured_ns, true),
4376 Some((1, 8)),
4377 );
4378 }
4379
4380 #[test]
4381 fn late_runtime_reprobe_advances_once_instead_of_bursting_catchup() {
4382 let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4383 let due = every;
4384 assert_eq!(runtime_peer_probe_next_copy(due, due), due + 4 * every);
4385 assert_eq!(runtime_peer_probe_next_copy(due, 20 * every), 21 * every);
4386 }
4387
4388 #[test]
4389 fn runtime_reprobe_deferral_metric_counts_intervals_and_publishes_bound_state() {
4390 use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
4391
4392 assert_eq!(
4393 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS * PEER_RUNTIME_PROBE_INTERVAL_COPIES,
4394 PEER_RUNTIME_PROBE_CYCLE_COPIES,
4395 );
4396 let deferred = AtomicU64::new(0);
4397 let degraded = AtomicBool::new(false);
4398 publish_runtime_peer_probe_deferral(&deferred, °raded, 1, false);
4399 assert_eq!(deferred.load(Ordering::Relaxed), 1);
4400 assert!(!degraded.load(Ordering::Acquire));
4401
4402 publish_runtime_peer_probe_deferral(
4403 &deferred,
4404 °raded,
4405 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS - 1,
4406 true,
4407 );
4408 assert_eq!(
4409 deferred.load(Ordering::Relaxed),
4410 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS,
4411 );
4412 assert!(degraded.load(Ordering::Acquire));
4413 }
4414
4415 #[test]
4416 fn runtime_probe_failure_latches_native_before_publishing_validated_bounce() {
4417 use std::sync::atomic::{AtomicBool, Ordering};
4418
4419 let failed = AtomicBool::new(false);
4420 let degraded = AtomicBool::new(false);
4421 let armed = latch_runtime_host_bounce(&failed, °raded, || Ok::<_, String>(()));
4422 assert!(armed.is_ok());
4423 assert!(failed.load(Ordering::Acquire));
4424 assert!(degraded.load(Ordering::Acquire));
4425
4426 let failed = AtomicBool::new(false);
4427 let degraded = AtomicBool::new(false);
4428 let refused = latch_runtime_host_bounce(&failed, °raded, || {
4429 Err::<(), _>("injected staging mismatch".to_string())
4430 });
4431 assert_eq!(refused, Err("injected staging mismatch".to_string()));
4432 assert!(failed.load(Ordering::Acquire));
4433 assert!(!degraded.load(Ordering::Acquire));
4434 }
4435
4436 #[test]
4437 fn transport_selection_keeps_peer_default_and_bounces_only_cross_device() {
4438 assert_eq!(boundary_transport(false, false), BoundaryTransport::Local);
4439 assert_eq!(boundary_transport(false, true), BoundaryTransport::Local);
4440 assert_eq!(boundary_transport(true, false), BoundaryTransport::Peer);
4441 assert_eq!(
4442 boundary_transport(true, true),
4443 BoundaryTransport::HostBounce
4444 );
4445 }
4446
4447 #[test]
4448 fn step37_geometry_sizes_each_slot_from_the_prime_cap() {
4449 let (elems, bytes) = host_bounce_capacity(4096).expect("valid Step-3.7 geometry");
4450 assert_eq!(elems, 4096 * crate::cache::PRIME_CHUNK_MAX_TOKENS);
4451 assert_eq!(bytes, 64 * 1024 * 1024);
4452 }
4453
4454 #[test]
4455 fn host_bounce_capacity_rejects_invalid_or_overflowing_geometry() {
4456 assert!(host_bounce_capacity(0).is_err());
4457 assert!(host_bounce_capacity(usize::MAX).is_err());
4458 }
4459}