1use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
77use std::sync::{Arc, Mutex, OnceLock};
78
79use cudarc::driver::{CudaContext, CudaEvent, CudaSlice, CudaStream};
80
81use crate::Engine;
82
83pub fn pp_cuts(n_layers: usize) -> Option<Vec<usize>> {
88 let n_st: usize = match std::env::var("MEMRA_PP_STAGES") {
89 Ok(v) if v.is_empty() || v == "0" || v == "1" => return None,
90 Ok(v) => match v.parse::<usize>() {
91 Ok(n) => n,
92 Err(_) => {
93 warn_bad_once(&format!("MEMRA_PP_STAGES={v} unparseable; door stays OFF"));
94 return None;
95 }
96 },
97 Err(_) => return None,
98 };
99 if n_st < 2 || n_st > n_layers {
100 warn_bad_once(&format!(
101 "MEMRA_PP_STAGES={n_st} outside [2, n_layers={n_layers}]; door stays OFF"
102 ));
103 return None;
104 }
105 let mut fence = Vec::with_capacity(n_st + 1);
106 fence.push(0usize);
107 if let Ok(s) = std::env::var("MEMRA_PP_SPLITS") {
108 let parts: Result<Vec<usize>, _> =
109 s.split(',').map(|p| p.trim().parse::<usize>()).collect();
110 match parts {
111 Ok(cuts) if cuts.len() == n_st - 1 => fence.extend(cuts),
112 _ => {
113 warn_bad_once(&format!(
114 "MEMRA_PP_SPLITS={s} invalid (want {} comma-separated cuts); door stays OFF",
115 n_st - 1
116 ));
117 return None;
118 }
119 }
120 } else if let Ok(v) = std::env::var("MEMRA_PP_SPLIT") {
121 if n_st != 2 {
124 warn_bad_once(&format!(
125 "MEMRA_PP_SPLIT={v} set with MEMRA_PP_STAGES={n_st}; use MEMRA_PP_SPLITS \
126 for N>2 — door stays OFF"
127 ));
128 return None;
129 }
130 match v.parse::<usize>() {
131 Ok(c) => fence.push(c),
132 Err(_) => {
133 warn_bad_once(&format!("MEMRA_PP_SPLIT={v} unparseable; door stays OFF"));
134 return None;
135 }
136 }
137 } else {
138 for s in 1..n_st {
139 fence.push(s * n_layers / n_st);
140 }
141 }
142 fence.push(n_layers);
143 for w in fence.windows(2) {
144 if w[0] >= w[1] {
145 warn_bad_once(&format!(
146 "pp stage fence {fence:?} not strictly increasing over [0, {n_layers}]; \
147 door stays OFF"
148 ));
149 return None;
150 }
151 }
152 Some(fence)
153}
154
155pub fn pp2_split(n_layers: usize) -> Option<usize> {
158 pp_cuts(n_layers).filter(|f| f.len() == 3).map(|f| f[1])
159}
160
161pub fn stage_of(fence: &[usize], il: usize) -> usize {
163 debug_assert!(fence.len() >= 2);
164 match fence[1..fence.len() - 1].binary_search(&il) {
165 Ok(k) => k + 1,
167 Err(k) => k,
168 }
169}
170
171pub fn pp2_streams_off() -> bool {
174 matches!(std::env::var("MEMRA_PP_STREAMS").as_deref(), Ok("0"))
175}
176
177pub fn pp_multi_stream_same_device() -> bool {
188 let stages_open = std::env::var("MEMRA_PP_STAGES")
189 .map(|v| v.parse::<usize>().map(|n| n >= 2).unwrap_or(false))
190 .unwrap_or(false);
191 let devices = std::env::var("MEMRA_PP_DEVICES").ok().filter(|v| !v.is_empty());
192 if (!stages_open && devices.is_none()) || pp2_streams_off() {
193 return false;
194 }
195 match devices {
196 None => true, Some(s) => {
198 let mut v: Vec<&str> = s.split(',').map(|p| p.trim()).collect();
199 let n = v.len();
200 v.sort_unstable();
201 v.dedup();
202 v.len() < n }
204 }
205}
206
207pub fn pp_sharded_cross_device() -> bool {
221 let stages_open = std::env::var("MEMRA_PP_STAGES")
222 .map(|v| v.parse::<usize>().map(|n| n >= 2).unwrap_or(false))
223 .unwrap_or(false);
224 if !stages_open || pp_shard_off() || pp2_streams_off() {
231 return false;
232 }
233 match pp2_devices_env() {
234 None => false, Some(s) => {
236 let mut v: Vec<&str> = s.split(',').map(|p| p.trim()).collect();
237 v.sort_unstable();
238 v.dedup();
239 v.len() >= 2
240 }
241 }
242}
243
244pub fn refuse_unsplit_if_remote(path: &str, alt: &str) -> Result<(), Box<dyn std::error::Error>> {
256 if pp_host_bounce_active() {
257 return Err(format!(
258 "{path}: refused with MEMRA_PP_HOST_BOUNCE=1 on sharded cross-device PP — \
259 this unsplit path peer-reads remote weights, while host bounce covers only \
260 explicit stage-boundary transfers. Use {alt}; the \
261 MEMRA_PP_ALLOW_UNSPLIT_BATCH override is unavailable on a broken-peer host."
262 )
263 .into());
264 }
265 if pp_sharded_cross_device()
266 && std::env::var("MEMRA_PP_ALLOW_UNSPLIT_BATCH").as_deref() != Ok("1")
267 {
268 return Err(format!(
269 "{path}: refused with the ppN door open across 2+ devices — this path has no pp \
270 stage split, so it would walk ALL layers on one stream and peer-read every \
271 remote stage's weights each step (measured 28x slower at B=1, 13.9x at B=8 on \
272 a PRO 6000 pair over PCIe Gen5 x16 P2P; research/pp2-hardening-20260806). \
273 Exactness is unaffected — peer reads return identical bytes and the exactness \
274 gates PASS on this config — which is exactly why it must refuse instead of \
275 being caught by a gate. Fixes, in order: {alt}; or MEMRA_PP_SHARD=0 (all \
276 weights home on the primary — full speed, forfeits the capacity PP-2 exists \
277 for); or close the pp door. MEMRA_PP_ALLOW_UNSPLIT_BATCH=1 overrides for \
278 measurement."
279 )
280 .into());
281 }
282 Ok(())
283}
284
285pub fn batch_pp_on() -> bool {
293 std::env::var("MEMRA_BATCH_PP").as_deref() != Ok("0")
294}
295
296#[derive(Clone, Copy, PartialEq, Eq, Debug)]
314pub enum DualPpMode {
315 Off,
316 Forced,
317 Auto,
318}
319
320pub fn dual_pp_mode_resolve(v: Option<&str>) -> DualPpMode {
323 match v {
324 Some("0") => DualPpMode::Off,
325 Some("1") => DualPpMode::Forced,
326 _ => DualPpMode::Auto,
327 }
328}
329
330pub fn dual_pp_mode() -> DualPpMode {
331 dual_pp_mode_resolve(std::env::var("MEMRA_DUAL_PP").ok().as_deref())
332}
333
334pub fn dual_pp_on() -> bool {
337 dual_pp_mode() != DualPpMode::Off
338}
339
340pub fn dual_pp_route(
346 mode: DualPpMode,
347 batch: usize,
348 stages: usize,
349 double_slot: bool,
350 host_bounce: bool,
351) -> bool {
352 if batch < 2 {
353 return false;
354 }
355 match mode {
356 DualPpMode::Off => false,
357 DualPpMode::Forced => true,
358 DualPpMode::Auto => stages == 2 && double_slot && !host_bounce,
359 }
360}
361
362pub const DUAL_PP_SINGLE_SLOT_REFUSAL: &str =
365 "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";
366pub const DUAL_PP_HOST_BOUNCE_REFUSAL: &str =
367 "decode_step_batch_dual: refused: MEMRA_PP_HOST_BOUNCE=1 is unvalidated for dual-active decode; disable MEMRA_DUAL_PP or use peer transport";
368
369pub fn dual_pp_wave_mid(batch: usize) -> Option<usize> {
372 (batch >= 2).then_some((batch + 1) / 2)
373}
374
375pub fn dual_pp_eligibility(
378 stages: usize,
379 double_slot: bool,
380 host_bounce: bool,
381) -> Result<(), &'static str> {
382 if stages != 2 {
383 return Err("decode_step_batch_dual: refused: dual-active decode requires exactly two PP stages");
384 }
385 if !double_slot {
386 return Err(DUAL_PP_SINGLE_SLOT_REFUSAL);
387 }
388 if host_bounce {
389 return Err(DUAL_PP_HOST_BOUNCE_REFUSAL);
390 }
391 Ok(())
392}
393
394static DUAL_PP_OVERLAPS: AtomicUsize = AtomicUsize::new(0);
397static DUAL_PP_ACTIVE_STAGES: AtomicUsize = AtomicUsize::new(0);
398static DUAL_PP_STAGE_NS: [AtomicU64; 4] = [
399 AtomicU64::new(0), AtomicU64::new(0), AtomicU64::new(0), AtomicU64::new(0),
400];
401static DUAL_PP_STAGE_SAMPLES: [AtomicUsize; 4] = [
402 AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
403];
404static DUAL_PP_TIMING_DROPPED: AtomicUsize = AtomicUsize::new(0);
405static DUAL_PP_SLOT_PAIRS: AtomicUsize = AtomicUsize::new(0);
406static DUAL_PP_SLOT_USES: [AtomicUsize; 2] = [AtomicUsize::new(0), AtomicUsize::new(0)];
407static DUAL_PP_SLOT_COLLISIONS: AtomicUsize = AtomicUsize::new(0);
408
409pub const DUAL_PP_STAGE_NAMES: [&str; 4] = [
410 "wave_a_stage0", "wave_a_stage1", "wave_b_stage0", "wave_b_stage1",
411];
412
413pub fn dual_pp_overlaps() -> usize {
414 DUAL_PP_OVERLAPS.load(Ordering::Relaxed)
415}
416
417pub(crate) fn record_dual_pp_slot_pair(slot_a: usize, slot_b: usize) -> bool {
421 debug_assert!(slot_a < DUAL_PP_SLOT_USES.len());
422 debug_assert!(slot_b < DUAL_PP_SLOT_USES.len());
423 if slot_a == slot_b {
424 DUAL_PP_SLOT_COLLISIONS.fetch_add(1, Ordering::Relaxed);
425 return false;
426 }
427 DUAL_PP_SLOT_USES[slot_a].fetch_add(1, Ordering::Relaxed);
428 DUAL_PP_SLOT_USES[slot_b].fetch_add(1, Ordering::Relaxed);
429 DUAL_PP_SLOT_PAIRS.fetch_add(1, Ordering::Relaxed);
430 true
431}
432
433pub fn dual_pp_slot_snapshot() -> (usize, [usize; 2], usize) {
435 (
436 DUAL_PP_SLOT_PAIRS.load(Ordering::Relaxed),
437 std::array::from_fn(|i| DUAL_PP_SLOT_USES[i].load(Ordering::Relaxed)),
438 DUAL_PP_SLOT_COLLISIONS.load(Ordering::Relaxed),
439 )
440}
441
442pub fn dual_pp_timing_on() -> bool {
446 static ON: OnceLock<bool> = OnceLock::new();
447 *ON.get_or_init(|| std::env::var("MEMRA_DUAL_PP_TIMING").as_deref() == Ok("1"))
448}
449
450pub(crate) fn record_dual_pp_stage_ms(stage: usize, ms: f32) {
451 assert!(stage < DUAL_PP_STAGE_NS.len(), "dual PP timing stage out of range");
452 let ns = (f64::from(ms) * 1_000_000.0).round() as u64;
453 DUAL_PP_STAGE_NS[stage].fetch_add(ns, Ordering::Relaxed);
454 DUAL_PP_STAGE_SAMPLES[stage].fetch_add(1, Ordering::Relaxed);
455}
456
457pub(crate) fn record_dual_pp_timing_drop(
460 context: &str,
461 err: &dyn std::fmt::Display,
462) {
463 let previous = DUAL_PP_TIMING_DROPPED.fetch_add(1, Ordering::Relaxed);
464 if previous == 0 {
465 eprintln!(
466 "[dual-pp] WARN: skipped diagnostic timing sample at {context}: {err}; decode continues"
467 );
468 }
469}
470
471pub(crate) fn record_dual_pp_stage_result<E: std::fmt::Display>(
472 stage: usize,
473 elapsed: Result<f32, E>,
474) {
475 match elapsed {
476 Ok(ms) => record_dual_pp_stage_ms(stage, ms),
477 Err(err) => record_dual_pp_timing_drop(DUAL_PP_STAGE_NAMES[stage], &err),
478 }
479}
480
481pub fn dual_pp_timing_dropped() -> usize {
482 DUAL_PP_TIMING_DROPPED.load(Ordering::Relaxed)
483}
484
485pub fn dual_pp_timing_snapshot() -> ([u64; 4], [usize; 4]) {
487 (
488 std::array::from_fn(|i| DUAL_PP_STAGE_NS[i].load(Ordering::Relaxed)),
489 std::array::from_fn(|i| DUAL_PP_STAGE_SAMPLES[i].load(Ordering::Relaxed)),
490 )
491}
492
493pub(crate) struct DualPpStageGuard;
494
495pub(crate) fn enter_dual_pp_stage() -> DualPpStageGuard {
496 let active = DUAL_PP_ACTIVE_STAGES.fetch_add(1, Ordering::AcqRel);
497 if active > 0 {
498 DUAL_PP_OVERLAPS.fetch_add(1, Ordering::Relaxed);
499 }
500 DualPpStageGuard
501}
502
503impl Drop for DualPpStageGuard {
504 fn drop(&mut self) {
505 let active = DUAL_PP_ACTIVE_STAGES.fetch_sub(1, Ordering::AcqRel);
506 debug_assert!(active > 0, "dual PP active-stage counter underflow");
507 }
508}
509
510pub fn prime_pp_on() -> bool {
520 std::env::var("MEMRA_PRIME_PP").as_deref() != Ok("0")
521}
522
523pub fn prime_pipe_on() -> bool {
528 std::env::var("MEMRA_PRIME_PIPE").as_deref() != Ok("0")
529}
530
531pub static PRIME_SPLIT_CHUNKS: AtomicUsize = AtomicUsize::new(0);
538
539pub fn prime_split_chunks() -> usize {
541 PRIME_SPLIT_CHUNKS.load(Ordering::Relaxed)
542}
543
544pub static PRIME_PIPE_OVERLAPS: AtomicUsize = AtomicUsize::new(0);
549
550pub fn prime_pipe_overlaps() -> usize {
552 PRIME_PIPE_OVERLAPS.load(Ordering::Relaxed)
553}
554
555static PRIME_PIPE_ACTIVE_STAGES: AtomicUsize = AtomicUsize::new(0);
556
557pub(crate) struct PrimePipeStageGuard;
558
559pub(crate) fn enter_prime_pipe_stage() -> PrimePipeStageGuard {
562 let active = PRIME_PIPE_ACTIVE_STAGES.fetch_add(1, Ordering::AcqRel);
563 if active > 0 {
564 PRIME_PIPE_OVERLAPS.fetch_add(1, Ordering::Relaxed);
565 }
566 PrimePipeStageGuard
567}
568
569impl Drop for PrimePipeStageGuard {
570 fn drop(&mut self) {
571 let active = PRIME_PIPE_ACTIVE_STAGES.fetch_sub(1, Ordering::AcqRel);
572 debug_assert!(active > 0, "prime pipeline active-stage counter underflow");
573 }
574}
575
576pub static STEP35_PRIME_BATCHES: AtomicUsize = AtomicUsize::new(0);
580pub static STEP35_PRIME_BATCH_SPLITS: AtomicUsize = AtomicUsize::new(0);
581
582pub fn step35_prime_batches() -> usize {
583 STEP35_PRIME_BATCHES.load(Ordering::Relaxed)
584}
585
586pub fn step35_prime_batch_splits() -> usize {
587 STEP35_PRIME_BATCH_SPLITS.load(Ordering::Relaxed)
588}
589
590pub fn spec_pp_on() -> bool {
598 std::env::var("MEMRA_SPEC_PP").as_deref() != Ok("0")
599}
600
601pub fn pp2_overlap() -> bool {
612 pp2_overlap_resolve(std::env::var("MEMRA_PP_OVERLAP").ok().as_deref(), dual_pp_mode())
613}
614
615pub fn pp2_overlap_resolve(v: Option<&str>, mode: DualPpMode) -> bool {
618 match v {
619 Some("1") => true,
620 Some(_) => false,
621 None => mode == DualPpMode::Auto,
622 }
623}
624
625pub fn pp_host_bounce_on() -> bool {
628 matches!(std::env::var("MEMRA_PP_HOST_BOUNCE").as_deref(), Ok("1"))
629}
630
631pub fn pp_host_bounce_active() -> bool {
634 pp_host_bounce_on() && pp_sharded_cross_device()
635}
636
637pub fn pp_shard_off() -> bool {
641 matches!(std::env::var("MEMRA_PP_SHARD").as_deref(), Ok("0"))
642}
643
644fn pp2_devices_env() -> Option<String> {
647 std::env::var("MEMRA_PP_DEVICES").ok().filter(|v| !v.is_empty())
648}
649
650static WARNED_BAD: AtomicBool = AtomicBool::new(false);
651fn warn_bad_once(msg: &str) {
652 if !WARNED_BAD.swap(true, Ordering::Relaxed) {
653 eprintln!("[pp] {msg}");
654 }
655}
656
657static WARNED_UNWIRED: AtomicBool = AtomicBool::new(false);
658pub fn warn_unwired_once(path: &str) {
661 let open = std::env::var("MEMRA_PP_STAGES")
662 .map(|v| !v.is_empty() && v != "0" && v != "1")
663 .unwrap_or(false);
664 if open && !WARNED_UNWIRED.swap(true, Ordering::Relaxed) {
665 eprintln!(
666 "[pp] MEMRA_PP_STAGES set but `{path}` has no pp arm at this N; running unsplit"
667 );
668 }
669}
670
671pub struct StageRt {
679 pub dev: usize,
680 pub ctx: Arc<CudaContext>,
681 pub stream: Arc<CudaStream>,
682 engine: Option<Engine>,
684}
685
686struct BoundarySlot {
691 buf: Mutex<Option<CudaSlice<f32>>>,
692 ev_tx: CudaEvent,
695 ev_rx: CudaEvent,
699}
700
701struct BoundaryRt {
705 slots: [BoundarySlot; 2],
706 step: AtomicUsize,
707 cross: bool,
709}
710
711#[derive(Clone, Copy, Debug, PartialEq, Eq)]
712enum BoundaryTransport {
713 Local,
714 Peer,
715 HostBounce,
716}
717
718#[derive(Clone, Copy)]
719struct BoundaryPath {
720 boundary: usize,
721 src_stage: usize,
722 dst_stage: usize,
723 transport: BoundaryTransport,
724}
725
726fn boundary_transport(cross: bool, host_bounce: bool) -> BoundaryTransport {
727 match (cross, host_bounce) {
728 (false, _) => BoundaryTransport::Local,
729 (true, false) => BoundaryTransport::Peer,
730 (true, true) => BoundaryTransport::HostBounce,
731 }
732}
733
734const PEER_PROBE_FIXED_BYTES: usize = 16 * 1024;
735const PEER_PROBE_TOKEN_WIDTHS: [usize; 4] = [
736 1,
737 8,
738 16,
739 crate::cache::PRIME_CHUNK_MAX_TOKENS,
740];
741
742pub const PEER_RUNTIME_PROBE_INTERVAL_COPIES: u64 = 8 * 1024;
745pub const PEER_RUNTIME_PROBE_CYCLE_COPIES: u64 =
747 PEER_RUNTIME_PROBE_INTERVAL_COPIES * PEER_PROBE_TOKEN_WIDTHS.len() as u64;
748
749pub const PEER_PROBE_REQUIRED_REFUSAL: &str =
750 "PP bring-up refused: MEMRA_PEER_PROBE=0 cannot authorize native peer transport for a \
751 sharded cross-device placement while MEMRA_PP_HOST_BOUNCE!=1; leave MEMRA_PEER_PROBE \
752 enabled or set MEMRA_PP_HOST_BOUNCE=1";
753
754#[derive(Clone, Copy, Debug, PartialEq, Eq)]
755pub enum PeerProbeStartupPolicy {
756 Allowed,
757 BypassedWithHostBounce,
758}
759
760pub fn peer_probe_startup_policy(
763 probe_on: bool,
764 sharded_cross_device: bool,
765 host_bounce: bool,
766) -> Result<PeerProbeStartupPolicy, &'static str> {
767 match (probe_on, sharded_cross_device, host_bounce) {
768 (false, true, false) => Err(PEER_PROBE_REQUIRED_REFUSAL),
769 (false, true, true) => Ok(PeerProbeStartupPolicy::BypassedWithHostBounce),
770 _ => Ok(PeerProbeStartupPolicy::Allowed),
771 }
772}
773
774static PEER_PROBE_BYPASSED: AtomicU64 = AtomicU64::new(0);
775static PEER_BOUNDARY_COPIES: AtomicU64 = AtomicU64::new(0);
776static PEER_RUNTIME_PROBES: AtomicU64 = AtomicU64::new(0);
777static PEER_RUNTIME_PROBE_FAILURES: AtomicU64 = AtomicU64::new(0);
778static PEER_RUNTIME_LAST_PROBE_COPY: AtomicU64 = AtomicU64::new(0);
779static PEER_RUNTIME_PROBE_FAILED: AtomicBool = AtomicBool::new(false);
780
781#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
782pub struct PeerProbeMetrics {
783 pub bypassed: u64,
784 pub boundary_copies: u64,
785 pub runtime_probes: u64,
786 pub runtime_failures: u64,
787}
788
789pub fn peer_probe_metrics() -> PeerProbeMetrics {
790 PeerProbeMetrics {
791 bypassed: PEER_PROBE_BYPASSED.load(Ordering::Relaxed),
792 boundary_copies: PEER_BOUNDARY_COPIES.load(Ordering::Relaxed),
793 runtime_probes: PEER_RUNTIME_PROBES.load(Ordering::Relaxed),
794 runtime_failures: PEER_RUNTIME_PROBE_FAILURES.load(Ordering::Relaxed),
795 }
796}
797
798fn runtime_peer_probe_due(copies: u64, last_probe_copy: u64) -> bool {
799 copies.saturating_sub(last_probe_copy) >= PEER_RUNTIME_PROBE_INTERVAL_COPIES
800}
801
802fn runtime_peer_probe_width(probe_index: u64) -> (usize, usize) {
805 let width_index = (probe_index % PEER_PROBE_TOKEN_WIDTHS.len() as u64) as usize;
806 (width_index, PEER_PROBE_TOKEN_WIDTHS[width_index])
807}
808
809fn peer_probe_on() -> bool {
810 std::env::var("MEMRA_PEER_PROBE").as_deref() != Ok("0")
811}
812
813#[derive(Clone, Copy, Debug, PartialEq, Eq)]
814enum PeerProbeDecision {
815 Clean,
816 ProceedWithHostBounce { mismatches: usize },
817}
818
819fn peer_probe_mismatch_count(expected: &[u8], readback: &[u8]) -> usize {
820 expected
821 .iter()
822 .zip(readback)
823 .filter(|(a, b)| a != b)
824 .count()
825 + expected.len().abs_diff(readback.len())
826}
827
828fn peer_probe_decision(
829 expected: &[u8],
830 readback: &[u8],
831 host_bounce: bool,
832) -> Result<PeerProbeDecision, String> {
833 let mismatches = peer_probe_mismatch_count(expected, readback);
834 if mismatches == 0 {
835 Ok(PeerProbeDecision::Clean)
836 } else if host_bounce {
837 Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches })
838 } else {
839 Err(format!("{mismatches} mismatched byte(s)"))
840 }
841}
842
843fn peer_probe_pattern(bytes: usize, boundary: usize, src_dev: usize, dst_dev: usize) -> Vec<u8> {
844 let mut state = 0xD1B5_4A32_D192_ED03u64
845 ^ (bytes as u64).rotate_left(7)
846 ^ (boundary as u64).rotate_left(19)
847 ^ (src_dev as u64).rotate_left(31)
848 ^ (dst_dev as u64).rotate_left(43);
849 (0..bytes)
850 .map(|_| {
851 state ^= state << 13;
852 state ^= state >> 7;
853 state ^= state << 17;
854 state as u8
855 })
856 .collect()
857}
858
859fn peer_probe_bytes_to_f32(bytes: &[u8]) -> Vec<f32> {
860 assert_eq!(bytes.len() % std::mem::size_of::<f32>(), 0);
861 bytes
862 .chunks_exact(std::mem::size_of::<f32>())
863 .map(|chunk| f32::from_bits(u32::from_ne_bytes(chunk.try_into().unwrap())))
864 .collect()
865}
866
867fn peer_probe_f32_to_bytes(values: &[f32]) -> Vec<u8> {
868 values
869 .iter()
870 .flat_map(|value| value.to_bits().to_ne_bytes())
871 .collect()
872}
873
874struct PeerProbeBuffer {
878 ctx: Arc<CudaContext>,
879 ptr: cudarc::driver::sys::CUdeviceptr,
880}
881
882impl PeerProbeBuffer {
883 fn new(ctx: &Arc<CudaContext>, bytes: usize) -> Result<Self, Box<dyn std::error::Error>> {
884 ctx.bind_to_thread()?;
885 let ptr = unsafe { cudarc::driver::result::malloc_sync(bytes)? };
886 Ok(Self { ctx: ctx.clone(), ptr })
887 }
888}
889
890impl Drop for PeerProbeBuffer {
891 fn drop(&mut self) {
892 if self.ctx.bind_to_thread().is_ok() {
893 let _ = unsafe { cudarc::driver::result::free_sync(self.ptr) };
894 }
895 }
896}
897
898fn peer_probe_copy(
899 src: &StageRt,
900 dst: &StageRt,
901 expected: &[u8],
902) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
903 let bytes = expected.len();
904 let src_buf = PeerProbeBuffer::new(&src.ctx, bytes)?;
905 unsafe {
906 cudarc::driver::result::memcpy_htod_sync(src_buf.ptr, expected)?;
907 }
908
909 let dst_buf = PeerProbeBuffer::new(&dst.ctx, bytes)?;
910 let poison: Vec<u8> = expected.iter().map(|b| !b).collect();
911 unsafe {
912 cudarc::driver::result::memcpy_htod_sync(dst_buf.ptr, &poison)?;
913 }
914
915 src.ctx.bind_to_thread()?;
916 unsafe {
917 cudarc::driver::result::memcpy_peer_async(
918 dst.ctx.cu_ctx(),
919 dst_buf.ptr,
920 src.ctx.cu_ctx(),
921 src_buf.ptr,
922 bytes,
923 src.stream.cu_stream(),
924 )?;
925 }
926 src.stream.synchronize()?;
927
928 dst.ctx.bind_to_thread()?;
929 let mut readback = vec![0u8; bytes];
930 unsafe {
931 cudarc::driver::result::memcpy_dtoh_sync(&mut readback, dst_buf.ptr)?;
932 }
933 Ok(readback)
934}
935
936fn run_peer_probe_pass(
937 stages: &[StageRt],
938 peer_capable: &[(usize, usize)],
939 host_bounce: bool,
940 label: &str,
941 bytes: usize,
942) -> Result<(), Box<dyn std::error::Error>> {
943 if bytes == 0 {
944 return Err(format!("PP peer byte-integrity probe {label} size is zero").into());
945 }
946 let started = std::time::Instant::now();
947 let mut copies = 0usize;
948 let mut skipped = 0usize;
949 let mut total_mismatches = 0usize;
950
951 for boundary in 0..stages.len() - 1 {
952 if stages[boundary].dev == stages[boundary + 1].dev {
953 continue;
954 }
955 for (src_idx, dst_idx) in [(boundary, boundary + 1), (boundary + 1, boundary)] {
956 let src = &stages[src_idx];
957 let dst = &stages[dst_idx];
958 if !peer_capable.contains(&(src.dev, dst.dev)) {
959 if host_bounce {
960 skipped += 1;
961 eprintln!(
962 "[pp] peer byte-integrity probe SKIP: boundary={boundary} \
963 dev{}->dev{} label={label} bytes={bytes} (peer capability unavailable; \
964 MEMRA_PP_HOST_BOUNCE=1 remains fail-safe)",
965 src.dev, dst.dev,
966 );
967 continue;
968 }
969 return Err(format!(
970 "PP peer byte-integrity probe cannot run boundary={boundary} \
971 dev{}->dev{}: peer access was not enabled",
972 src.dev, dst.dev,
973 )
974 .into());
975 }
976
977 let expected = peer_probe_pattern(bytes, boundary, src.dev, dst.dev);
978 let readback = match peer_probe_copy(src, dst, &expected) {
979 Ok(readback) => readback,
980 Err(err) if host_bounce => {
981 skipped += 1;
982 eprintln!(
983 "[pp] peer byte-integrity probe ERROR: boundary={boundary} \
984 dev{}->dev{} label={label} bytes={bytes}: {err}; \
985 MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path",
986 src.dev, dst.dev,
987 );
988 continue;
989 }
990 Err(err) => {
991 return Err(format!(
992 "PP peer byte-integrity probe FAILED: boundary={boundary} \
993 dev{}->dev{} label={label} bytes={bytes}: {err}; refusing native P2P \
994 (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
995 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)",
996 src.dev, dst.dev,
997 )
998 .into());
999 }
1000 };
1001 copies += 1;
1002 match peer_probe_decision(&expected, &readback, host_bounce) {
1003 Ok(PeerProbeDecision::Clean) => {}
1004 Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches }) => {
1005 total_mismatches += mismatches;
1006 eprintln!(
1007 "[pp] peer byte-integrity probe CORRUPTION: boundary={boundary} \
1008 dev{}->dev{} label={label} bytes={bytes} mismatches={mismatches}; \
1009 MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path",
1010 src.dev, dst.dev,
1011 );
1012 }
1013 Err(mismatch) => {
1014 return Err(format!(
1015 "PP peer byte-integrity probe FAILED: boundary={boundary} \
1016 dev{}->dev{} label={label} bytes={bytes}: {mismatch}; refusing native \
1017 P2P (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
1018 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)",
1019 src.dev, dst.dev,
1020 )
1021 .into());
1022 }
1023 }
1024 }
1025 }
1026
1027 let status = if total_mismatches > 0 {
1028 "BOUNCE"
1029 } else if skipped > 0 && copies > 0 {
1030 "PARTIAL"
1031 } else if skipped > 0 {
1032 "SKIP"
1033 } else {
1034 "PASS"
1035 };
1036 eprintln!(
1037 "[pp] peer byte-integrity probe {}: label={label} bytes={bytes} copies={copies} \
1038 skipped={skipped} mismatches={total_mismatches} elapsed_ms={:.3}",
1039 status,
1040 started.elapsed().as_secs_f64() * 1e3,
1041 );
1042 Ok(())
1043}
1044
1045fn host_bounce_capacity(n_embd: usize) -> Result<(usize, usize), String> {
1046 if n_embd == 0 {
1047 return Err("MEMRA_PP_HOST_BOUNCE needs non-zero model n_embd".into());
1048 }
1049 let elems = n_embd
1050 .checked_mul(crate::cache::PRIME_CHUNK_MAX_TOKENS)
1051 .ok_or_else(|| format!("host-bounce element count overflows for n_embd={n_embd}"))?;
1052 let bytes = elems
1053 .checked_mul(std::mem::size_of::<f32>())
1054 .ok_or_else(|| format!("host-bounce byte count overflows for n_embd={n_embd}"))?;
1055 Ok((elems, bytes))
1056}
1057
1058struct PinnedHostBounce {
1063 ptr: *mut f32,
1064 len: usize,
1065}
1066
1067unsafe impl Send for PinnedHostBounce {}
1068unsafe impl Sync for PinnedHostBounce {}
1069
1070impl PinnedHostBounce {
1071 fn new(len: usize) -> Result<Self, Box<dyn std::error::Error>> {
1072 let bytes = len
1073 .checked_mul(std::mem::size_of::<f32>())
1074 .ok_or("host-bounce pinned allocation size overflow")?;
1075 let ptr = unsafe {
1076 cudarc::driver::result::malloc_host(
1077 bytes,
1078 cudarc::driver::sys::CU_MEMHOSTALLOC_PORTABLE,
1079 )?
1080 } as *mut f32;
1081 if ptr.is_null() {
1082 return Err("cuMemHostAlloc returned a null host-bounce pointer".into());
1083 }
1084 Ok(Self { ptr, len })
1085 }
1086
1087 fn prefix(&self, n: usize) -> &[f32] {
1088 assert!(n <= self.len, "host-bounce source {n} > capacity {}", self.len);
1089 unsafe { std::slice::from_raw_parts(self.ptr, n) }
1090 }
1091
1092 fn prefix_mut(&mut self, n: usize) -> &mut [f32] {
1093 assert!(n <= self.len, "host-bounce destination {n} > capacity {}", self.len);
1094 unsafe { std::slice::from_raw_parts_mut(self.ptr, n) }
1095 }
1096}
1097
1098impl Drop for PinnedHostBounce {
1099 fn drop(&mut self) {
1100 let _ = unsafe { cudarc::driver::result::free_host(self.ptr.cast()) };
1101 }
1102}
1103
1104struct HostBounceRt {
1105 n_embd: usize,
1106 capacity: usize,
1107 slots: Vec<Option<[Mutex<PinnedHostBounce>; 2]>>,
1108}
1109
1110impl HostBounceRt {
1111 fn new(n_embd: usize, boundaries: &[BoundaryRt]) -> Result<Self, Box<dyn std::error::Error>> {
1112 let (capacity, _) = host_bounce_capacity(n_embd)?;
1113 let mut slots = Vec::with_capacity(boundaries.len());
1114 for boundary in boundaries {
1115 slots.push(if boundary.cross {
1116 Some([
1117 Mutex::new(PinnedHostBounce::new(capacity)?),
1118 Mutex::new(PinnedHostBounce::new(capacity)?),
1119 ])
1120 } else {
1121 None
1122 });
1123 }
1124 Ok(Self { n_embd, capacity, slots })
1125 }
1126
1127 fn slot(
1128 &self,
1129 boundary: usize,
1130 slot: usize,
1131 ) -> Result<&Mutex<PinnedHostBounce>, Box<dyn std::error::Error>> {
1132 self.slots
1133 .get(boundary)
1134 .and_then(Option::as_ref)
1135 .and_then(|slots| slots.get(slot))
1136 .ok_or_else(|| format!("host-bounce slot {boundary}:{slot} is not initialized").into())
1137 }
1138}
1139
1140pub struct PpNRt {
1141 stages: Vec<StageRt>,
1142 boundaries: Vec<BoundaryRt>,
1143 cross_any: bool,
1145 host_bounce: bool,
1147 peer_probe: bool,
1149 peer_capable: Vec<(usize, usize)>,
1151 peer_probe_geometry: OnceLock<Result<usize, String>>,
1153 bounce: OnceLock<Result<HostBounceRt, String>>,
1155 readback: Arc<CudaStream>,
1158}
1159
1160pub type Pp2Rt = PpNRt;
1162
1163static RTN: OnceLock<Result<PpNRt, String>> = OnceLock::new();
1164
1165impl PpNRt {
1166 pub fn get(e: &Engine) -> Result<&'static PpNRt, Box<dyn std::error::Error>> {
1170 RTN.get_or_init(|| Self::build(e).map_err(|err| err.to_string()))
1171 .as_ref()
1172 .map_err(|s| -> Box<dyn std::error::Error> { s.clone().into() })
1173 }
1174
1175 fn build(e: &Engine) -> Result<PpNRt, Box<dyn std::error::Error>> {
1176 let primary_dev = e.ctx().ordinal();
1177 let devices: Vec<usize> = match pp2_devices_env() {
1180 Some(s) => {
1181 let parts: Result<Vec<usize>, _> =
1182 s.split(',').map(|p| p.trim().parse::<usize>()).collect();
1183 match parts {
1184 Ok(v) if v.len() >= 2 => v,
1185 _ => {
1186 return Err(format!(
1187 "MEMRA_PP_DEVICES={s} unparseable (want <d0>,..,<dN-1> e.g. 0,1,2,3)"
1188 )
1189 .into())
1190 }
1191 }
1192 }
1193 None => {
1194 let n_st = std::env::var("MEMRA_PP_STAGES")
1195 .ok()
1196 .and_then(|v| v.parse::<usize>().ok())
1197 .filter(|&n| n >= 2)
1198 .unwrap_or(2);
1199 vec![primary_dev; n_st]
1200 }
1201 };
1202 if let Ok(v) = std::env::var("MEMRA_PP_STAGES") {
1203 if let Ok(n) = v.parse::<usize>() {
1204 if n >= 2 && n != devices.len() {
1205 return Err(format!(
1206 "MEMRA_PP_DEVICES lists {} devices but MEMRA_PP_STAGES={n} — \
1207 refusing an ambiguous placement",
1208 devices.len()
1209 )
1210 .into());
1211 }
1212 }
1213 }
1214 let n_st = devices.len();
1215 let cross_any = devices.iter().any(|&d| d != devices[0]);
1216 let host_bounce = pp_host_bounce_on();
1217 let peer_probe = peer_probe_on();
1218 let sharded_cross_device = cross_any && !pp_shard_off();
1219 if host_bounce && cross_any {
1220 if pp_shard_off() {
1221 return Err(
1222 "MEMRA_PP_HOST_BOUNCE=1 refuses MEMRA_PP_SHARD=0: the boundary can bounce, \
1223 but remote stages would still peer-read primary-device weights"
1224 .into(),
1225 );
1226 }
1227 if devices.last().copied() != Some(primary_dev) {
1228 return Err(format!(
1229 "MEMRA_PP_HOST_BOUNCE=1 requires the primary engine on the last/head stage \
1230 (primary dev{primary_dev}, placement {devices:?}); otherwise returned \
1231 logits/hidden state remain peer reads"
1232 )
1233 .into());
1234 }
1235 }
1236 let peer_probe_policy =
1237 peer_probe_startup_policy(peer_probe, sharded_cross_device, host_bounce)?;
1238 if peer_probe_policy == PeerProbeStartupPolicy::BypassedWithHostBounce {
1239 PEER_PROBE_BYPASSED.fetch_add(1, Ordering::Relaxed);
1240 eprintln!(
1241 "[pp] SECURITY RED: peer_probe_bypassed: MEMRA_PEER_PROBE=0 on a sharded \
1242 cross-device placement; MEMRA_PP_HOST_BOUNCE=1 is the only enabled transport"
1243 );
1244 }
1245
1246 let mut used: Vec<usize> = devices.clone();
1250 used.push(primary_dev);
1251 used.sort_unstable();
1252 used.dedup();
1253 let mut peer_capable = Vec::new();
1254 if used.len() > 1 {
1255 let n = cudarc::driver::result::device::get_count()? as usize;
1256 for &d in &used {
1257 if d >= n {
1258 return Err(format!(
1259 "MEMRA_PP_DEVICES={devices:?} but only {n} CUDA device(s) present"
1260 )
1261 .into());
1262 }
1263 }
1264 if !host_bounce || peer_probe {
1265 for &a in &used {
1266 for &b in &used {
1267 if a == b {
1268 continue;
1269 }
1270 let da = cudarc::driver::result::device::get(a as i32)?;
1271 let db = cudarc::driver::result::device::get(b as i32)?;
1272 let mut can: i32 = 0;
1273 let capability = unsafe {
1274 cudarc::driver::sys::cuDeviceCanAccessPeer(&mut can, da, db).result()
1275 };
1276 if let Err(err) = capability {
1277 if host_bounce {
1278 eprintln!(
1279 "[pp] peer byte-integrity probe capability query failed for \
1280 dev{a}->dev{b}: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
1281 );
1282 continue;
1283 }
1284 return Err(err.into());
1285 }
1286 if can == 0 {
1287 if !host_bounce {
1288 return Err(format!(
1289 "device {a} cannot peer-access device {b} \
1290 (cuDeviceCanAccessPeer=0); ppN cross-device needs P2P — \
1291 refusing a silently-staged path"
1292 )
1293 .into());
1294 }
1295 } else {
1296 peer_capable.push((a, b));
1297 }
1298 }
1299 }
1300 }
1301 }
1302
1303 let mk_stage = |dev: usize, s: usize| -> Result<StageRt, Box<dyn std::error::Error>> {
1316 if dev == primary_dev && s == 0 {
1317 let ctx = e.ctx().clone();
1318 let stream = ctx.new_stream()?;
1319 Ok(StageRt { dev, ctx, stream, engine: None })
1320 } else {
1321 let eng = Engine::new(dev)?;
1322 let ctx = eng.ctx().clone();
1323 let stream = ctx.new_stream()?;
1324 Ok(StageRt { dev, ctx, stream, engine: Some(eng) })
1325 }
1326 };
1327 let mut stages = Vec::with_capacity(n_st);
1328 for (s, &d) in devices.iter().enumerate() {
1329 stages.push(mk_stage(d, s)?);
1330 }
1331
1332 if cross_any
1333 && !peer_probe
1334 && peer_probe_policy != PeerProbeStartupPolicy::BypassedWithHostBounce
1335 {
1336 eprintln!(
1337 "[pp] WARNING: MEMRA_PEER_PROBE=0 skips the boot-time peer byte-integrity \
1338 gate; diagnostics escape hatch active"
1339 );
1340 }
1341
1342 if used.len() > 1 {
1343 if !host_bounce {
1344 let ctx_of = |d: usize| -> &Arc<CudaContext> {
1347 if d == primary_dev {
1348 e.ctx()
1349 } else {
1350 &stages.iter().find(|s| s.dev == d).unwrap().ctx
1351 }
1352 };
1353 for &a in &used {
1356 for &b in &used {
1357 if a == b {
1358 continue;
1359 }
1360 ctx_of(a).bind_to_thread()?;
1361 let rc = unsafe {
1362 cudarc::driver::sys::cuCtxEnablePeerAccess(ctx_of(b).cu_ctx(), 0)
1363 };
1364 use cudarc::driver::sys::cudaError_enum as E;
1365 if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
1366 return Err(format!(
1367 "cuCtxEnablePeerAccess(dev{a} -> dev{b}) failed: {rc:?}"
1368 )
1369 .into());
1370 }
1371 }
1372 }
1373 if peer_probe && cross_any {
1377 let probe = run_peer_probe_pass(
1378 &stages,
1379 &peer_capable,
1380 host_bounce,
1381 "fixed-16KiB",
1382 PEER_PROBE_FIXED_BYTES,
1383 );
1384 e.ctx().bind_to_thread()?;
1385 probe?;
1386 }
1387 for &owner in &used {
1396 for &accessor in &used {
1397 if owner == accessor {
1398 continue;
1399 }
1400 let dev = cudarc::driver::result::device::get(owner as i32)?;
1401 let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
1402 unsafe {
1403 cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
1404 }
1405 let desc = cudarc::driver::sys::CUmemAccessDesc {
1406 location: cudarc::driver::sys::CUmemLocation {
1407 type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
1408 id: accessor as i32,
1409 },
1410 flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
1411 };
1412 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
1413 if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
1414 return Err(format!(
1415 "cuMemPoolSetAccess(dev{owner} pool -> dev{accessor}) failed: {rc:?}"
1416 )
1417 .into());
1418 }
1419 }
1420 }
1421 for (owner, accessor) in [(stages[0].dev, stages[1].dev), (stages[1].dev, stages[0].dev)] {
1430 let dev = cudarc::driver::result::device::get(owner as i32)?;
1431 let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
1432 unsafe {
1433 cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
1434 }
1435 let desc = cudarc::driver::sys::CUmemAccessDesc {
1436 location: cudarc::driver::sys::CUmemLocation {
1437 type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
1438 id: accessor as i32,
1439 },
1440 flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
1441 };
1442 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
1443 if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
1444 return Err(format!(
1445 "cuMemPoolSetAccess(dev{owner} pool -> dev{accessor}) failed: {rc:?}"
1446 )
1447 .into());
1448 }
1449 }
1450 e.ctx().bind_to_thread()?;
1452 eprintln!(
1453 "[pp] cross-device transport: {} (cudaMemcpyPeerAsync per cross boundary; \
1454 peer + default-pool access granted all pairs over {used:?}; weight home: {})",
1455 devices
1456 .iter()
1457 .enumerate()
1458 .map(|(s, d)| format!("stage{s}=dev{d}"))
1459 .collect::<Vec<_>>()
1460 .join(" "),
1461 if pp_shard_off() {
1462 format!("dev{primary_dev} (MEMRA_PP_SHARD=0 bring-up placement)")
1463 } else {
1464 "per-stage (sharded loader)".to_string()
1465 }
1466 );
1467 } else {
1468 e.ctx().bind_to_thread()?;
1469 eprintln!(
1470 "[pp] cross-device transport: {} (HOST-STAGED pinned D2H -> H2D per cross \
1471 boundary; MEMRA_PP_HOST_BOUNCE=1; peer-pool grants bypassed; \
1472 diagnostic peer access is removed before host-staged serving; \
1473 weight home: per-stage (sharded loader))",
1474 devices
1475 .iter()
1476 .enumerate()
1477 .map(|(s, d)| format!("stage{s}=dev{d}"))
1478 .collect::<Vec<_>>()
1479 .join(" "),
1480 );
1481 }
1482 }
1483
1484 let mk_slot = |tx: &StageRt, rx: &StageRt| -> Result<BoundarySlot, Box<dyn std::error::Error>> {
1485 Ok(BoundarySlot {
1486 buf: Mutex::new(None),
1487 ev_tx: tx.ctx.new_event(None)?,
1488 ev_rx: rx.ctx.new_event(None)?,
1489 })
1490 };
1491 let mut boundaries = Vec::with_capacity(n_st - 1);
1492 for b in 0..n_st - 1 {
1493 let (tx, rx) = (&stages[b], &stages[b + 1]);
1494 boundaries.push(BoundaryRt {
1495 slots: [mk_slot(tx, rx)?, mk_slot(tx, rx)?],
1496 step: AtomicUsize::new(0),
1497 cross: tx.dev != rx.dev,
1498 });
1499 }
1500 let readback = stages[n_st - 1].ctx.new_stream()?;
1501 let rt = PpNRt {
1502 stages,
1503 boundaries,
1504 cross_any,
1505 host_bounce,
1506 peer_probe,
1507 peer_capable,
1508 peer_probe_geometry: OnceLock::new(),
1509 bounce: OnceLock::new(),
1510 readback,
1511 };
1512 if rt.peer_probe && rt.cross_any && rt.host_bounce {
1513 rt.run_host_bounce_legacy_probe(e)?;
1514 }
1515 Ok(rt)
1516 }
1517
1518 pub fn n_stages(&self) -> usize {
1519 self.stages.len()
1520 }
1521
1522 pub fn cross_device(&self) -> bool {
1524 self.cross_any
1525 }
1526
1527 fn context_for_dev<'a>(
1528 &'a self,
1529 e: &'a Engine,
1530 dev: usize,
1531 ) -> Result<&'a Arc<CudaContext>, Box<dyn std::error::Error>> {
1532 if dev == e.ctx().ordinal() {
1533 return Ok(e.ctx());
1534 }
1535 self.stages
1536 .iter()
1537 .find(|stage| stage.dev == dev)
1538 .map(|stage| &stage.ctx)
1539 .ok_or_else(|| format!("PP peer probe has no CUDA context for dev{dev}").into())
1540 }
1541
1542 fn enable_probe_peer_access(
1543 &self,
1544 e: &Engine,
1545 pairs: &[(usize, usize)],
1546 ) -> Result<Vec<(usize, usize)>, Box<dyn std::error::Error>> {
1547 let mut enabled = Vec::new();
1548 for &(src_dev, dst_dev) in pairs {
1549 let enable = (|| -> Result<(), Box<dyn std::error::Error>> {
1550 let src_ctx = self.context_for_dev(e, src_dev)?;
1551 let dst_ctx = self.context_for_dev(e, dst_dev)?;
1552 src_ctx.bind_to_thread()?;
1553 let rc = unsafe { cudarc::driver::sys::cuCtxEnablePeerAccess(dst_ctx.cu_ctx(), 0) };
1554 use cudarc::driver::sys::cudaError_enum as E;
1555 if rc == E::CUDA_SUCCESS || rc == E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
1556 Ok(())
1557 } else {
1558 Err(format!("{rc:?}").into())
1559 }
1560 })();
1561 if let Err(err) = enable {
1562 eprintln!(
1563 "[pp] peer byte-integrity probe could not enable \
1564 dev{src_dev}->dev{dst_dev}: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
1565 );
1566 } else {
1567 enabled.push((src_dev, dst_dev));
1568 }
1569 }
1570 Ok(enabled)
1571 }
1572
1573 fn disable_probe_peer_access(
1574 &self,
1575 e: &Engine,
1576 pairs: &[(usize, usize)],
1577 ) -> Result<(), Box<dyn std::error::Error>> {
1578 let mut failures = Vec::new();
1579 for &(src_dev, dst_dev) in pairs {
1580 let disable = (|| -> Result<(), Box<dyn std::error::Error>> {
1581 let src_ctx = self.context_for_dev(e, src_dev)?;
1582 let dst_ctx = self.context_for_dev(e, dst_dev)?;
1583 src_ctx.bind_to_thread()?;
1584 let rc = unsafe { cudarc::driver::sys::cuCtxDisablePeerAccess(dst_ctx.cu_ctx()) };
1585 use cudarc::driver::sys::cudaError_enum as E;
1586 if rc == E::CUDA_SUCCESS || rc == E::CUDA_ERROR_PEER_ACCESS_NOT_ENABLED {
1587 Ok(())
1588 } else {
1589 Err(format!("{rc:?}").into())
1590 }
1591 })();
1592 if let Err(err) = disable {
1593 failures.push(format!("dev{src_dev}->dev{dst_dev}: {err}"));
1594 }
1595 }
1596 e.ctx().bind_to_thread()?;
1597 if failures.is_empty() {
1598 eprintln!(
1599 "[pp] peer byte-integrity probe teardown: disabled {} diagnostic pair(s); \
1600 host-bounce serving has no probe-enabled peer access",
1601 pairs.len(),
1602 );
1603 Ok(())
1604 } else {
1605 Err(format!(
1606 "PP peer probe could not disable diagnostic peer access ({}); \
1607 refusing host-bounce serving",
1608 failures.join(", "),
1609 )
1610 .into())
1611 }
1612 }
1613
1614 fn grant_probe_pool_access(
1615 &self,
1616 e: &Engine,
1617 pairs: &[(usize, usize)],
1618 ) -> Result<Vec<(usize, usize)>, Box<dyn std::error::Error>> {
1619 let mut granted = Vec::new();
1620 for &(src_dev, dst_dev) in pairs {
1621 let grant = (|| -> Result<(), Box<dyn std::error::Error>> {
1622 self.context_for_dev(e, dst_dev)?.bind_to_thread()?;
1623 let dev = cudarc::driver::result::device::get(dst_dev as i32)?;
1624 let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
1625 unsafe {
1626 cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
1627 }
1628 let desc = cudarc::driver::sys::CUmemAccessDesc {
1629 location: cudarc::driver::sys::CUmemLocation {
1630 type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
1631 id: src_dev as i32,
1632 },
1633 flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
1634 };
1635 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
1636 if rc == cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
1637 Ok(())
1638 } else {
1639 Err(format!("{rc:?}").into())
1640 }
1641 })();
1642 if let Err(err) = grant {
1643 eprintln!(
1644 "[pp] production-slot probe could not grant dev{src_dev} access to \
1645 dev{dst_dev}'s default pool: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
1646 );
1647 } else {
1648 granted.push((src_dev, dst_dev));
1649 }
1650 }
1651 Ok(granted)
1652 }
1653
1654 fn revoke_probe_pool_access(
1655 &self,
1656 e: &Engine,
1657 pairs: &[(usize, usize)],
1658 ) -> Result<(), Box<dyn std::error::Error>> {
1659 let mut failures = Vec::new();
1660 for &(src_dev, dst_dev) in pairs {
1661 let revoke = (|| -> Result<(), Box<dyn std::error::Error>> {
1662 self.context_for_dev(e, dst_dev)?.bind_to_thread()?;
1663 let dev = cudarc::driver::result::device::get(dst_dev as i32)?;
1664 let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
1665 unsafe {
1666 cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
1667 }
1668 let desc = cudarc::driver::sys::CUmemAccessDesc {
1669 location: cudarc::driver::sys::CUmemLocation {
1670 type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
1671 id: src_dev as i32,
1672 },
1673 flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_NONE,
1674 };
1675 let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
1676 if rc == cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
1677 Ok(())
1678 } else {
1679 Err(format!("{rc:?}").into())
1680 }
1681 })();
1682 if let Err(err) = revoke {
1683 failures.push(format!("dev{src_dev}->dev{dst_dev}: {err}"));
1684 }
1685 }
1686 e.ctx().bind_to_thread()?;
1687 if failures.is_empty() {
1688 Ok(())
1689 } else {
1690 Err(format!(
1691 "PP peer probe could not revoke diagnostic pool access ({}); \
1692 refusing host-bounce serving",
1693 failures.join(", "),
1694 )
1695 .into())
1696 }
1697 }
1698
1699 fn run_host_bounce_legacy_probe(
1700 &self,
1701 e: &Engine,
1702 ) -> Result<(), Box<dyn std::error::Error>> {
1703 let enabled = self.enable_probe_peer_access(e, &self.peer_capable)?;
1704 let probe = run_peer_probe_pass(
1705 &self.stages,
1706 &enabled,
1707 true,
1708 "fixed-16KiB-legacy-preflight",
1709 PEER_PROBE_FIXED_BYTES,
1710 );
1711 let disable = self.disable_probe_peer_access(e, &enabled);
1712 disable?;
1713 probe
1714 }
1715
1716 fn new_peer_probe_boundary(
1717 &self,
1718 src_stage: usize,
1719 dst_stage: usize,
1720 ) -> Result<BoundaryRt, Box<dyn std::error::Error>> {
1721 let tx = &self.stages[src_stage];
1722 let rx = &self.stages[dst_stage];
1723 let mk_slot = || -> Result<BoundarySlot, Box<dyn std::error::Error>> {
1724 Ok(BoundarySlot {
1725 buf: Mutex::new(None),
1726 ev_tx: tx.ctx.new_event(None)?,
1727 ev_rx: rx.ctx.new_event(None)?,
1728 })
1729 };
1730 Ok(BoundaryRt {
1731 slots: [mk_slot()?, mk_slot()?],
1732 step: AtomicUsize::new(0),
1733 cross: tx.dev != rx.dev,
1734 })
1735 }
1736
1737 fn production_probe_readback(
1738 &self,
1739 path: BoundaryPath,
1740 boundary: &BoundaryRt,
1741 expected: &[u8],
1742 n: usize,
1743 slot_idx: usize,
1744 ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
1745 debug_assert_eq!(expected.len(), n * std::mem::size_of::<f32>());
1746 let host = peer_probe_bytes_to_f32(expected);
1747 let poison_bytes: Vec<u8> = expected.iter().map(|byte| !byte).collect();
1748 let poison = peer_probe_bytes_to_f32(&poison_bytes);
1749 let src = &self.stages[path.src_stage];
1750 let dst = &self.stages[path.dst_stage];
1751
1752 dst.ctx.bind_to_thread()?;
1755 let poison_buf = dst.stream.clone_htod(&poison)?;
1756 dst.stream.synchronize()?;
1757 let replaced = boundary.slots[slot_idx].buf.lock().unwrap().replace(poison_buf);
1758 drop(replaced);
1759 dst.stream.synchronize()?;
1760
1761 src.ctx.bind_to_thread()?;
1762 let x = src.stream.clone_htod(&host)?;
1763 self.tx_slot_path(path, boundary, &x, n, slot_idx)?;
1764
1765 dst.ctx.bind_to_thread()?;
1766 let work = self.rx_slot_path(path, boundary, slot_idx, n)?;
1767 let back = dst.stream.clone_dtoh(&work)?;
1768 dst.stream.synchronize()?;
1769 Ok(peer_probe_f32_to_bytes(&back))
1770 }
1771
1772 fn clear_peer_probe_boundary(
1773 &self,
1774 boundary: &BoundaryRt,
1775 src_stage: usize,
1776 dst_stage: usize,
1777 ) -> Result<(), Box<dyn std::error::Error>> {
1778 self.stages[dst_stage].ctx.bind_to_thread()?;
1779 for slot in &boundary.slots {
1780 let buffer = slot.buf.lock().unwrap().take();
1781 drop(buffer);
1782 }
1783 self.stages[src_stage].stream.synchronize()?;
1784 self.stages[dst_stage].stream.synchronize()?;
1785 Ok(())
1786 }
1787
1788 fn run_production_peer_probe(
1789 &self,
1790 enabled_pairs: &[(usize, usize)],
1791 host_bounce: bool,
1792 n_embd: usize,
1793 ) -> Result<(), Box<dyn std::error::Error>> {
1794 let started = std::time::Instant::now();
1795 let mut copies = 0usize;
1796 let mut skipped = 0usize;
1797 let mut total_mismatches = 0usize;
1798 let mut largest_clean_payload = 0usize;
1799
1800 for boundary_idx in 0..self.stages.len() - 1 {
1801 if self.stages[boundary_idx].dev == self.stages[boundary_idx + 1].dev {
1802 continue;
1803 }
1804 for (src_stage, dst_stage) in [
1805 (boundary_idx, boundary_idx + 1),
1806 (boundary_idx + 1, boundary_idx),
1807 ] {
1808 let src_dev = self.stages[src_stage].dev;
1809 let dst_dev = self.stages[dst_stage].dev;
1810 if !enabled_pairs.contains(&(src_dev, dst_dev)) {
1811 if host_bounce {
1812 skipped += PEER_PROBE_TOKEN_WIDTHS.len();
1813 eprintln!(
1814 "[pp] production-slot peer probe SKIP: boundary={boundary_idx} \
1815 dev{src_dev}->dev{dst_dev} widths_tokens={:?} \
1816 (peer or pool access unavailable; MEMRA_PP_HOST_BOUNCE=1 remains \
1817 fail-safe)",
1818 PEER_PROBE_TOKEN_WIDTHS,
1819 );
1820 continue;
1821 }
1822 return Err(format!(
1823 "PP production-slot peer probe cannot run boundary={boundary_idx} \
1824 dev{src_dev}->dev{dst_dev}: peer/pool access is not enabled"
1825 )
1826 .into());
1827 }
1828
1829 let probe_boundary = self.new_peer_probe_boundary(src_stage, dst_stage)?;
1830 let path = BoundaryPath {
1831 boundary: boundary_idx,
1832 src_stage,
1833 dst_stage,
1834 transport: BoundaryTransport::Peer,
1835 };
1836 let mut direction_copies = 0usize;
1837 let mut direction_skipped = 0usize;
1838 let mut direction_mismatches = 0usize;
1839 let mut direction_largest_clean = 0usize;
1840 let mut failure = None;
1841
1842 for (width_idx, tokens) in PEER_PROBE_TOKEN_WIDTHS.into_iter().enumerate() {
1843 let n = n_embd.checked_mul(tokens).ok_or_else(|| {
1844 format!(
1845 "PP production-slot probe element count overflows for \
1846 n_embd={n_embd} tokens={tokens}"
1847 )
1848 })?;
1849 let bytes = n.checked_mul(std::mem::size_of::<f32>()).ok_or_else(|| {
1850 format!(
1851 "PP production-slot probe byte count overflows for \
1852 n_embd={n_embd} tokens={tokens}"
1853 )
1854 })?;
1855 let expected = peer_probe_pattern(
1856 bytes,
1857 boundary_idx,
1858 src_dev,
1859 dst_dev,
1860 );
1861 let readback = match self.production_probe_readback(
1862 path,
1863 &probe_boundary,
1864 &expected,
1865 n,
1866 width_idx % 2,
1867 ) {
1868 Ok(readback) => readback,
1869 Err(err) if host_bounce => {
1870 skipped += 1;
1871 direction_skipped += 1;
1872 eprintln!(
1873 "[pp] production-slot peer probe ERROR: \
1874 boundary={boundary_idx} dev{src_dev}->dev{dst_dev} \
1875 tokens={tokens} bytes={bytes}: {err}; \
1876 MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path"
1877 );
1878 continue;
1879 }
1880 Err(err) => {
1881 failure = Some(format!(
1882 "PP production-slot peer probe FAILED: \
1883 boundary={boundary_idx} dev{src_dev}->dev{dst_dev} \
1884 tokens={tokens} bytes={bytes}: {err}; refusing native P2P \
1885 (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
1886 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer \
1887 transport)"
1888 ));
1889 break;
1890 }
1891 };
1892 copies += 1;
1893 direction_copies += 1;
1894 let mismatches = peer_probe_mismatch_count(&expected, &readback);
1895 if mismatches == 0 {
1896 largest_clean_payload = largest_clean_payload.max(bytes);
1897 direction_largest_clean = direction_largest_clean.max(bytes);
1898 } else if host_bounce {
1899 total_mismatches += mismatches;
1900 direction_mismatches += mismatches;
1901 eprintln!(
1902 "[pp] production-slot peer probe CORRUPTION: \
1903 boundary={boundary_idx} dev{src_dev}->dev{dst_dev} tokens={tokens} \
1904 bytes={bytes} mismatches={mismatches}; MEMRA_PP_HOST_BOUNCE=1, \
1905 proceeding on the host-staged path"
1906 );
1907 } else {
1908 failure = Some(format!(
1909 "PP production-slot peer probe FAILED: boundary={boundary_idx} \
1910 dev{src_dev}->dev{dst_dev} tokens={tokens} bytes={bytes}: \
1911 {mismatches} mismatched byte(s); refusing native P2P \
1912 (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
1913 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)"
1914 ));
1915 break;
1916 }
1917 }
1918
1919 self.clear_peer_probe_boundary(&probe_boundary, src_stage, dst_stage)?;
1920 if let Some(err) = failure {
1921 return Err(err.into());
1922 }
1923 eprintln!(
1924 "[pp] production-slot peer probe direction: boundary={boundary_idx} \
1925 dev{src_dev}->dev{dst_dev} copies={direction_copies} \
1926 skipped={direction_skipped} mismatches={direction_mismatches} \
1927 largest_clean_payload_bytes={direction_largest_clean}"
1928 );
1929 }
1930 }
1931
1932 let status = if total_mismatches > 0 {
1933 "BOUNCE"
1934 } else if skipped > 0 && copies > 0 {
1935 "PARTIAL"
1936 } else if skipped > 0 {
1937 "SKIP"
1938 } else {
1939 "PASS"
1940 };
1941 eprintln!(
1942 "[pp] production-slot peer probe {status}: widths_tokens={:?} copies={copies} \
1943 skipped={skipped} mismatches={total_mismatches} \
1944 largest_clean_payload_bytes={largest_clean_payload} elapsed_ms={:.3}",
1945 PEER_PROBE_TOKEN_WIDTHS,
1946 started.elapsed().as_secs_f64() * 1e3,
1947 );
1948 Ok(())
1949 }
1950
1951 fn run_host_bounce_production_probe(
1952 &self,
1953 e: &Engine,
1954 n_embd: usize,
1955 ) -> Result<(), Box<dyn std::error::Error>> {
1956 let enabled = self.enable_probe_peer_access(e, &self.peer_capable)?;
1957 let granted = self.grant_probe_pool_access(e, &enabled)?;
1958 let probe = self.run_production_peer_probe(&granted, true, n_embd);
1959 let revoke = self.revoke_probe_pool_access(e, &granted);
1965 let disable = self.disable_probe_peer_access(e, &enabled);
1966 probe?;
1967 revoke?;
1968 disable?;
1969 Ok(())
1970 }
1971
1972 fn init_peer_probe_geometry(
1973 &self,
1974 e: &Engine,
1975 n_embd: usize,
1976 ) -> Result<(), Box<dyn std::error::Error>> {
1977 if !self.peer_probe || !self.cross_any {
1978 return Ok(());
1979 }
1980 let bytes = n_embd
1981 .checked_mul(std::mem::size_of::<f32>())
1982 .ok_or_else(|| format!("PP boundary-slot byte count overflows for n_embd={n_embd}"))?;
1983 let result = self.peer_probe_geometry.get_or_init(|| {
1984 let probe = if self.host_bounce {
1985 self.run_host_bounce_production_probe(e, n_embd)
1986 } else {
1987 self.run_production_peer_probe(&self.peer_capable, false, n_embd)
1988 };
1989 let restore = e.ctx().bind_to_thread();
1990 match (probe, restore) {
1991 (Ok(()), Ok(())) => Ok(bytes),
1992 (Err(err), _) => Err(err.to_string()),
1993 (_, Err(err)) => Err(err.to_string()),
1994 }
1995 });
1996 let probed = result
1997 .as_ref()
1998 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
1999 if *probed != bytes {
2000 return Err(format!(
2001 "peer probe initialized for boundary-slot bytes={probed} but model requests \
2002 bytes={bytes}; one PP runtime supports one model geometry per process"
2003 )
2004 .into());
2005 }
2006 Ok(())
2007 }
2008
2009 pub fn init_boundary_transport(
2015 &self,
2016 e: &Engine,
2017 n_embd: usize,
2018 ) -> Result<(), Box<dyn std::error::Error>> {
2019 if PEER_RUNTIME_PROBE_FAILED.load(Ordering::Acquire) {
2020 return Err(
2021 "PP runtime peer byte-integrity probe previously failed; refusing native P2P \
2022 reuse in this process (restart with MEMRA_PP_HOST_BOUNCE=1)"
2023 .into(),
2024 );
2025 }
2026 self.init_peer_probe_geometry(e, n_embd)?;
2027 if !self.host_bounce || !self.cross_any {
2028 return Ok(());
2029 }
2030 e.ctx().bind_to_thread()?;
2031 let result = self.bounce.get_or_init(|| {
2032 HostBounceRt::new(n_embd, &self.boundaries)
2033 .map(|rt| {
2034 let bytes = rt.capacity * std::mem::size_of::<f32>();
2035 eprintln!(
2036 "[pp] host-bounce staging ready: n_embd={n_embd} max_tokens={} \
2037 slot_bytes={bytes} slots_per_cross_boundary=2",
2038 crate::cache::PRIME_CHUNK_MAX_TOKENS,
2039 );
2040 rt
2041 })
2042 .map_err(|err| err.to_string())
2043 });
2044 let bounce = result
2045 .as_ref()
2046 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
2047 if bounce.n_embd != n_embd {
2048 return Err(format!(
2049 "host-bounce runtime initialized for n_embd={} but model requests n_embd={n_embd}; \
2050 one PP runtime supports one model geometry per process",
2051 bounce.n_embd,
2052 )
2053 .into());
2054 }
2055 Ok(())
2056 }
2057
2058 fn service_runtime_peer_probe(
2062 &self,
2063 e: &Engine,
2064 ) -> Result<bool, Box<dyn std::error::Error>> {
2065 if !self.peer_probe || !self.cross_any || self.host_bounce {
2066 return Ok(false);
2067 }
2068 if PEER_RUNTIME_PROBE_FAILED.load(Ordering::Acquire) {
2069 return Err(
2070 "PP runtime peer byte-integrity probe previously failed; native P2P is latched off"
2071 .into(),
2072 );
2073 }
2074 let row_bytes = match self.peer_probe_geometry.get() {
2075 Some(Ok(bytes)) => *bytes,
2076 _ => return Ok(false),
2077 };
2078
2079 let copies = PEER_BOUNDARY_COPIES.load(Ordering::Relaxed);
2080 loop {
2081 let last = PEER_RUNTIME_LAST_PROBE_COPY.load(Ordering::Relaxed);
2082 if !runtime_peer_probe_due(copies, last) {
2083 return Ok(false);
2084 }
2085 if PEER_RUNTIME_LAST_PROBE_COPY
2086 .compare_exchange(last, copies, Ordering::AcqRel, Ordering::Relaxed)
2087 .is_ok()
2088 {
2089 break;
2090 }
2091 }
2092
2093 let probe_index = PEER_RUNTIME_PROBES.fetch_add(1, Ordering::Relaxed);
2094 let (width_index, tokens) = runtime_peer_probe_width(probe_index);
2095 let probe_bytes = row_bytes.checked_mul(tokens);
2096 let label = format!("runtime-idle-{tokens}tok");
2097 let probe = match probe_bytes {
2098 Some(bytes) => run_peer_probe_pass(
2099 &self.stages,
2100 &self.peer_capable,
2101 false,
2102 &label,
2103 bytes,
2104 ),
2105 None => Err(format!(
2106 "PP runtime peer probe byte count overflows for row_bytes={row_bytes} \
2107 tokens={tokens}"
2108 )
2109 .into()),
2110 };
2111 let restore = e.ctx().bind_to_thread();
2112 let verdict = match (probe, restore) {
2113 (Ok(()), Ok(())) => Ok(()),
2114 (Err(err), _) => Err(err.to_string()),
2115 (_, Err(err)) => Err(err.to_string()),
2116 };
2117 if let Err(err) = verdict {
2118 PEER_RUNTIME_PROBE_FAILURES.fetch_add(1, Ordering::Relaxed);
2119 PEER_RUNTIME_PROBE_FAILED.store(true, Ordering::Release);
2120 let message = format!(
2121 "PP runtime peer byte-integrity re-probe FAILED after \
2122 boundary_copies={copies} rung={}/{} tokens={tokens}: {err}; refusing further \
2123 native P2P (restart with MEMRA_PP_HOST_BOUNCE=1; MEMRA_PEER_PROBE=0 cannot \
2124 bypass this failure)",
2125 width_index + 1,
2126 PEER_PROBE_TOKEN_WIDTHS.len(),
2127 );
2128 eprintln!("[pp] SECURITY RED: {message}");
2129 return Err(message.into());
2130 }
2131 eprintln!(
2132 "[pp] runtime peer byte-integrity re-probe PASS: \
2133 boundary_copies={copies} interval_copies={PEER_RUNTIME_PROBE_INTERVAL_COPIES} \
2134 rung={}/{} tokens={tokens} bytes={} probe_index={probe_index}",
2135 width_index + 1,
2136 PEER_PROBE_TOKEN_WIDTHS.len(),
2137 probe_bytes.unwrap(),
2138 );
2139 Ok(true)
2140 }
2141
2142 fn bounce_rt(&self) -> Result<&HostBounceRt, Box<dyn std::error::Error>> {
2143 self.bounce
2144 .get()
2145 .ok_or_else(|| -> Box<dyn std::error::Error> {
2146 "MEMRA_PP_HOST_BOUNCE=1 staging was not initialized from model geometry".into()
2147 })?
2148 .as_ref()
2149 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })
2150 }
2151
2152 pub fn engine<'a>(&'a self, s: usize, primary: &'a Engine) -> &'a Engine {
2155 self.stages[s].engine.as_ref().unwrap_or(primary)
2156 }
2157
2158 pub fn bind_stage(&self, s: usize) -> Result<(), Box<dyn std::error::Error>> {
2160 self.stages[s].ctx.bind_to_thread()?;
2161 Ok(())
2162 }
2163
2164 pub fn enter(&self, s: usize) -> memra_runtime::StreamOverride {
2167 memra_runtime::push_stream_override(self.stages[s].stream.clone())
2168 }
2169
2170 pub fn prepare_overlap_slots(&self, b: usize, n: usize)
2176 -> Result<(), Box<dyn std::error::Error>> {
2177 let bd = &self.boundaries[b];
2178 let s_rx = &self.stages[b + 1].stream;
2179 let mut grew = false;
2180 for sl in &bd.slots {
2181 let mut guard = sl.buf.lock().unwrap();
2182 if guard.as_ref().map(|bf| bf.len() < n).unwrap_or(true) {
2183 *guard = Some(s_rx.alloc_zeros::<f32>(n)?);
2184 grew = true;
2185 }
2186 }
2187 if grew {
2188 s_rx.synchronize()?;
2189 }
2190 Ok(())
2191 }
2192
2193 pub fn tx(&self, b: usize, x: &CudaSlice<f32>, n: usize)
2207 -> Result<usize, Box<dyn std::error::Error>> {
2208 assert_eq!(x.len(), n, "pp tx: residual length mismatch");
2209 let bd = &self.boundaries[b];
2210 let slot_idx = if pp2_overlap() {
2211 bd.step.fetch_add(1, Ordering::Relaxed) % 2
2212 } else {
2213 0
2214 };
2215 self.tx_slot(b, x, n, slot_idx)
2216 }
2217
2218 pub fn tx_pipelined(&self, b: usize, x: &CudaSlice<f32>, n: usize)
2222 -> Result<usize, Box<dyn std::error::Error>> {
2223 assert_eq!(x.len(), n, "pp tx: residual length mismatch");
2224 let slot_idx = self.boundaries[b].step.fetch_add(1, Ordering::Relaxed) % 2;
2225 self.tx_slot(b, x, n, slot_idx)
2226 }
2227
2228 fn tx_slot(&self, b: usize, x: &CudaSlice<f32>, n: usize, slot_idx: usize)
2229 -> Result<usize, Box<dyn std::error::Error>> {
2230 let bd = &self.boundaries[b];
2231 let path = BoundaryPath {
2232 boundary: b,
2233 src_stage: b,
2234 dst_stage: b + 1,
2235 transport: boundary_transport(bd.cross, self.host_bounce),
2236 };
2237 let copied_slot = self.tx_slot_path(path, bd, x, n, slot_idx)?;
2238 if path.transport == BoundaryTransport::Peer {
2239 PEER_BOUNDARY_COPIES.fetch_add(1, Ordering::Relaxed);
2240 }
2241 Ok(copied_slot)
2242 }
2243
2244 fn tx_slot_path(
2245 &self,
2246 path: BoundaryPath,
2247 bd: &BoundaryRt,
2248 x: &CudaSlice<f32>,
2249 n: usize,
2250 slot_idx: usize,
2251 ) -> Result<usize, Box<dyn std::error::Error>> {
2252 debug_assert!(slot_idx < 2);
2253 let sl = &bd.slots[slot_idx];
2254 let s_tx = &self.stages[path.src_stage].stream;
2255 s_tx.wait(&sl.ev_rx)?;
2256 let mut guard = sl.buf.lock().unwrap();
2257 if guard.as_ref().map(|bf| bf.len() < n).unwrap_or(true) {
2258 let s_rx = &self.stages[path.dst_stage].stream;
2260 *guard = Some(s_rx.alloc_zeros::<f32>(n)?);
2261 s_rx.synchronize()?;
2271 }
2272 let buf = guard.as_mut().unwrap();
2273 match path.transport {
2274 BoundaryTransport::Local => s_tx.memcpy_dtod(x, buf)?,
2275 BoundaryTransport::HostBounce => {
2276 debug_assert_eq!(path.src_stage, path.boundary);
2277 debug_assert_eq!(path.dst_stage, path.boundary + 1);
2278 let bounce = self.bounce_rt()?;
2279 if n > bounce.capacity {
2280 return Err(format!(
2281 "pp host-bounce payload {n} exceeds geometry-sized capacity {} \
2282 (n_embd={}, max prime tokens={})",
2283 bounce.capacity,
2284 bounce.n_embd,
2285 crate::cache::PRIME_CHUNK_MAX_TOKENS,
2286 )
2287 .into());
2288 }
2289 let mut host = bounce.slot(path.boundary, slot_idx)?.lock().unwrap();
2290 s_tx.memcpy_dtoh(x, host.prefix_mut(n))?;
2294 }
2295 BoundaryTransport::Peer => {
2296 use cudarc::driver::{DevicePtr, DevicePtrMut};
2299 let (sp, _g0) = x.device_ptr(s_tx);
2300 let (dp, _g1) = buf.device_ptr_mut(s_tx);
2301 self.stages[path.src_stage].ctx.bind_to_thread()?;
2302 unsafe {
2303 cudarc::driver::result::memcpy_peer_async(
2304 self.stages[path.dst_stage].ctx.cu_ctx(),
2305 dp,
2306 self.stages[path.src_stage].ctx.cu_ctx(),
2307 sp,
2308 n * std::mem::size_of::<f32>(),
2309 s_tx.cu_stream(),
2310 )?;
2311 }
2312 }
2313 }
2314 sl.ev_tx.record(s_tx)?;
2315 Ok(slot_idx)
2316 }
2317
2318 pub fn rx(&self, b: usize, slot_idx: usize, n: usize)
2323 -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
2324 let bd = &self.boundaries[b];
2325 let path = BoundaryPath {
2326 boundary: b,
2327 src_stage: b,
2328 dst_stage: b + 1,
2329 transport: boundary_transport(bd.cross, self.host_bounce),
2330 };
2331 self.rx_slot_path(path, bd, slot_idx, n)
2332 }
2333
2334 fn rx_slot_path(
2335 &self,
2336 path: BoundaryPath,
2337 bd: &BoundaryRt,
2338 slot_idx: usize,
2339 n: usize,
2340 ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
2341 let sl = &bd.slots[slot_idx];
2342 let s_rx = &self.stages[path.dst_stage].stream;
2343 s_rx.wait(&sl.ev_tx)?;
2344 let mut guard = sl.buf.lock().unwrap();
2345 let buf = guard.as_mut().expect("pp rx before tx");
2346 assert!(buf.len() >= n, "pp rx: slot holds {} < requested {n}", buf.len());
2347 if path.transport == BoundaryTransport::HostBounce {
2348 debug_assert_eq!(path.src_stage, path.boundary);
2349 debug_assert_eq!(path.dst_stage, path.boundary + 1);
2350 let bounce = self.bounce_rt()?;
2351 let host = bounce.slot(path.boundary, slot_idx)?.lock().unwrap();
2352 let mut dst = buf.slice_mut(0..n);
2353 s_rx.memcpy_htod(host.prefix(n), &mut dst)?;
2356 }
2357 let mut work = unsafe { s_rx.alloc::<f32>(n)? };
2360 s_rx.memcpy_dtod(&buf.slice(0..n), &mut work)?;
2364 sl.ev_rx.record(s_rx)?;
2365 Ok(work)
2366 }
2367
2368 pub fn publish_to(&self, s: usize, dst: &Arc<CudaStream>)
2395 -> Result<(), Box<dyn std::error::Error>> {
2396 let st = &self.stages[s];
2397 if Arc::ptr_eq(&st.stream, dst) {
2400 return Ok(());
2401 }
2402 let ev = st.ctx.new_event(None)?;
2403 ev.record(&st.stream)?;
2404 dst.wait(&ev)?;
2405 Ok(())
2406 }
2407
2408 pub fn fence_stages_behind(&self, src: &Arc<CudaStream>)
2430 -> Result<(), Box<dyn std::error::Error>> {
2431 let ev = src.context().new_event(None)?;
2432 ev.record(src)?;
2433 for st in &self.stages {
2434 if Arc::ptr_eq(&st.stream, src) {
2435 continue;
2436 }
2437 st.stream.wait(&ev)?;
2438 }
2439 Ok(())
2440 }
2441
2442 pub fn record_done(&self) -> Result<CudaEvent, Box<dyn std::error::Error>> {
2445 let last = &self.stages[self.stages.len() - 1];
2446 let ev = last.ctx.new_event(None)?;
2447 ev.record(&last.stream)?;
2448 Ok(ev)
2449 }
2450
2451 pub fn readback_stream(&self) -> &Arc<CudaStream> {
2453 &self.readback
2454 }
2455}
2456
2457pub fn service_runtime_peer_probe(e: &Engine) -> Result<bool, Box<dyn std::error::Error>> {
2460 let Some(rt) = RTN.get() else { return Ok(false) };
2461 let rt = rt
2462 .as_ref()
2463 .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
2464 rt.service_runtime_peer_probe(e)
2465}
2466
2467pub struct PendingLogits {
2472 logits: CudaSlice<f32>,
2473 ev: CudaEvent,
2474 rb: Arc<CudaStream>,
2475}
2476
2477impl PendingLogits {
2478 pub fn new(logits: CudaSlice<f32>, ev: CudaEvent, rb: Arc<CudaStream>) -> Self {
2479 PendingLogits { logits, ev, rb }
2480 }
2481
2482 pub fn wait(self) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2486 self.rb.wait(&self.ev)?;
2487 let host = self.rb.clone_dtoh(&self.logits)?;
2488 self.rb.synchronize()?;
2489 Ok(host)
2492 }
2493}
2494
2495pub fn init_model_transport(
2498 e: &Engine,
2499 cfg: &memra_gguf::config::ModelConfig,
2500 n_trunk: usize,
2501) -> Result<(), Box<dyn std::error::Error>> {
2502 if pp2_streams_off() || pp2_devices_env().is_none() || pp_cuts(n_trunk).is_none() {
2503 return Ok(());
2504 }
2505 PpNRt::get(e)?.init_boundary_transport(e, cfg.n_embd as usize)
2506}
2507
2508pub fn new_cache(e: &Engine, cfg: &memra_gguf::config::ModelConfig, max_ctx: usize)
2515 -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
2516 let n_trunk = (cfg.n_layer - cfg.nextn_predict_layers) as usize;
2517 if let Some(fence) = pp_cuts(n_trunk) {
2518 if pp2_devices_env().is_some() && !pp2_streams_off() {
2519 let rt = PpNRt::get(e)?;
2520 rt.init_boundary_transport(e, cfg.n_embd as usize)?;
2521 let n_st = fence.len() - 1;
2522 assert_eq!(
2523 rt.n_stages(), n_st,
2524 "PpNRt stage count {} != fence stages {n_st}", rt.n_stages()
2525 );
2526 rt.fence_stages_behind(&e.stream())?;
2535 let devs: Vec<&dyn memra_kv::KvDev> =
2536 (0..n_st).map(|s| rt.engine(s, e) as &dyn memra_kv::KvDev).collect();
2537 let cache = crate::cache::Cache::new_ppn(&devs, &fence, cfg, max_ctx)?;
2538 sync_stages_after_load(e, n_trunk)?;
2539 return Ok(cache);
2540 }
2541 if !pp2_streams_off() {
2542 let cache = crate::cache::Cache::new(e, cfg, max_ctx)?;
2550 sync_stages_after_load(e, n_trunk)?;
2551 return Ok(cache);
2552 }
2553 }
2554 crate::cache::Cache::new(e, cfg, max_ctx)
2555}
2556
2557pub fn sync_stages_after_load(e: &Engine, n_trunk: usize)
2566 -> Result<(), Box<dyn std::error::Error>> {
2567 if pp2_streams_off() || pp_cuts(n_trunk).is_none() {
2568 return Ok(());
2569 }
2570 let rt = PpNRt::get(e)?;
2571 for s in 0..rt.n_stages() {
2572 rt.stages[s].ctx.bind_to_thread()?;
2573 unsafe {
2574 cudarc::driver::sys::cuCtxSynchronize().result()?;
2575 }
2576 }
2577 e.ctx().bind_to_thread()?;
2578 unsafe {
2579 cudarc::driver::sys::cuCtxSynchronize().result()?;
2580 }
2581 Ok(())
2582}
2583
2584pub fn layer_engine<'a>(e: &'a Engine, n_trunk: usize, il: usize)
2590 -> Result<&'a Engine, Box<dyn std::error::Error>> {
2591 if pp_shard_off() || pp2_devices_env().is_none() || pp2_streams_off() {
2592 return Ok(e);
2593 }
2594 let Some(fence) = pp_cuts(n_trunk) else { return Ok(e) };
2595 let rt = PpNRt::get(e)?;
2596 let s = stage_of(&fence, il.min(n_trunk - 1));
2597 Ok(rt.engine(s, e))
2598}
2599
2600pub fn restore_cache_checkpoint(
2611 e: &Engine,
2612 cfg: &memra_gguf::config::ModelConfig,
2613 source: Option<&crate::cache::Cache>,
2614 target: &mut crate::cache::Cache,
2615 snap: &crate::cache::CacheSnapshot,
2616) -> Result<(), Box<dyn std::error::Error>> {
2617 let n = target.kv.len();
2618 if target.recur.len() != n
2619 || snap.kv_len.len() != n
2620 || snap.conv.len() != n
2621 || snap.ssm.len() != n
2622 || source.is_some_and(|s| s.kv.len() != n || s.recur.len() != n)
2623 {
2624 return Err("checkpoint cache layer-count mismatch".into());
2625 }
2626 if snap.pos > target.max_ctx {
2627 return Err(format!(
2628 "checkpoint pos {} exceeds target capacity {}",
2629 snap.pos, target.max_ctx,
2630 )
2631 .into());
2632 }
2633
2634 let n_trunk = (cfg.n_layer - cfg.nextn_predict_layers) as usize;
2635 for il in 0..n {
2636 let owner = layer_engine(e, n_trunk, il)?;
2637 let src_kv = source.map(|s| &s.kv[il]);
2638 match (src_kv, target.kv[il].as_mut(), snap.kv_len[il]) {
2639 (Some(Some(src)), Some(dst), Some(len)) => {
2640 if len > src.len || len > target.max_ctx {
2641 return Err(format!(
2642 "checkpoint layer {il} len {len} exceeds source {} or target {}",
2643 src.len, target.max_ctx,
2644 )
2645 .into());
2646 }
2647 if src.kv_dim_k != dst.kv_dim_k
2648 || src.kv_dim_v != dst.kv_dim_v
2649 || src.k_tok_bytes != dst.k_tok_bytes
2650 || src.v_tok_bytes != dst.v_tok_bytes
2651 {
2652 return Err(format!("checkpoint KV layout mismatch at layer {il}").into());
2653 }
2654 let kb = len * src.k_tok_bytes;
2655 let vb = len * src.v_tok_bytes;
2656 if kb > 0 {
2657 owner.copy_u8_into(&mut dst.k, 0, &src.k, kb)?;
2658 }
2659 if vb > 0 {
2660 owner.copy_u8_into(&mut dst.v, 0, &src.v, vb)?;
2661 }
2662 dst.len = len;
2663 owner.set_i32_one(&mut dst.len_d, len as i32)?;
2664 }
2665 (None, Some(dst), Some(len)) => {
2666 if len > dst.len || len > target.max_ctx {
2667 return Err(format!(
2668 "checkpoint layer {il} len {len} exceeds live {} or target {}",
2669 dst.len, target.max_ctx,
2670 )
2671 .into());
2672 }
2673 dst.len = len;
2674 owner.set_i32_one(&mut dst.len_d, len as i32)?;
2675 }
2676 (Some(None), None, None) | (None, None, None) => {}
2677 _ => return Err(format!("checkpoint KV kind mismatch at layer {il}").into()),
2678 }
2679
2680 match (
2681 target.recur[il].as_mut(),
2682 &snap.conv[il],
2683 &snap.ssm[il],
2684 ) {
2685 (Some(dst), Some(conv), Some(ssm)) => {
2686 if conv.len() != dst.conv_state.len() || ssm.len() != dst.ssm_state.len() {
2687 return Err(
2688 format!("checkpoint recurrent layout mismatch at layer {il}").into(),
2689 );
2690 }
2691 owner.copy_into(&mut dst.conv_state, 0, conv, conv.len())?;
2692 owner.copy_into(&mut dst.ssm_state, 0, ssm, ssm.len())?;
2693 }
2694 (None, None, None) => {}
2695 _ => {
2696 return Err(
2697 format!("checkpoint recurrent kind mismatch at layer {il}").into(),
2698 );
2699 }
2700 }
2701 }
2702 target.pos = snap.pos;
2703
2704 sync_stages_after_load(e, n_trunk)?;
2707 if source.is_some() {
2708 e.stream().synchronize()?;
2711 }
2712 Ok(())
2713}
2714
2715#[cfg(test)]
2716mod host_bounce_tests {
2717 use super::{
2718 boundary_transport, dual_pp_eligibility, dual_pp_timing_dropped,
2719 dual_pp_timing_snapshot, dual_pp_wave_mid, host_bounce_capacity,
2720 peer_probe_bytes_to_f32, peer_probe_decision, peer_probe_f32_to_bytes,
2721 peer_probe_mismatch_count, peer_probe_pattern, peer_probe_startup_policy,
2722 record_dual_pp_stage_result, runtime_peer_probe_due, runtime_peer_probe_width,
2723 BoundaryTransport, PeerProbeDecision, PeerProbeStartupPolicy,
2724 DUAL_PP_HOST_BOUNCE_REFUSAL, DUAL_PP_SINGLE_SLOT_REFUSAL, PEER_PROBE_FIXED_BYTES,
2725 PEER_PROBE_REQUIRED_REFUSAL, PEER_PROBE_TOKEN_WIDTHS,
2726 PEER_RUNTIME_PROBE_CYCLE_COPIES, PEER_RUNTIME_PROBE_INTERVAL_COPIES,
2727 };
2728
2729 #[test]
2733 fn flip_default_is_dual_auto_with_explicit_off_and_forced_seams() {
2734 use super::{dual_pp_mode_resolve, DualPpMode};
2735 assert_eq!(dual_pp_mode_resolve(None), DualPpMode::Auto);
2736 assert_eq!(dual_pp_mode_resolve(Some("0")), DualPpMode::Off);
2737 assert_eq!(dual_pp_mode_resolve(Some("1")), DualPpMode::Forced);
2738 assert_eq!(dual_pp_mode_resolve(Some("2")), DualPpMode::Auto);
2740 assert_eq!(dual_pp_mode_resolve(Some("")), DualPpMode::Auto);
2741 }
2742
2743 #[test]
2744 fn flip_overlap_follows_mode_and_one_flag_restores_preflip_serial() {
2745 use super::{pp2_overlap_resolve, DualPpMode};
2746 assert!(pp2_overlap_resolve(None, DualPpMode::Auto));
2748 assert!(!pp2_overlap_resolve(None, DualPpMode::Off));
2750 assert!(!pp2_overlap_resolve(None, DualPpMode::Forced));
2752 for mode in [DualPpMode::Off, DualPpMode::Forced, DualPpMode::Auto] {
2754 assert!(pp2_overlap_resolve(Some("1"), mode));
2755 assert!(!pp2_overlap_resolve(Some("0"), mode));
2756 }
2757 }
2758
2759 #[test]
2760 fn flip_auto_routes_only_the_regated_regime_and_degrades_serially_elsewhere() {
2761 use super::{dual_pp_route, DualPpMode};
2762 assert!(dual_pp_route(DualPpMode::Auto, 2, 2, true, false));
2764 assert!(dual_pp_route(DualPpMode::Auto, 17, 2, true, false));
2765 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));
2772 assert!(!dual_pp_route(DualPpMode::Forced, 1, 2, true, false));
2773 assert!(!dual_pp_route(DualPpMode::Off, 8, 2, true, false));
2775 }
2776
2777 #[test]
2778 fn dual_pp_split_is_honest_at_one_and_ceil_first_afterward() {
2779 assert_eq!(dual_pp_wave_mid(1), None);
2780 assert_eq!(dual_pp_wave_mid(2), Some(1));
2781 assert_eq!(dual_pp_wave_mid(3), Some(2));
2782 assert_eq!(dual_pp_wave_mid(8), Some(4));
2783 assert_eq!(dual_pp_wave_mid(16), Some(8));
2784 assert_eq!(dual_pp_wave_mid(31), Some(16));
2785 assert_eq!(dual_pp_wave_mid(32), Some(16));
2786 }
2787
2788 #[test]
2789 fn dual_pp_refuses_single_slot_and_non_pp2_shapes() {
2790 assert_eq!(dual_pp_eligibility(2, false, false), Err(DUAL_PP_SINGLE_SLOT_REFUSAL));
2791 assert!(dual_pp_eligibility(2, true, false).is_ok());
2792 assert!(dual_pp_eligibility(3, true, false).is_err());
2793 }
2794
2795 #[test]
2796 fn dual_pp_refuses_unvalidated_host_bounce_transport() {
2797 assert_eq!(
2798 dual_pp_eligibility(2, true, true),
2799 Err(DUAL_PP_HOST_BOUNCE_REFUSAL),
2800 );
2801 }
2802
2803 #[test]
2804 fn dual_pp_timing_error_is_counted_without_recording_a_sample() {
2805 let dropped_before = dual_pp_timing_dropped();
2806 let (_, samples_before) = dual_pp_timing_snapshot();
2807 record_dual_pp_stage_result(0, Err::<f32, _>("CUDA_ERROR_NOT_READY"));
2808 let (_, samples_after) = dual_pp_timing_snapshot();
2809 assert_eq!(samples_after[0], samples_before[0]);
2810 assert!(dual_pp_timing_dropped() >= dropped_before + 1);
2811 }
2812
2813 #[test]
2814 fn corrupted_peer_readback_fails_closed_unless_host_bounce_is_selected() {
2815 assert_eq!(
2816 PEER_PROBE_TOKEN_WIDTHS,
2817 [1, 8, 16, crate::cache::PRIME_CHUNK_MAX_TOKENS],
2818 );
2819 let largest_payload_bytes = PEER_PROBE_TOKEN_WIDTHS[3]
2820 * 4096
2821 * std::mem::size_of::<f32>();
2822 assert_eq!(largest_payload_bytes, 64 * 1024 * 1024);
2823 assert!(largest_payload_bytes >= 1024 * 1024);
2824 let expected = peer_probe_pattern(PEER_PROBE_FIXED_BYTES, 2, 0, 1);
2825 assert_eq!(
2826 peer_probe_f32_to_bytes(&peer_probe_bytes_to_f32(&expected)),
2827 expected,
2828 );
2829 let mut corrupted = expected.clone();
2830 for offset in [0, 8_191, PEER_PROBE_FIXED_BYTES - 1] {
2831 corrupted[offset] ^= 0x5a;
2832 }
2833
2834 assert_eq!(peer_probe_mismatch_count(&expected, &corrupted), 3);
2835 assert_eq!(
2836 peer_probe_decision(&expected, &corrupted, false),
2837 Err("3 mismatched byte(s)".to_string()),
2838 );
2839 assert_eq!(
2840 peer_probe_decision(&expected, &corrupted, true),
2841 Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches: 3 }),
2842 );
2843 }
2844
2845 #[test]
2846 fn probe_off_refusal_matrix_is_fail_closed_only_for_sharded_native_peer() {
2847 for probe_on in [false, true] {
2848 for sharded in [false, true] {
2849 for host_bounce in [false, true] {
2850 let got = peer_probe_startup_policy(probe_on, sharded, host_bounce);
2851 let expected = match (probe_on, sharded, host_bounce) {
2852 (false, true, false) => Err(PEER_PROBE_REQUIRED_REFUSAL),
2853 (false, true, true) => {
2854 Ok(PeerProbeStartupPolicy::BypassedWithHostBounce)
2855 }
2856 _ => Ok(PeerProbeStartupPolicy::Allowed),
2857 };
2858 assert_eq!(
2859 got, expected,
2860 "probe_on={probe_on} sharded={sharded} host_bounce={host_bounce}",
2861 );
2862 }
2863 }
2864 }
2865 assert!(PEER_PROBE_REQUIRED_REFUSAL.contains("MEMRA_PEER_PROBE=0"));
2866 assert!(PEER_PROBE_REQUIRED_REFUSAL.contains("MEMRA_PP_HOST_BOUNCE!=1"));
2867 }
2868
2869 #[test]
2870 fn runtime_reprobe_becomes_due_only_at_each_copy_interval() {
2871 let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
2872 assert_eq!(PEER_RUNTIME_PROBE_CYCLE_COPIES, 4 * every);
2873 assert!(!runtime_peer_probe_due(every - 1, 0));
2874 assert!(runtime_peer_probe_due(every, 0));
2875 assert!(!runtime_peer_probe_due(2 * every - 1, every));
2876 assert!(runtime_peer_probe_due(2 * every, every));
2877 assert!(!runtime_peer_probe_due(every - 1, every));
2878 }
2879
2880 #[test]
2881 fn runtime_reprobe_rotates_every_boot_width_in_deterministic_order() {
2882 let cycle_len = PEER_PROBE_TOKEN_WIDTHS.len();
2883 let got: Vec<(usize, usize)> = (0..2 * cycle_len)
2884 .map(|probe_index| runtime_peer_probe_width(probe_index as u64))
2885 .collect();
2886 let expected: Vec<(usize, usize)> = PEER_PROBE_TOKEN_WIDTHS
2887 .into_iter()
2888 .enumerate()
2889 .chain(PEER_PROBE_TOKEN_WIDTHS.into_iter().enumerate())
2890 .collect();
2891
2892 assert_eq!(got, expected);
2893 assert_eq!(got[cycle_len - 1].1, crate::cache::PRIME_CHUNK_MAX_TOKENS);
2894 assert_eq!(got[2 * cycle_len - 1].1, crate::cache::PRIME_CHUNK_MAX_TOKENS);
2895 }
2896
2897 #[test]
2898 fn transport_selection_keeps_peer_default_and_bounces_only_cross_device() {
2899 assert_eq!(boundary_transport(false, false), BoundaryTransport::Local);
2900 assert_eq!(boundary_transport(false, true), BoundaryTransport::Local);
2901 assert_eq!(boundary_transport(true, false), BoundaryTransport::Peer);
2902 assert_eq!(
2903 boundary_transport(true, true),
2904 BoundaryTransport::HostBounce
2905 );
2906 }
2907
2908 #[test]
2909 fn step37_geometry_sizes_each_slot_from_the_prime_cap() {
2910 let (elems, bytes) = host_bounce_capacity(4096).expect("valid Step-3.7 geometry");
2911 assert_eq!(elems, 4096 * crate::cache::PRIME_CHUNK_MAX_TOKENS);
2912 assert_eq!(bytes, 64 * 1024 * 1024);
2913 }
2914
2915 #[test]
2916 fn host_bounce_capacity_rejects_invalid_or_overflowing_geometry() {
2917 assert!(host_bounce_capacity(0).is_err());
2918 assert!(host_bounce_capacity(usize::MAX).is_err());
2919 }
2920}