use std::cell::RefCell;
use std::net::SocketAddr;
use std::rc::Rc;
use std::time::{Duration, Instant};
use rand_chacha::ChaCha20Rng;
use rand_chacha::rand_core::SeedableRng;
use slither::packet::ReferenceSuite;
use slither::prelude::*;
const ITERATIONS: usize = 1000;
const WARMUP: usize = 50;
const PAYLOAD: usize = 64;
const ECHO_TIMEOUT: Duration = Duration::from_secs(5);
type Id = SoftwareIdentity<ReferenceSuite, ChaCha20Rng>;
#[derive(Clone, Copy)]
struct SendSpan {
entry: Instant,
exit: Instant,
len: usize,
}
struct TimedWire {
inner: tokio::net::UdpSocket,
sends: Rc<RefCell<Vec<SendSpan>>>,
}
impl Wire for TimedWire {
async fn send_to(&self, buf: &[u8], addr: SocketAddr) -> std::io::Result<usize> {
let entry = Instant::now();
let len = buf.len();
let result = self.inner.send_to(buf, addr).await;
let exit = Instant::now();
self.sends.borrow_mut().push(SendSpan { entry, exit, len });
result
}
async fn recv_from(&self, buf: &mut [u8]) -> std::io::Result<(usize, SocketAddr)> {
self.inner.recv_from(buf).await
}
}
struct Series {
name: &'static str,
samples: Vec<u64>,
}
impl Series {
fn new(name: &'static str, samples: Vec<u64>) -> Self {
Self { name, samples }
}
fn percentile(sorted: &[u64], q: f64) -> u64 {
let rank = (q * sorted.len() as f64).ceil() as usize;
sorted[rank.clamp(1, sorted.len()) - 1]
}
fn print(&self) {
if self.samples.is_empty() {
println!("SERIES {} n=0 (no samples)", self.name);
return;
}
let mut sorted = self.samples.clone();
sorted.sort_unstable();
let us = |ns: u64| ns / 1_000;
let p50 = Self::percentile(&sorted, 0.50);
let p90 = Self::percentile(&sorted, 0.90);
let p99 = Self::percentile(&sorted, 0.99);
let min = sorted[0];
let max = sorted[sorted.len() - 1];
println!(
"SERIES {} n={} p50_us={} p90_us={} p99_us={} min_us={} max_us={} \
p50_ns={} p99_ns={} max_ns={}",
self.name,
sorted.len(),
us(p50),
us(p90),
us(p99),
us(min),
us(max),
p50,
p99,
max,
);
}
}
async fn loopback_pair() -> (
Endpoint<Id>,
Endpoint<Id>,
Connection<ReferenceSuite>,
Connection<ReferenceSuite>,
Rc<RefCell<Vec<SendSpan>>>,
) {
let sock_a = tokio::net::UdpSocket::bind("127.0.0.1:0")
.await
.expect("bind the initiator socket on loopback");
let sock_b = tokio::net::UdpSocket::bind("127.0.0.1:0")
.await
.expect("bind the responder socket on loopback");
let addr_b = sock_b.local_addr().expect("the responder's bound address");
let id_a: Id = SoftwareIdentity::generate(ChaCha20Rng::from_seed([0xA1; 32]))
.expect("a seeded ChaCha20 stream yields a valid P-256 scalar");
let id_b: Id = SoftwareIdentity::generate(ChaCha20Rng::from_seed([0xB2; 32]))
.expect("a seeded ChaCha20 stream yields a valid P-256 scalar");
let pk_b = *Identity::public_static(&id_b);
let sends = Rc::new(RefCell::new(Vec::with_capacity(4 * ITERATIONS)));
let wire_a = TimedWire {
inner: sock_a,
sends: Rc::clone(&sends),
};
let ep_a: Endpoint<Id> = Endpoint::builder()
.identity(id_a)
.wire(wire_a)
.rng_seed([0x11; 32])
.build();
let ep_b: Endpoint<Id> = Endpoint::builder()
.identity(id_b)
.wire(sock_b)
.rng_seed([0x22; 32])
.build();
let dial = async {
ep_a.connect(addr_b, pk_b)
.expect("mint the pending connection")
.await
.expect("the dial completed")
};
let accept = async {
let intro = ep_b.accept().await.expect("an introduction arrived");
let claimed = intro.read_identity().await.expect("read_identity");
let proven = claimed.authenticate().await.expect("authenticate");
proven.accept().await.expect("accept")
};
let (ca, cb) = tokio::join!(dial, accept);
(ep_a, ep_b, ca, cb, sends)
}
async fn round_trip(
conn: &Connection<ReferenceSuite>,
seq: u64,
payload: &mut [u8; PAYLOAD],
) -> (Instant, Instant, Instant) {
payload[..8].copy_from_slice(&seq.to_le_bytes());
let t0 = Instant::now();
conn.send_datagram(payload).expect("queue the datagram");
let t1 = Instant::now();
let echo = tokio::time::timeout(ECHO_TIMEOUT, conn.recv_datagram())
.await
.unwrap_or_else(|_| {
panic!(
"no echo for datagram {seq} within {ECHO_TIMEOUT:?} — \
§11.1 permits the loss, but on loopback it means the run is broken"
)
})
.expect("the connection outlived the probe");
let t2 = Instant::now();
assert_eq!(
&echo[..8],
&seq.to_le_bytes(),
"the echo did not match the request — the ping-pong lost its lockstep",
);
(t0, t1, t2)
}
fn match_sends(spans: &[SendSpan], t1s: &[Instant]) -> (Vec<u64>, Vec<u64>, Vec<usize>) {
let mut dispatch = Vec::with_capacity(t1s.len());
let mut syscall = Vec::with_capacity(t1s.len());
let mut lengths = Vec::with_capacity(t1s.len());
let mut cursor = 0usize;
for &t1 in t1s {
while cursor < spans.len() && spans[cursor].entry < t1 {
cursor += 1;
}
let Some(span) = spans.get(cursor) else { break };
dispatch.push((span.entry - t1).as_nanos() as u64);
syscall.push((span.exit - span.entry).as_nanos() as u64);
lengths.push(span.len);
cursor += 1;
}
(dispatch, syscall, lengths)
}
fn length_histogram(lengths: &[usize]) -> String {
let mut sorted = lengths.to_vec();
sorted.sort_unstable();
let mut out = Vec::new();
for len in sorted {
match out.last_mut() {
Some((seen, count)) if *seen == len => *count += 1,
_ => out.push((len, 1usize)),
}
}
out.iter()
.map(|(len, count)| format!("{len}={count}"))
.collect::<Vec<_>>()
.join(",")
}
fn main() {
println!("audit_udp — round 41 item 3.1, the split-timer loopback probe");
println!(
" iterations={ITERATIONS} warmup={WARMUP} payload={PAYLOAD}B \
topology=one-thread/one-LocalSet/two-real-UDP-sockets"
);
println!();
block_on(async {
let (ep_a, ep_b, ca, cb, sends) = loopback_pair().await;
let echo = tokio::task::spawn_local(async move {
while let Ok(datagram) = cb.recv_datagram().await {
let _ = cb.send_datagram(&datagram);
}
});
let mut payload = [0u8; PAYLOAD];
for seq in 0..WARMUP as u64 {
round_trip(&ca, seq, &mut payload).await;
}
let mut send_call = Vec::with_capacity(ITERATIONS);
let mut reply_wait = Vec::with_capacity(ITERATIONS);
let mut total = Vec::with_capacity(ITERATIONS);
let mut t1s = Vec::with_capacity(ITERATIONS);
sends.borrow_mut().clear();
let wall = Instant::now();
for i in 0..ITERATIONS as u64 {
let (t0, t1, t2) = round_trip(&ca, WARMUP as u64 + i, &mut payload).await;
send_call.push((t1 - t0).as_nanos() as u64);
reply_wait.push((t2 - t1).as_nanos() as u64);
total.push((t2 - t0).as_nanos() as u64);
t1s.push(t1);
}
let elapsed = wall.elapsed();
let spans = sends.borrow().clone();
let (dispatch, syscall, matched_lengths) = match_sends(&spans, &t1s);
let all_lengths = spans.iter().map(|s| s.len).collect::<Vec<_>>();
for series in [
Series::new("send_call", send_call),
Series::new("wire_dispatch", dispatch),
Series::new("wire_syscall", syscall),
Series::new("reply_wait", reply_wait),
Series::new("total", total),
] {
series.print();
}
println!(
"WIRE_SENDS total={} per_round_trip={:.2} all_lengths={}",
spans.len(),
spans.len() as f64 / ITERATIONS as f64,
length_histogram(&all_lengths),
);
println!(
"WIRE_MATCHED n={} lengths={}",
matched_lengths.len(),
length_histogram(&matched_lengths),
);
println!(
"PHASE_C_DONE iterations={ITERATIONS} wall_ms={}",
elapsed.as_millis(),
);
echo.abort();
drop(ca);
drop(ep_a);
drop(ep_b);
});
}