use std::net::SocketAddr;
use std::thread;
use std::time::{Duration, Instant};
use subetha_cxc::fusion::ImmediateUpConservativeDown;
use subetha_cxc::link_sensor::{LinkSensor, LinkSnapshot, StubSensor};
use subetha_cxc::udp_bridge::{SensOMaticReceiver, SensOMaticSender};
struct StressSensor(f32);
impl LinkSensor for StressSensor {
fn sample(&mut self) -> LinkSnapshot {
LinkSnapshot { drop_rate: Some(self.0), ..LinkSnapshot::default() }
}
fn backend(&self) -> &'static str {
"stress-stub"
}
}
fn gen_items(n: usize, item_len: usize, seed: u64) -> Vec<Vec<u8>> {
let mut out = Vec::with_capacity(n);
for i in 0..n {
let mut v = vec![0u8; item_len];
let s = (i as u64 ^ seed).wrapping_mul(0x9E37_79B9_7F4A_7C15);
for (j, b) in v.iter_mut().enumerate() {
*b = (s.wrapping_add(j as u64).wrapping_mul(2_654_435_761) >> 24) as u8;
}
v[0..8].copy_from_slice(&(i as u64).to_le_bytes());
out.push(v);
}
out
}
struct RunResult {
byte_exact: bool,
fully_acked: bool,
saw_passthrough: bool,
rearmed: bool,
passthrough_blocks: u64,
fec_blocks: u64,
goodput_mbit: f64,
parity_hist: [u64; 9],
}
impl RunResult {
fn typical_parity(&self) -> usize {
let (mut best_r, mut best_c) = (0usize, 0u64);
for (r, &c) in self.parity_hist.iter().enumerate() {
if c > best_c {
best_c = c;
best_r = r;
}
}
best_r
}
}
fn run_stream(
port: u16,
n: usize,
item_len: usize,
clean_hold: u32,
sensor: Box<dyn LinkSensor + Send>,
loss_schedule: impl Fn(f64) -> u32 + Send + 'static,
) -> RunResult {
let addr: SocketAddr = format!("127.0.0.1:{port}").parse().unwrap();
let items = gen_items(n, item_len, port as u64);
let expected = items.clone();
let total = items.len();
let rx = thread::spawn(move || -> bool {
let mut recv = SensOMaticReceiver::bind(addr).expect("bind recv");
let (mut got, mut ok) = (0usize, true);
let start = Instant::now();
let mut last_pct = u32::MAX;
while got < total {
if start.elapsed() > Duration::from_secs(120) {
return false;
}
let pct = loss_schedule(got as f64 / total as f64);
if pct != last_pct {
recv.set_debug_loss(pct);
last_pct = pct;
}
for item in recv.poll().unwrap_or_default() {
if item != expected[got] {
ok = false;
}
got += 1;
}
}
for _ in 0..100 {
recv.nudge_feedback().ok();
thread::sleep(Duration::from_millis(2));
}
ok && got == total
});
thread::sleep(Duration::from_millis(250));
let mut send = SensOMaticSender::bind("127.0.0.1:0", addr, 8, 2, item_len)
.expect("bind send")
.with_sensor(sensor)
.with_fusion(Box::new(ImmediateUpConservativeDown::with_holds(2, clean_hold)));
let mut saw_passthrough = false;
let mut rearmed = false;
let mut parity_hist = [0u64; 9];
let t0 = Instant::now();
for it in &items {
while send.flow_blocked() {
send.pump_feedback().ok();
if send.flow_blocked() {
thread::sleep(Duration::from_micros(50));
}
}
send.send_item(it).expect("send_item");
let p = send.control().parity_r() as usize;
parity_hist[p.min(8)] += 1;
if p == 0 {
saw_passthrough = true;
} else if saw_passthrough {
rearmed = true;
}
}
send.flush().expect("flush");
let fully_acked = send
.drain_until_acked(Duration::from_secs(120))
.expect("drain");
let secs = t0.elapsed().as_secs_f64();
let (passthrough_blocks, fec_blocks) = send.coding_counts();
let byte_exact = rx.join().expect("rx join");
RunResult {
byte_exact,
fully_acked,
saw_passthrough,
rearmed,
passthrough_blocks,
fec_blocks,
goodput_mbit: (n * item_len) as f64 * 8.0 / secs / 1e6,
parity_hist,
}
}
fn main() {
let item_len = 256usize;
let mut failures = 0;
let clean = run_stream(25810, 40_000, item_len, 5, Box::new(StubSensor), |_| 0);
println!(
"clean (PT) : byte_exact={} acked={} passthrough_blocks={} fec_blocks={} goodput={:.0} Mbit/s",
clean.byte_exact, clean.fully_acked, clean.passthrough_blocks, clean.fec_blocks, clean.goodput_mbit
);
if !(clean.byte_exact && clean.fully_acked && clean.passthrough_blocks > 0) {
eprintln!(" FAIL: clean link did not drop to Passthrough byte-exact");
failures += 1;
}
let lossy = run_stream(25820, 20_000, item_len, 5, Box::new(StubSensor), |_| 12);
println!(
"12% loss : byte_exact={} acked={} passthrough_blocks={} fec_blocks={}",
lossy.byte_exact, lossy.fully_acked, lossy.passthrough_blocks, lossy.fec_blocks
);
if !(lossy.byte_exact && lossy.fully_acked && lossy.fec_blocks > 0) {
eprintln!(" FAIL: lossy link not byte-exact or never armed parity");
failures += 1;
}
let trans = run_stream(25830, 40_000, item_len, 5, Box::new(StubSensor), |frac| {
if frac < 0.5 { 0 } else { 12 }
});
println!(
"transition : byte_exact={} acked={} passthrough_blocks={} fec_blocks={} saw_passthrough={} rearmed={}",
trans.byte_exact, trans.fully_acked, trans.passthrough_blocks, trans.fec_blocks, trans.saw_passthrough, trans.rearmed
);
if !(trans.byte_exact
&& trans.fully_acked
&& trans.passthrough_blocks > 0
&& trans.fec_blocks > 0
&& trans.rearmed)
{
eprintln!(" FAIL: transition did not Passthrough->re-arm byte-exact");
failures += 1;
}
let stressed = run_stream(25840, 40_000, item_len, 5, Box::new(StressSensor(0.5)), |_| 0);
println!(
"stress (FEC): byte_exact={} acked={} passthrough_blocks={} fec_blocks={} goodput={:.0} Mbit/s",
stressed.byte_exact, stressed.fully_acked, stressed.passthrough_blocks, stressed.fec_blocks, stressed.goodput_mbit
);
if !(stressed.byte_exact
&& stressed.fully_acked
&& stressed.fec_blocks > 0
&& !stressed.saw_passthrough)
{
eprintln!(" FAIL: link stress did not keep FEC armed at zero loss");
failures += 1;
}
if clean.goodput_mbit > 0.0 && stressed.goodput_mbit > 0.0 {
println!(
"\nclean-link goodput: Passthrough {:.0} vs forced-FEC {:.0} Mbit/s = {:.2}x (FEC off packs more payload)",
clean.goodput_mbit, stressed.goodput_mbit, clean.goodput_mbit / stressed.goodput_mbit
);
}
println!("\nadaptive parity size (typical parity_r the controller settles on):");
let mut prev_r = 0usize;
let mut size_ok = true;
for (i, loss) in [0u32, 5, 15, 30].into_iter().enumerate() {
let port = 25850 + i as u16;
let r = run_stream(port, 30_000, item_len, 5, Box::new(StubSensor), move |_| loss);
let tr = r.typical_parity();
println!(
" {loss:2}% loss -> parity_r={tr} byte_exact={} (hist {:?})",
r.byte_exact, &r.parity_hist[..6]
);
if !r.byte_exact {
size_ok = false;
}
if loss > 0 && tr < prev_r {
size_ok = false; }
prev_r = tr;
}
if !size_ok {
eprintln!(" FAIL: parity did not right-size monotonically with loss");
failures += 1;
}
if failures == 0 {
println!(
"\nALL E2E PASS: FEC switches off on a clean link, re-arms instantly on loss, \
ARQ is the floor, every item byte-exact."
);
std::process::exit(0);
} else {
eprintln!("\n{failures} run(s) FAILED");
std::process::exit(1);
}
}