//! M3 real-parallelism stress harness. //! //! Runs `xenia-rs check sylpheed.iso --parallel --halt-on-deadlock` //! many times back-to-back to surface lost-wakeups, lock-order //! inversions, and ABA hazards that a single run wouldn't reliably //! reproduce. Failures dump per-run stdout/stderr to //! `target/parallel-stress-NNN.{stdout,stderr}` for post-mortem. //! //! Two configurations: //! - `parallel_stress_short`: 20 runs at -n 5_000_000. Quick smoke //! check — runs in a few minutes on the current substrate. //! - `parallel_stress_long` (ignored, opt-in): 100 runs at //! -n 50_000_000. The full gate from the master plan; expected //! runtime is hours until the perf gap (Step 05's deferred parking //! fix) closes. //! //! Run with `cargo test --release -p xenia-app --test parallel_stress //! -- --ignored --nocapture` for the full 100x; otherwise the short //! variant runs as part of the normal test suite when explicitly //! invoked: `cargo test --release -p xenia-app --test parallel_stress //! -- --nocapture parallel_stress_short`. use std::process::Command; use std::time::Instant; const ISO_DEFAULT: &str = "/home/fabi/RE Project Sylpheed/Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso"; fn iso_path() -> String { std::env::var("SYLPHEED_ISO").unwrap_or_else(|_| ISO_DEFAULT.to_string()) } fn run_stress(label: &str, runs: u32, max_instr: u64) { let bin = env!("CARGO_BIN_EXE_xenia-rs"); let iso = iso_path(); if !std::path::Path::new(&iso).exists() { eprintln!("{label}: iso not found at {iso}; set SYLPHEED_ISO to override. SKIPPING."); return; } std::fs::create_dir_all("target").ok(); let mut failures: u32 = 0; let mut wall_ms: Vec = Vec::with_capacity(runs as usize); let max_instr_str = max_instr.to_string(); for run in 1..=runs { let t0 = Instant::now(); let out = Command::new(bin) .args([ "exec", &iso, "-n", &max_instr_str, "--parallel", "--halt-on-deadlock", "--quiet", ]) .output() .expect("failed to spawn xenia-rs"); let dt = t0.elapsed().as_millis(); wall_ms.push(dt); let exit_ok = out.status.success(); let vdswap2 = String::from_utf8_lossy(&out.stderr).contains("VdSwap") || String::from_utf8_lossy(&out.stdout).contains("VdSwap"); let _ = vdswap2; // VdSwap=2 not required at -n 5M; tracked for diagnostic only. if !exit_ok { failures += 1; std::fs::write( format!("target/parallel-stress-{label}-{run:03}.stdout"), &out.stdout, ) .ok(); std::fs::write( format!("target/parallel-stress-{label}-{run:03}.stderr"), &out.stderr, ) .ok(); eprintln!( "{label}: run {run}/{runs} FAILED (wall={}ms, exit={:?})", dt, out.status.code() ); } else { eprintln!("{label}: run {run}/{runs} ok (wall={dt}ms)"); } } wall_ms.sort(); let p50 = wall_ms[wall_ms.len() / 2]; let p95_idx = ((wall_ms.len() - 1) * 95) / 100; let p95 = wall_ms[p95_idx]; let max = *wall_ms.last().unwrap(); eprintln!( "{label} summary: runs={runs} ok={} failed={failures} p50={p50}ms p95={p95}ms max={max}ms", runs - failures, ); assert_eq!(failures, 0, "{label}: {failures} of {runs} stress runs failed"); } /// 20 runs at -n 5M. Session-feasible (~10 minutes at the current /// perf level). Surfaces lost-wakeup / lock-order / phaser-timeout /// bugs that a single run wouldn't reproduce. #[test] #[ignore = "stress test; run via `cargo test ... -- --ignored parallel_stress_short`"] fn parallel_stress_short() { run_stress("short", 20, 5_000_000); } /// 100 runs at -n 50M. The full M3 follow-up gate per the master /// plan. Expected runtime is hours until the perf gap closes. #[test] #[ignore = "full stress test; run via `cargo test ... -- --ignored parallel_stress_long`"] fn parallel_stress_long() { run_stress("long", 100, 50_000_000); }