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 order_engine_behind(
2993 src: &Engine,
2994 dst: &Engine,
2995 ) -> Result<(), Box<dyn std::error::Error>> {
2996 if std::ptr::eq(src, dst) {
2997 return Ok(());
2998 }
2999 let s = src.stream();
3000 let d = dst.gpu.main_stream();
3001 if Arc::ptr_eq(&s, d) {
3002 return Ok(());
3003 }
3004 if src.ctx() == dst.ctx() {
3005 let ev = s.context().new_event(None)?;
3006 ev.record(&s)?;
3007 d.wait(&ev)?;
3008 } else {
3009 s.synchronize()?;
3010 }
3011 Ok(())
3012 }
3013
3014 pub fn bind_stage(&self, s: usize) -> Result<(), Box<dyn std::error::Error>> {
3016 self.stages[s].ctx.bind_to_thread()?;
3017 Ok(())
3018 }
3019
3020 pub fn enter(&self, s: usize) -> memra_runtime::StreamOverride {
3023 memra_runtime::push_stream_override(
3024 self.stages[s].stream.clone(),
3025 self.stages[s].blas.clone(),
3026 )
3027 }
3028
3029 pub fn prepare_overlap_slots(
3035 &self,
3036 b: usize,
3037 n: usize,
3038 ) -> Result<(), Box<dyn std::error::Error>> {
3039 let bd = &self.boundaries[b];
3040 let s_rx = &self.stages[b + 1].stream;
3041 let mut grew = false;
3042 for sl in &bd.slots {
3043 let mut guard = sl.buf.lock().unwrap();
3044 if guard.as_ref().map(|bf| bf.len() < n).unwrap_or(true) {
3045 *guard = Some(s_rx.alloc_zeros::<f32>(n)?);
3046 grew = true;
3047 }
3048 }
3049 if grew {
3050 s_rx.synchronize()?;
3051 }
3052 Ok(())
3053 }
3054
3055 pub fn boundary_slot_growth_bytes(
3059 &self,
3060 b: usize,
3061 n: usize,
3062 ) -> Result<usize, Box<dyn std::error::Error>> {
3063 let boundary = self
3064 .boundaries
3065 .get(b)
3066 .ok_or_else(|| format!("PP boundary {b} is outside the runtime"))?;
3067 let mut current = [0usize; 2];
3068 for (index, slot) in boundary.slots.iter().enumerate() {
3069 let guard = slot
3070 .buf
3071 .lock()
3072 .map_err(|_| format!("PP boundary {b} slot lock is poisoned"))?;
3073 current[index] = guard.as_ref().map_or(0, CudaSlice::len);
3074 }
3075 let elements = boundary_slot_growth_elements(current, n);
3076 Ok(elements.saturating_mul(std::mem::size_of::<f32>()))
3077 }
3078
3079 pub fn tx(
3093 &self,
3094 b: usize,
3095 x: &CudaSlice<f32>,
3096 n: usize,
3097 ) -> Result<usize, Box<dyn std::error::Error>> {
3098 assert_eq!(x.len(), n, "pp tx: residual length mismatch");
3099 let bd = &self.boundaries[b];
3100 let slot_idx = if pp2_overlap() {
3101 bd.step.fetch_add(1, Ordering::Relaxed) % 2
3102 } else {
3103 0
3104 };
3105 self.tx_slot(b, x, n, slot_idx)
3106 }
3107
3108 pub fn tx_pipelined(
3112 &self,
3113 b: usize,
3114 x: &CudaSlice<f32>,
3115 n: usize,
3116 ) -> Result<usize, Box<dyn std::error::Error>> {
3117 assert_eq!(x.len(), n, "pp tx: residual length mismatch");
3118 let slot_idx = self.boundaries[b].step.fetch_add(1, Ordering::Relaxed) % 2;
3119 self.tx_slot(b, x, n, slot_idx)
3120 }
3121
3122 fn tx_slot(
3123 &self,
3124 b: usize,
3125 x: &CudaSlice<f32>,
3126 n: usize,
3127 slot_idx: usize,
3128 ) -> Result<usize, Box<dyn std::error::Error>> {
3129 let bd = &self.boundaries[b];
3130 let path = BoundaryPath {
3131 boundary: b,
3132 src_stage: b,
3133 dst_stage: b + 1,
3134 transport: boundary_transport(bd.cross, self.host_bounce_active()),
3135 };
3136 let copied_slot = self.tx_slot_path(path, bd, x, n, slot_idx)?;
3137 if path.transport == BoundaryTransport::Peer {
3138 PEER_BOUNDARY_COPIES.fetch_add(1, Ordering::Relaxed);
3139 }
3140 Ok(copied_slot)
3141 }
3142
3143 fn tx_slot_path(
3144 &self,
3145 path: BoundaryPath,
3146 bd: &BoundaryRt,
3147 x: &CudaSlice<f32>,
3148 n: usize,
3149 slot_idx: usize,
3150 ) -> Result<usize, Box<dyn std::error::Error>> {
3151 debug_assert!(slot_idx < 2);
3152 let sl = &bd.slots[slot_idx];
3153 let s_tx = &self.stages[path.src_stage].stream;
3154 s_tx.wait(&sl.ev_rx)?;
3155 let mut guard = sl.buf.lock().unwrap();
3156 if guard.as_ref().map(|bf| bf.len() < n).unwrap_or(true) {
3157 let s_rx = &self.stages[path.dst_stage].stream;
3159 *guard = Some(s_rx.alloc_zeros::<f32>(n)?);
3160 s_rx.synchronize()?;
3170 }
3171 let buf = guard.as_mut().unwrap();
3172 match path.transport {
3173 BoundaryTransport::Local => s_tx.memcpy_dtod(x, buf)?,
3174 BoundaryTransport::HostBounce => {
3175 debug_assert_eq!(path.src_stage, path.boundary);
3176 debug_assert_eq!(path.dst_stage, path.boundary + 1);
3177 let bounce = self.bounce_rt()?;
3178 if n > bounce.capacity {
3179 return Err(format!(
3180 "pp host-bounce payload {n} exceeds geometry-sized capacity {} \
3181 (n_embd={}, max prime tokens={})",
3182 bounce.capacity,
3183 bounce.n_embd,
3184 crate::cache::PRIME_CHUNK_MAX_TOKENS,
3185 )
3186 .into());
3187 }
3188 let mut host = bounce.slot(path.boundary, slot_idx)?.lock().unwrap();
3189 s_tx.memcpy_dtoh(x, host.prefix_mut(n))?;
3193 }
3194 BoundaryTransport::Peer => {
3195 use cudarc::driver::{DevicePtr, DevicePtrMut};
3198 let (sp, _g0) = x.device_ptr(s_tx);
3199 let (dp, _g1) = buf.device_ptr_mut(s_tx);
3200 self.stages[path.src_stage].ctx.bind_to_thread()?;
3201 unsafe {
3202 cudarc::driver::result::memcpy_peer_async(
3203 self.stages[path.dst_stage].ctx.cu_ctx(),
3204 dp,
3205 self.stages[path.src_stage].ctx.cu_ctx(),
3206 sp,
3207 n * std::mem::size_of::<f32>(),
3208 s_tx.cu_stream(),
3209 )?;
3210 }
3211 }
3212 }
3213 sl.ev_tx.record(s_tx)?;
3214 Ok(slot_idx)
3215 }
3216
3217 pub fn rx(
3222 &self,
3223 b: usize,
3224 slot_idx: usize,
3225 n: usize,
3226 ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3227 let bd = &self.boundaries[b];
3228 let path = BoundaryPath {
3229 boundary: b,
3230 src_stage: b,
3231 dst_stage: b + 1,
3232 transport: boundary_transport(bd.cross, self.host_bounce_active()),
3233 };
3234 self.rx_slot_path(path, bd, slot_idx, n)
3235 }
3236
3237 fn rx_slot_path(
3238 &self,
3239 path: BoundaryPath,
3240 bd: &BoundaryRt,
3241 slot_idx: usize,
3242 n: usize,
3243 ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3244 let sl = &bd.slots[slot_idx];
3245 let s_rx = &self.stages[path.dst_stage].stream;
3246 s_rx.wait(&sl.ev_tx)?;
3247 let mut guard = sl.buf.lock().unwrap();
3248 let buf = guard.as_mut().expect("pp rx before tx");
3249 assert!(
3250 buf.len() >= n,
3251 "pp rx: slot holds {} < requested {n}",
3252 buf.len()
3253 );
3254 if path.transport == BoundaryTransport::HostBounce {
3255 debug_assert_eq!(path.src_stage, path.boundary);
3256 debug_assert_eq!(path.dst_stage, path.boundary + 1);
3257 let bounce = self.bounce_rt()?;
3258 let host = bounce.slot(path.boundary, slot_idx)?.lock().unwrap();
3259 let mut dst = buf.slice_mut(0..n);
3260 s_rx.memcpy_htod(host.prefix(n), &mut dst)?;
3263 }
3264 let mut work = unsafe { s_rx.alloc::<f32>(n)? };
3267 s_rx.memcpy_dtod(&buf.slice(0..n), &mut work)?;
3271 sl.ev_rx.record(s_rx)?;
3272 Ok(work)
3273 }
3274
3275 pub fn publish_to(
3302 &self,
3303 s: usize,
3304 dst: &Arc<CudaStream>,
3305 ) -> Result<(), Box<dyn std::error::Error>> {
3306 let st = &self.stages[s];
3307 if Arc::ptr_eq(&st.stream, dst) {
3310 return Ok(());
3311 }
3312 let ev = st.ctx.new_event(None)?;
3313 ev.record(&st.stream)?;
3314 dst.wait(&ev)?;
3315 Ok(())
3316 }
3317
3318 pub fn publish_all_to(&self, dst: &Arc<CudaStream>) -> Result<(), Box<dyn std::error::Error>> {
3349 if !pp_exit_publish() {
3350 return Ok(());
3351 }
3352 for s in 0..self.stages.len() {
3353 self.publish_to(s, dst)?;
3354 }
3355 Ok(())
3356 }
3357
3358 pub fn fence_stages_behind(
3380 &self,
3381 src: &Arc<CudaStream>,
3382 ) -> Result<(), Box<dyn std::error::Error>> {
3383 let ev = src.context().new_event(None)?;
3384 ev.record(src)?;
3385 for st in &self.stages {
3386 if Arc::ptr_eq(&st.stream, src) {
3387 continue;
3388 }
3389 st.stream.wait(&ev)?;
3390 }
3391 Ok(())
3392 }
3393
3394 pub fn record_done(&self) -> Result<CudaEvent, Box<dyn std::error::Error>> {
3397 let last = &self.stages[self.stages.len() - 1];
3398 let ev = last.ctx.new_event(None)?;
3399 ev.record(&last.stream)?;
3400 Ok(ev)
3401 }
3402
3403 pub fn readback_stream(&self) -> &Arc<CudaStream> {
3405 &self.readback
3406 }
3407}
3408
3409pub fn service_runtime_peer_probe(
3412 e: &Engine,
3413 scheduler_idle: bool,
3414 probe_allowed: bool,
3415) -> Result<RuntimePeerProbeStatus, Box<dyn std::error::Error>> {
3416 let Some(rt) = RTN.get() else {
3417 return Ok(RuntimePeerProbeStatus::NotRun);
3418 };
3419 let rt = rt
3420 .as_ref()
3421 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
3422 rt.service_runtime_peer_probe(e, scheduler_idle, probe_allowed)
3423}
3424
3425pub struct PendingLogits {
3430 logits: CudaSlice<f32>,
3431 ev: CudaEvent,
3432 rb: Arc<CudaStream>,
3433 _walk: PpWalkLease,
3434}
3435
3436impl PendingLogits {
3437 pub(crate) fn new(
3438 logits: CudaSlice<f32>,
3439 ev: CudaEvent,
3440 rb: Arc<CudaStream>,
3441 walk: PpWalkLease,
3442 ) -> Self {
3443 PendingLogits {
3444 logits,
3445 ev,
3446 rb,
3447 _walk: walk,
3448 }
3449 }
3450
3451 pub fn wait(self) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3455 self.rb.wait(&self.ev)?;
3456 let host = self.rb.clone_dtoh(&self.logits)?;
3457 self.rb.synchronize()?;
3458 Ok(host)
3461 }
3462}
3463
3464pub fn init_model_transport(
3467 e: &Engine,
3468 cfg: &memra_gguf::config::ModelConfig,
3469 n_trunk: usize,
3470) -> Result<(), Box<dyn std::error::Error>> {
3471 if pp2_streams_off() || pp2_devices_env().is_none() || pp_cuts(n_trunk).is_none() {
3472 return Ok(());
3473 }
3474 PpNRt::get(e)?.init_boundary_transport(e, cfg.n_embd as usize)
3475}
3476
3477pub fn new_cache(
3484 e: &Engine,
3485 cfg: &memra_gguf::config::ModelConfig,
3486 max_ctx: usize,
3487) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3488 new_cache_inner(e, cfg, None, max_ctx)
3489}
3490
3491pub fn new_cache_planned(
3492 e: &Engine,
3493 cfg: &memra_gguf::config::ModelConfig,
3494 plan: &memra_gguf::model_plan::ModelPlan,
3495 max_ctx: usize,
3496) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3497 new_cache_inner(e, cfg, Some(plan), max_ctx)
3498}
3499
3500fn new_cache_inner(
3501 e: &Engine,
3502 cfg: &memra_gguf::config::ModelConfig,
3503 plan: Option<&memra_gguf::model_plan::ModelPlan>,
3504 max_ctx: usize,
3505) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3506 let n_trunk = (cfg.n_layer - cfg.nextn_predict_layers) as usize;
3507 if let Some(fence) = pp_cuts(n_trunk) {
3508 if pp2_devices_env().is_some() && !pp2_streams_off() {
3509 let rt = PpNRt::get(e)?;
3510 rt.init_boundary_transport(e, cfg.n_embd as usize)?;
3511 let n_st = fence.len() - 1;
3512 assert_eq!(
3513 rt.n_stages(),
3514 n_st,
3515 "PpNRt stage count {} != fence stages {n_st}",
3516 rt.n_stages()
3517 );
3518 rt.fence_stages_behind(&e.stream())?;
3527 let devs: Vec<&dyn memra_kv::KvDev> = (0..n_st)
3528 .map(|s| rt.engine(s, e) as &dyn memra_kv::KvDev)
3529 .collect();
3530 let cache = match plan {
3531 Some(plan) => {
3532 crate::cache::Cache::new_ppn_planned(&devs, &fence, cfg, plan, max_ctx)?
3533 }
3534 None => crate::cache::Cache::new_ppn(&devs, &fence, cfg, max_ctx)?,
3535 };
3536 sync_stages_after_load(e, n_trunk)?;
3537 return Ok(cache);
3538 }
3539 if !pp2_streams_off() {
3540 let cache = match plan {
3548 Some(plan) => crate::cache::Cache::new_planned(e, cfg, plan, max_ctx)?,
3549 None => crate::cache::Cache::new(e, cfg, max_ctx)?,
3550 };
3551 sync_stages_after_load(e, n_trunk)?;
3552 return Ok(cache);
3553 }
3554 }
3555 match plan {
3556 Some(plan) => crate::cache::Cache::new_planned(e, cfg, plan, max_ctx),
3557 None => crate::cache::Cache::new(e, cfg, max_ctx),
3558 }
3559}
3560
3561pub fn sync_stages_after_load(
3570 e: &Engine,
3571 n_trunk: usize,
3572) -> Result<(), Box<dyn std::error::Error>> {
3573 if pp2_streams_off() || pp_cuts(n_trunk).is_none() {
3574 return Ok(());
3575 }
3576 let rt = PpNRt::get(e)?;
3577 for s in 0..rt.n_stages() {
3578 rt.stages[s].ctx.bind_to_thread()?;
3579 unsafe {
3580 cudarc::driver::sys::cuCtxSynchronize().result()?;
3581 }
3582 }
3583 e.ctx().bind_to_thread()?;
3584 unsafe {
3585 cudarc::driver::sys::cuCtxSynchronize().result()?;
3586 }
3587 Ok(())
3588}
3589
3590pub fn layer_engine(
3596 e: &Engine,
3597 n_trunk: usize,
3598 il: usize,
3599) -> Result<&Engine, Box<dyn std::error::Error>> {
3600 if pp_shard_off() || pp2_devices_env().is_none() || pp2_streams_off() {
3601 return Ok(e);
3602 }
3603 let Some(fence) = pp_cuts(n_trunk) else {
3604 return Ok(e);
3605 };
3606 let rt = PpNRt::get(e)?;
3607 let s = stage_of(&fence, il.min(n_trunk - 1));
3608 Ok(rt.engine(s, e))
3609}
3610
3611#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3613pub(crate) enum TpRestoreRefusal {
3614 TargetAbsent,
3616 SourceAbsent,
3618 GrowTargetNotFresh,
3620 TokenGraphDoorOpen,
3623}
3624
3625#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3627pub(crate) enum TpRestore {
3628 Nothing,
3630 Rewind(usize),
3632 Grow(usize),
3634 DropMirror,
3638 Refuse(TpRestoreRefusal),
3639}
3640
3641pub(crate) fn tp_restore_plan(
3682 snap_len: Option<usize>,
3683 source_has_tp: Option<bool>,
3684 target_has_tp: bool,
3685 token_graph_door: bool,
3686) -> TpRestore {
3687 match (source_has_tp, snap_len) {
3688 (None, Some(len)) => {
3689 if target_has_tp {
3690 TpRestore::Rewind(len)
3691 } else {
3692 TpRestore::Refuse(TpRestoreRefusal::TargetAbsent)
3693 }
3694 }
3695 (None, None) => {
3696 if !target_has_tp {
3697 TpRestore::Nothing
3698 } else if token_graph_door {
3699 TpRestore::Refuse(TpRestoreRefusal::TokenGraphDoorOpen)
3700 } else {
3701 TpRestore::DropMirror
3702 }
3703 }
3704 (Some(source_has_tp), Some(len)) => {
3705 if !source_has_tp {
3706 TpRestore::Refuse(TpRestoreRefusal::SourceAbsent)
3707 } else if target_has_tp {
3708 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
3709 } else {
3710 TpRestore::Grow(len)
3711 }
3712 }
3713 (Some(_), None) => {
3714 if target_has_tp {
3715 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
3717 } else {
3718 TpRestore::Nothing
3723 }
3724 }
3725 }
3726}
3727
3728pub fn restore_cache_checkpoint(
3740 e: &Engine,
3741 model: &crate::hybrid::HybridModel,
3742 source: Option<&crate::cache::Cache>,
3743 target: &mut crate::cache::Cache,
3744 snap: &crate::cache::CacheSnapshot,
3745) -> Result<(), Box<dyn std::error::Error>> {
3746 target.ensure_usable("restore_cache_checkpoint target")?;
3747 if let Some(source) = source {
3748 source.ensure_usable("restore_cache_checkpoint source")?;
3749 }
3750 let cfg = &model.cfg;
3751 let n = target.kv.len();
3752 if target.recur.len() != n
3753 || target.tp_kv.len() != n
3754 || snap.kv_len.len() != n
3755 || snap.tp_kv_len.len() != n
3756 || snap.conv.len() != n
3757 || snap.ssm.len() != n
3758 || source.is_some_and(|s| s.kv.len() != n || s.recur.len() != n || s.tp_kv.len() != n)
3759 {
3760 return Err("checkpoint cache layer-count mismatch".into());
3761 }
3762 if snap.pos > target.max_ctx {
3763 return Err(format!(
3764 "checkpoint pos {} exceeds target capacity {}",
3765 snap.pos, target.max_ctx,
3766 )
3767 .into());
3768 }
3769
3770 let n_trunk = (cfg.n_layer - cfg.nextn_predict_layers) as usize;
3771 let token_graph_door = crate::tp::step_tp_graph_enabled().unwrap_or(false);
3773 let mut dropped_mirrors = 0usize;
3774 for il in 0..n {
3775 let owner = layer_engine(e, n_trunk, il)?;
3776 let src_kv = source.map(|s| &s.kv[il]);
3777 match (src_kv, target.kv[il].as_mut(), snap.kv_len[il]) {
3778 (Some(Some(src)), Some(dst), Some(len)) => {
3779 if len > src.len || len > target.max_ctx {
3780 return Err(format!(
3781 "checkpoint layer {il} len {len} exceeds source {} or target {}",
3782 src.len, target.max_ctx,
3783 )
3784 .into());
3785 }
3786 if src.kv_dim_k != dst.kv_dim_k
3787 || src.kv_dim_v != dst.kv_dim_v
3788 || src.k_tok_bytes != dst.k_tok_bytes
3789 || src.v_tok_bytes != dst.v_tok_bytes
3790 {
3791 return Err(format!("checkpoint KV layout mismatch at layer {il}").into());
3792 }
3793 match (&src.ring, dst.ring.as_ref()) {
3794 (Some(sring), Some(dring)) => {
3795 if dring.base() != 0 {
3801 return Err(format!(
3802 "checkpoint SWA restore at layer {il} requires a fresh target \
3803 ring (base {}, expected 0)",
3804 dring.base(),
3805 )
3806 .into());
3807 }
3808 let (new_base, phys) = sring.restore_plan(len).map_err(|e| {
3809 format!("checkpoint SWA restore refused at layer {il}: {e}")
3810 })?;
3811 let rows = phys.len();
3812 let kb = rows * src.k_tok_bytes;
3813 let vb = rows * src.v_tok_bytes;
3814 if kb > 0 {
3815 owner.copy_u8_range_into(
3816 &mut dst.k,
3817 0,
3818 &src.k,
3819 phys.start * src.k_tok_bytes,
3820 kb,
3821 )?;
3822 }
3823 if vb > 0 {
3824 owner.copy_u8_range_into(
3825 &mut dst.v,
3826 0,
3827 &src.v,
3828 phys.start * src.v_tok_bytes,
3829 vb,
3830 )?;
3831 }
3832 dst.ring
3833 .as_mut()
3834 .expect("ring presence checked above")
3835 .apply_rebase(new_base);
3836 if let Some(base_d) = dst.base_d.as_mut() {
3837 owner.set_i32_one(base_d, new_base as i32)?;
3838 }
3839 }
3840 (None, None) => {
3841 let kb = len * src.k_tok_bytes;
3842 let vb = len * src.v_tok_bytes;
3843 if kb > 0 {
3844 owner.copy_u8_into(&mut dst.k, 0, &src.k, kb)?;
3845 }
3846 if vb > 0 {
3847 owner.copy_u8_into(&mut dst.v, 0, &src.v, vb)?;
3848 }
3849 }
3850 _ => {
3851 return Err(
3852 format!("checkpoint ring/flat KV mismatch at layer {il}").into()
3853 );
3854 }
3855 }
3856 dst.len = len;
3857 owner.set_i32_one(&mut dst.len_d, len as i32)?;
3858 }
3859 (None, Some(dst), Some(len)) => {
3860 if len > dst.len || len > target.max_ctx {
3861 return Err(format!(
3862 "checkpoint layer {il} len {len} exceeds live {} or target {}",
3863 dst.len, target.max_ctx,
3864 )
3865 .into());
3866 }
3867 if let Some(ring) = &dst.ring
3868 && !ring.can_rewind_to(len)
3869 {
3870 return Err(format!(
3871 "checkpoint SWA rewind at layer {il} has been lapped \
3872 (len {len}, ring base {}); full re-prime required",
3873 ring.base(),
3874 )
3875 .into());
3876 }
3877 dst.len = len;
3878 owner.set_i32_one(&mut dst.len_d, len as i32)?;
3879 }
3880 (Some(None), None, None) | (None, None, None) => {}
3881 _ => return Err(format!("checkpoint KV kind mismatch at layer {il}").into()),
3882 }
3883
3884 match tp_restore_plan(
3885 snap.tp_kv_len[il],
3886 source.map(|s| s.tp_kv[il].is_some()),
3887 target.tp_kv[il].is_some(),
3888 token_graph_door,
3889 ) {
3890 TpRestore::Nothing => {}
3891 TpRestore::Rewind(len) => target.tp_kv[il]
3892 .as_mut()
3893 .expect("tp_restore_plan::Rewind implies a present target mirror")
3894 .rewind_to(len)?,
3895 TpRestore::Grow(len) => {
3896 let src = source
3897 .and_then(|s| s.tp_kv[il].as_ref())
3898 .expect("tp_restore_plan::Grow implies a present source mirror");
3899 let runtime = model.step_tp_runtime_for_layer(il).ok_or_else(|| {
3900 format!("checkpoint TP KV layer {il} has no distributed runtime")
3901 })?;
3902 let grown = runtime.grow_tp_kv_cache(src, target.max_ctx, len)?;
3903 target.tp_kv[il] = Some(grown);
3904 }
3905 TpRestore::DropMirror => {
3906 if target.tp_kv[il].take().is_some() {
3910 dropped_mirrors += 1;
3911 }
3912 }
3913 TpRestore::Refuse(reason) => {
3914 return Err(format!(
3915 "checkpoint TP KV restore refused at layer {il}: {} \
3916 (snap.tp_kv_len={:?}, snap.kv_len={:?}, snap.pos={}, \
3917 source_has_tp={:?}, target_has_tp={}, target_committed={})",
3918 match reason {
3919 TpRestoreRefusal::TargetAbsent =>
3920 "the snapshot recorded a distributed length but the target holds no \
3921 distributed cache to rewind",
3922 TpRestoreRefusal::SourceAbsent =>
3923 "the snapshot recorded a distributed length the parked source cannot \
3924 supply",
3925 TpRestoreRefusal::GrowTargetNotFresh =>
3926 "the freshly allocated grow target already holds a distributed cache",
3927 TpRestoreRefusal::TokenGraphDoorOpen =>
3928 "MEMRA_STEP_TP_GRAPH is open, and its model-level whole-token graph \
3929 bakes the rank-cache pointers, so the stale mirror cannot be freed",
3930 },
3931 snap.tp_kv_len[il],
3932 snap.kv_len[il],
3933 snap.pos,
3934 source.map(|s| s.tp_kv[il].is_some()),
3935 target.tp_kv[il].is_some(),
3936 target.tp_kv[il]
3937 .as_ref()
3938 .map(|c| c.committed_len())
3939 .unwrap_or(0),
3940 )
3941 .into());
3942 }
3943 }
3944
3945 match (target.recur[il].as_mut(), &snap.conv[il], &snap.ssm[il]) {
3946 (Some(dst), Some(conv), Some(ssm)) => {
3947 if conv.len() != dst.conv_state.len() || ssm.len() != dst.ssm_state.len() {
3948 return Err(
3949 format!("checkpoint recurrent layout mismatch at layer {il}").into(),
3950 );
3951 }
3952 owner.copy_into(&mut dst.conv_state, 0, conv, conv.len())?;
3953 owner.copy_into(&mut dst.ssm_state, 0, ssm, ssm.len())?;
3954 }
3955 (None, None, None) => {}
3956 _ => {
3957 return Err(format!("checkpoint recurrent kind mismatch at layer {il}").into());
3958 }
3959 }
3960 }
3961 target.pos = snap.pos;
3962 if dropped_mirrors > 0 {
3963 eprintln!(
3967 "[pp] checkpoint restore: cleared {dropped_mirrors} stale distributed KV mirror(s) \
3968 at pos {} (snapshot predates lazy TP hydration); the next TP use rehydrates them \
3969 from the local plane",
3970 snap.pos,
3971 );
3972 }
3973
3974 sync_stages_after_load(e, n_trunk)?;
3977 if source.is_some() {
3978 e.stream().synchronize()?;
3981 }
3982 Ok(())
3983}
3984
3985#[cfg(test)]
3986mod host_bounce_tests {
3987 use super::{
3988 BoundaryTransport, DUAL_PP_HOST_BOUNCE_REFUSAL, DUAL_PP_SINGLE_SLOT_REFUSAL,
3989 PEER_PROBE_FIXED_BYTES, PEER_PROBE_REQUIRED_REFUSAL, PEER_PROBE_TOKEN_WIDTHS,
3990 PEER_RUNTIME_PROBE_BUDGET_NS, PEER_RUNTIME_PROBE_CYCLE_COPIES,
3991 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS, PEER_RUNTIME_PROBE_INTERVAL_COPIES,
3992 PP_WAVE_MAX_STAGES, PeerProbeDecision, PeerProbeStartupPolicy, acquire_pp_walk,
3993 boundary_slot_growth_elements, boundary_transport, dual_pp_eligibility,
3994 dual_pp_timing_dropped, dual_pp_timing_snapshot, dual_pp_wave_mid, enter_pp_wave_cell,
3995 host_bounce_capacity, latch_runtime_host_bounce, peer_probe_bytes_to_f32,
3996 peer_probe_decision, peer_probe_f32_to_bytes, peer_probe_mismatch_count,
3997 peer_probe_pattern, peer_probe_startup_policy, pp_devices_repeat, pp_wave_diagonal,
3998 pp_wave_eligibility, pp_wave_numeric_eligibility, pp_wave_on_value, pp_wave_ranges,
3999 pp_wave_route_enabled, pp_wave_snapshot, publish_runtime_peer_probe_deferral,
4000 record_dual_pp_stage_result, record_pp_wave_tick, runtime_peer_probe_candidate,
4001 runtime_peer_probe_next_copy,
4002 };
4003
4004 use super::{TpRestore, TpRestoreRefusal, tp_restore_plan};
4014
4015 #[test]
4016 fn mismatch_snapshot_predating_lazy_tp_drops_the_mirror_instead_of_refusing() {
4017 assert_eq!(
4019 tp_restore_plan(None, None, true, false),
4020 TpRestore::DropMirror
4021 );
4022 }
4023
4024 #[test]
4025 fn mismatch_on_the_grow_path_leaves_the_fresh_target_without_a_mirror() {
4026 assert_eq!(
4029 tp_restore_plan(None, Some(true), false, false),
4030 TpRestore::Nothing
4031 );
4032 }
4033
4034 #[test]
4035 fn drop_is_refused_while_the_token_graph_door_bakes_rank_pointers() {
4036 assert_eq!(
4037 tp_restore_plan(None, None, true, true),
4038 TpRestore::Refuse(TpRestoreRefusal::TokenGraphDoorOpen)
4039 );
4040 }
4041
4042 #[test]
4043 fn healthy_arms_are_untouched() {
4044 assert_eq!(
4045 tp_restore_plan(None, None, false, false),
4046 TpRestore::Nothing
4047 );
4048 assert_eq!(tp_restore_plan(None, None, false, true), TpRestore::Nothing);
4049 assert_eq!(
4050 tp_restore_plan(Some(15222), None, true, false),
4051 TpRestore::Rewind(15222)
4052 );
4053 assert_eq!(
4054 tp_restore_plan(Some(15222), Some(true), false, false),
4055 TpRestore::Grow(15222)
4056 );
4057 assert_eq!(
4058 tp_restore_plan(None, Some(false), false, false),
4059 TpRestore::Nothing
4060 );
4061 }
4062
4063 #[test]
4064 fn refuses_a_recorded_distributed_length_with_no_target_mirror() {
4065 assert_eq!(
4066 tp_restore_plan(Some(15222), None, false, false),
4067 TpRestore::Refuse(TpRestoreRefusal::TargetAbsent)
4068 );
4069 }
4070
4071 #[test]
4072 fn refuses_a_recorded_distributed_length_the_source_cannot_supply() {
4073 assert_eq!(
4074 tp_restore_plan(Some(15222), Some(false), false, false),
4075 TpRestore::Refuse(TpRestoreRefusal::SourceAbsent)
4076 );
4077 }
4078
4079 #[test]
4080 fn refuses_a_grow_target_that_is_not_fresh() {
4081 assert_eq!(
4082 tp_restore_plan(Some(15222), Some(true), true, false),
4083 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
4084 );
4085 assert_eq!(
4086 tp_restore_plan(None, Some(true), true, false),
4087 TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
4088 );
4089 }
4090
4091 #[test]
4095 fn flip_default_is_dual_auto_with_explicit_off_and_forced_seams() {
4096 use super::{DualPpMode, dual_pp_mode_resolve};
4097 assert_eq!(dual_pp_mode_resolve(None), DualPpMode::Auto);
4098 assert_eq!(dual_pp_mode_resolve(Some("0")), DualPpMode::Off);
4099 assert_eq!(dual_pp_mode_resolve(Some("1")), DualPpMode::Forced);
4100 assert_eq!(dual_pp_mode_resolve(Some("2")), DualPpMode::Auto);
4102 assert_eq!(dual_pp_mode_resolve(Some("")), DualPpMode::Auto);
4103 }
4104
4105 #[test]
4106 fn flip_overlap_follows_mode_and_one_flag_restores_preflip_serial() {
4107 use super::{DualPpMode, pp2_overlap_resolve};
4108 assert!(pp2_overlap_resolve(None, DualPpMode::Auto));
4110 assert!(!pp2_overlap_resolve(None, DualPpMode::Off));
4112 assert!(!pp2_overlap_resolve(None, DualPpMode::Forced));
4114 for mode in [DualPpMode::Off, DualPpMode::Forced, DualPpMode::Auto] {
4116 assert!(pp2_overlap_resolve(Some("1"), mode));
4117 assert!(!pp2_overlap_resolve(Some("0"), mode));
4118 }
4119 }
4120
4121 #[test]
4122 fn flip_auto_routes_only_the_regated_regime_and_degrades_serially_elsewhere() {
4123 use super::{DualPpMode, dual_pp_route};
4124 assert!(dual_pp_route(DualPpMode::Auto, 2, 2, true, false));
4126 assert!(dual_pp_route(DualPpMode::Auto, 17, 2, true, false));
4127 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));
4134 assert!(!dual_pp_route(DualPpMode::Forced, 1, 2, true, false));
4135 assert!(!dual_pp_route(DualPpMode::Off, 8, 2, true, false));
4137 }
4138
4139 #[test]
4140 fn pp_wave_flag_is_strict_and_does_not_inherit_the_pp2_default() {
4141 assert_eq!(pp_wave_on_value(None), Ok(false));
4142 assert!(pp_wave_on_value(Some("")).is_err());
4143 assert_eq!(pp_wave_on_value(Some("0")), Ok(false));
4144 assert_eq!(pp_wave_on_value(Some("1")), Ok(true));
4145 assert!(pp_wave_on_value(Some("auto")).is_err());
4146 assert!(pp_wave_on_value(Some("2")).is_err());
4147 }
4148
4149 #[test]
4150 fn pp_wave_route_treats_overlap_off_and_single_work_item_as_serial_rollback() {
4151 assert!(pp_wave_route_enabled(true, true, 3, 2));
4152 assert!(pp_wave_route_enabled(true, true, 4, 8));
4153 assert!(!pp_wave_route_enabled(true, false, 3, 8));
4154 assert!(!pp_wave_route_enabled(false, true, 3, 8));
4155 assert!(!pp_wave_route_enabled(true, true, 2, 8));
4156 assert!(!pp_wave_route_enabled(true, true, 4, 1));
4157 }
4158
4159 #[test]
4160 fn pp_wave_ranges_are_balanced_contiguous_and_priority_preserving() {
4161 assert!(pp_wave_ranges(0, 4).is_empty());
4162 assert!(pp_wave_ranges(8, 0).is_empty());
4163 assert_eq!(pp_wave_ranges(1, 4), vec![(0, 1)]);
4164 assert_eq!(pp_wave_ranges(2, 4), vec![(0, 1), (1, 2)]);
4165 assert_eq!(pp_wave_ranges(8, 4), vec![(0, 2), (2, 4), (4, 6), (6, 8)]);
4166 assert_eq!(
4167 pp_wave_ranges(17, 4),
4168 vec![(0, 5), (5, 9), (9, 13), (13, 17)]
4169 );
4170 for batch in 1..=64 {
4171 for stages in 2..=PP_WAVE_MAX_STAGES {
4172 let ranges = pp_wave_ranges(batch, stages);
4173 assert_eq!(ranges.len(), batch.min(stages));
4174 assert_eq!(ranges.first().copied().unwrap().0, 0);
4175 assert_eq!(ranges.last().copied().unwrap().1, batch);
4176 assert!(ranges.iter().all(|(lo, hi)| lo < hi));
4177 assert!(ranges.windows(2).all(|pair| pair[0].1 == pair[1].0));
4178 let widths: Vec<_> = ranges.iter().map(|(lo, hi)| hi - lo).collect();
4179 assert!(widths.windows(2).all(|pair| pair[0] >= pair[1]));
4180 assert!(widths.first().unwrap() - widths.last().unwrap() <= 1);
4181 }
4182 }
4183 }
4184
4185 #[test]
4186 fn pp_wave_diagonals_cover_the_grid_without_stage_or_wave_aliasing() {
4187 for stages in 3..=PP_WAVE_MAX_STAGES {
4188 for waves in 1..=stages {
4189 let mut seen = vec![vec![false; stages]; waves];
4190 for diagonal in 0..stages + waves - 1 {
4191 let cells = pp_wave_diagonal(stages, waves, diagonal);
4192 let mut stage_seen = vec![false; stages];
4193 let mut wave_seen = vec![false; waves];
4194 for (wave, stage) in cells {
4195 assert_eq!(wave + stage, diagonal);
4196 assert!(!stage_seen[stage]);
4197 assert!(!wave_seen[wave]);
4198 assert!(!seen[wave][stage]);
4199 stage_seen[stage] = true;
4200 wave_seen[wave] = true;
4201 seen[wave][stage] = true;
4202 }
4203 }
4204 assert!(seen.into_iter().flatten().all(|cell| cell));
4205 }
4206 }
4207 assert!(pp_wave_diagonal(4, 4, 7).is_empty());
4208 }
4209
4210 #[test]
4211 fn pp_wavefront_refuses_every_unqualified_transport_shape() {
4212 assert!(pp_wave_eligibility(3, true, false, false).is_ok());
4213 assert!(pp_wave_eligibility(4, true, false, false).is_ok());
4214 assert!(pp_wave_eligibility(2, true, false, false).is_err());
4215 assert!(pp_wave_eligibility(5, true, false, false).is_err());
4216 assert!(pp_wave_eligibility(3, false, false, false).is_err());
4217 assert!(pp_wave_eligibility(3, true, true, false).is_err());
4218 assert!(pp_wave_eligibility(3, true, false, true).is_err());
4219 }
4220
4221 #[test]
4222 fn pp_wavefront_requires_width_invariant_bf16_for_w4a16() {
4223 assert!(pp_wave_numeric_eligibility(false, false).is_ok());
4224 assert!(pp_wave_numeric_eligibility(false, true).is_ok());
4225 assert!(pp_wave_numeric_eligibility(true, true).is_ok());
4226 assert!(pp_wave_numeric_eligibility(true, false).is_err());
4227 }
4228
4229 #[test]
4230 fn pp_device_aliases_cannot_bypass_the_distinct_stage_gate() {
4231 assert!(!pp_devices_repeat("0,1,2,3"));
4232 assert!(pp_devices_repeat("0,00,1"));
4233 assert!(pp_devices_repeat("2,1,2"));
4234 assert!(pp_devices_repeat("0,nope,1"));
4235 }
4236
4237 #[test]
4238 fn pp_walk_owner_refuses_reentry_and_releases_at_scope_end() {
4239 let active = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
4240 let next = std::sync::atomic::AtomicU64::new(1);
4241 let first = acquire_pp_walk(&active, &next, 7, None, "first").unwrap();
4242 let held_clone = super::PpWalkLease {
4243 state: first.state.clone(),
4244 };
4245 let error = acquire_pp_walk(&active, &next, 7, None, "second").unwrap_err();
4246 assert!(error.contains("refused concurrent PP walk"));
4247 drop(first);
4248 assert!(acquire_pp_walk(&active, &next, 7, None, "third").is_err());
4249 drop(held_clone);
4250 assert!(acquire_pp_walk(&active, &next, 7, None, "fourth").is_ok());
4251 }
4252
4253 #[test]
4254 fn pp_walk_coordinator_borrow_is_explicit_and_thread_local() {
4255 let active = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
4256 let next = std::sync::atomic::AtomicU64::new(1);
4257 let lease = acquire_pp_walk(&active, &next, 11, None, "owner").unwrap();
4258 let state = lease.state.clone();
4259 super::PP_WALK_BORROWS.with(|borrows| borrows.borrow_mut().push(state.clone()));
4260 assert!(super::borrowed_pp_walk(11).is_some());
4261 std::thread::spawn(move || {
4262 assert!(super::borrowed_pp_walk(11).is_none());
4263 drop(state);
4264 })
4265 .join()
4266 .unwrap();
4267 super::PP_WALK_BORROWS.with(|borrows| borrows.borrow_mut().clear());
4268 drop(lease);
4269 assert_eq!(active.load(std::sync::atomic::Ordering::Acquire), 0);
4270 }
4271
4272 #[test]
4273 fn boundary_growth_charges_first_allocation_and_only_missing_high_water_afterward() {
4274 assert_eq!(boundary_slot_growth_elements([0, 0], 4096), 8192);
4275 assert_eq!(boundary_slot_growth_elements([4096, 4096], 4096), 0);
4276 assert_eq!(boundary_slot_growth_elements([4096, 2048], 4096), 2048);
4277 assert_eq!(boundary_slot_growth_elements([8192, 8192], 4096), 0);
4278 }
4279
4280 #[test]
4281 fn pp_wave_liveness_snapshot_counts_ticks_cells_and_real_overlap() {
4282 let before = pp_wave_snapshot();
4283 let first = enter_pp_wave_cell();
4284 let second = enter_pp_wave_cell();
4285 drop(second);
4286 drop(first);
4287 record_pp_wave_tick();
4288 let after = pp_wave_snapshot();
4289 assert!(after.0 > before.0);
4290 assert!(after.1 >= before.1 + 2);
4291 assert!(after.2 > before.2);
4292 }
4293
4294 #[test]
4295 fn dual_pp_split_is_honest_at_one_and_ceil_first_afterward() {
4296 assert_eq!(dual_pp_wave_mid(1), None);
4297 assert_eq!(dual_pp_wave_mid(2), Some(1));
4298 assert_eq!(dual_pp_wave_mid(3), Some(2));
4299 assert_eq!(dual_pp_wave_mid(8), Some(4));
4300 assert_eq!(dual_pp_wave_mid(16), Some(8));
4301 assert_eq!(dual_pp_wave_mid(31), Some(16));
4302 assert_eq!(dual_pp_wave_mid(32), Some(16));
4303 }
4304
4305 #[test]
4306 fn dual_pp_refuses_single_slot_and_non_pp2_shapes() {
4307 assert_eq!(
4308 dual_pp_eligibility(2, false, false),
4309 Err(DUAL_PP_SINGLE_SLOT_REFUSAL)
4310 );
4311 assert!(dual_pp_eligibility(2, true, false).is_ok());
4312 assert!(dual_pp_eligibility(3, true, false).is_err());
4313 }
4314
4315 #[test]
4316 fn dual_pp_refuses_unvalidated_host_bounce_transport() {
4317 assert_eq!(
4318 dual_pp_eligibility(2, true, true),
4319 Err(DUAL_PP_HOST_BOUNCE_REFUSAL),
4320 );
4321 }
4322
4323 #[test]
4324 #[allow(clippy::int_plus_one)] fn dual_pp_timing_error_is_counted_without_recording_a_sample() {
4326 let dropped_before = dual_pp_timing_dropped();
4327 let (_, samples_before) = dual_pp_timing_snapshot();
4328 record_dual_pp_stage_result(0, Err::<f32, _>("CUDA_ERROR_NOT_READY"));
4329 let (_, samples_after) = dual_pp_timing_snapshot();
4330 assert_eq!(samples_after[0], samples_before[0]);
4331 assert!(dual_pp_timing_dropped() >= dropped_before + 1);
4332 }
4333
4334 #[test]
4335 fn corrupted_peer_readback_fails_closed_unless_host_bounce_is_selected() {
4336 assert_eq!(
4337 PEER_PROBE_TOKEN_WIDTHS,
4338 [1, 8, 16, crate::cache::PRIME_CHUNK_MAX_TOKENS],
4339 );
4340 let largest_payload_bytes = PEER_PROBE_TOKEN_WIDTHS[3] * 4096 * std::mem::size_of::<f32>();
4341 assert_eq!(largest_payload_bytes, 64 * 1024 * 1024);
4342 assert!(largest_payload_bytes >= 1024 * 1024);
4343 let expected = peer_probe_pattern(PEER_PROBE_FIXED_BYTES, 2, 0, 1);
4344 assert_eq!(
4345 peer_probe_f32_to_bytes(&peer_probe_bytes_to_f32(&expected)),
4346 expected,
4347 );
4348 let mut corrupted = expected.clone();
4349 for offset in [0, 8_191, PEER_PROBE_FIXED_BYTES - 1] {
4350 corrupted[offset] ^= 0x5a;
4351 }
4352
4353 assert_eq!(peer_probe_mismatch_count(&expected, &corrupted), 3);
4354 assert_eq!(
4355 peer_probe_decision(&expected, &corrupted, false),
4356 Err("3 mismatched byte(s)".to_string()),
4357 );
4358 assert_eq!(
4359 peer_probe_decision(&expected, &corrupted, true),
4360 Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches: 3 }),
4361 );
4362 }
4363
4364 #[test]
4365 fn probe_off_refusal_matrix_is_fail_closed_only_for_sharded_native_peer() {
4366 for probe_on in [false, true] {
4367 for sharded in [false, true] {
4368 for host_bounce in [false, true] {
4369 let got = peer_probe_startup_policy(probe_on, sharded, host_bounce);
4370 let expected = match (probe_on, sharded, host_bounce) {
4371 (false, true, false) => Err(PEER_PROBE_REQUIRED_REFUSAL),
4372 (false, true, true) => Ok(PeerProbeStartupPolicy::BypassedWithHostBounce),
4373 _ => Ok(PeerProbeStartupPolicy::Allowed),
4374 };
4375 assert_eq!(
4376 got, expected,
4377 "probe_on={probe_on} sharded={sharded} host_bounce={host_bounce}",
4378 );
4379 }
4380 }
4381 }
4382 assert!(PEER_PROBE_REQUIRED_REFUSAL.contains("MEMRA_PEER_PROBE=0"));
4383 assert!(PEER_PROBE_REQUIRED_REFUSAL.contains("MEMRA_PP_HOST_BOUNCE!=1"));
4384 }
4385
4386 #[test]
4387 fn runtime_reprobe_keeps_cheap_deadlines_live_while_expensive_work_waits_for_idle() {
4388 let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4389 assert_eq!(PEER_RUNTIME_PROBE_CYCLE_COPIES, 4 * every);
4390 let mut next = [every, 2 * every, 3 * every, 4 * every];
4391 let measured_ns = [1_000_000, 2_000_000, 3_000_000, 0];
4392
4393 assert_eq!(
4394 runtime_peer_probe_candidate(every - 1, next, measured_ns, false),
4395 None,
4396 );
4397 assert_eq!(
4398 runtime_peer_probe_candidate(every, next, measured_ns, false),
4399 Some((0, 1)),
4400 );
4401
4402 next[..3].copy_from_slice(&[5 * every, 6 * every, 7 * every]);
4405 assert_eq!(
4406 runtime_peer_probe_candidate(4 * every, next, measured_ns, false),
4407 None,
4408 );
4409 assert_eq!(
4412 runtime_peer_probe_candidate(5 * every, next, measured_ns, false),
4413 Some((0, 1)),
4414 );
4415 assert_eq!(
4417 runtime_peer_probe_candidate(5 * every, next, measured_ns, true),
4418 Some((3, crate::cache::PRIME_CHUNK_MAX_TOKENS)),
4419 );
4420 }
4421
4422 #[test]
4423 fn runtime_reprobe_moves_any_measured_over_budget_rung_to_idle_only() {
4424 let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4425 let next = [u64::MAX, every, u64::MAX, u64::MAX];
4426 let mut measured_ns = [0; PEER_PROBE_TOKEN_WIDTHS.len()];
4427 measured_ns[1] = PEER_RUNTIME_PROBE_BUDGET_NS + 1;
4428 assert_eq!(
4429 runtime_peer_probe_candidate(every, next, measured_ns, false),
4430 None
4431 );
4432 assert_eq!(
4433 runtime_peer_probe_candidate(every, next, measured_ns, true),
4434 Some((1, 8)),
4435 );
4436 }
4437
4438 #[test]
4439 fn late_runtime_reprobe_advances_once_instead_of_bursting_catchup() {
4440 let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4441 let due = every;
4442 assert_eq!(runtime_peer_probe_next_copy(due, due), due + 4 * every);
4443 assert_eq!(runtime_peer_probe_next_copy(due, 20 * every), 21 * every);
4444 }
4445
4446 #[test]
4447 fn runtime_reprobe_deferral_metric_counts_intervals_and_publishes_bound_state() {
4448 use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
4449
4450 assert_eq!(
4451 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS * PEER_RUNTIME_PROBE_INTERVAL_COPIES,
4452 PEER_RUNTIME_PROBE_CYCLE_COPIES,
4453 );
4454 let deferred = AtomicU64::new(0);
4455 let degraded = AtomicBool::new(false);
4456 publish_runtime_peer_probe_deferral(&deferred, °raded, 1, false);
4457 assert_eq!(deferred.load(Ordering::Relaxed), 1);
4458 assert!(!degraded.load(Ordering::Acquire));
4459
4460 publish_runtime_peer_probe_deferral(
4461 &deferred,
4462 °raded,
4463 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS - 1,
4464 true,
4465 );
4466 assert_eq!(
4467 deferred.load(Ordering::Relaxed),
4468 PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS,
4469 );
4470 assert!(degraded.load(Ordering::Acquire));
4471 }
4472
4473 #[test]
4474 fn runtime_probe_failure_latches_native_before_publishing_validated_bounce() {
4475 use std::sync::atomic::{AtomicBool, Ordering};
4476
4477 let failed = AtomicBool::new(false);
4478 let degraded = AtomicBool::new(false);
4479 let armed = latch_runtime_host_bounce(&failed, °raded, || Ok::<_, String>(()));
4480 assert!(armed.is_ok());
4481 assert!(failed.load(Ordering::Acquire));
4482 assert!(degraded.load(Ordering::Acquire));
4483
4484 let failed = AtomicBool::new(false);
4485 let degraded = AtomicBool::new(false);
4486 let refused = latch_runtime_host_bounce(&failed, °raded, || {
4487 Err::<(), _>("injected staging mismatch".to_string())
4488 });
4489 assert_eq!(refused, Err("injected staging mismatch".to_string()));
4490 assert!(failed.load(Ordering::Acquire));
4491 assert!(!degraded.load(Ordering::Acquire));
4492 }
4493
4494 #[test]
4495 fn transport_selection_keeps_peer_default_and_bounces_only_cross_device() {
4496 assert_eq!(boundary_transport(false, false), BoundaryTransport::Local);
4497 assert_eq!(boundary_transport(false, true), BoundaryTransport::Local);
4498 assert_eq!(boundary_transport(true, false), BoundaryTransport::Peer);
4499 assert_eq!(
4500 boundary_transport(true, true),
4501 BoundaryTransport::HostBounce
4502 );
4503 }
4504
4505 #[test]
4506 fn step37_geometry_sizes_each_slot_from_the_prime_cap() {
4507 let (elems, bytes) = host_bounce_capacity(4096).expect("valid Step-3.7 geometry");
4508 assert_eq!(elems, 4096 * crate::cache::PRIME_CHUNK_MAX_TOKENS);
4509 assert_eq!(bytes, 64 * 1024 * 1024);
4510 }
4511
4512 #[test]
4513 fn host_bounce_capacity_rejects_invalid_or_overflowing_geometry() {
4514 assert!(host_bounce_capacity(0).is_err());
4515 assert!(host_bounce_capacity(usize::MAX).is_err());
4516 }
4517}