Skip to main content

data_codec_bench/
data_codec_bench.rs

1//! Release-mode comparison of legacy and v2 setup and steady-state encryption.
2//! Run with `cargo run --release -p pb-mapper-protocol --example data_codec_bench`.
3
4use std::{error::Error, hint::black_box, time::Instant};
5
6use pb_mapper_core::codec::{Decryptor, Encryptor};
7use pb_mapper_protocol::{data::DataCodec, secure::HeaderProtocol};
8
9fn measure(v2: bool, size: usize, iterations: usize) -> Result<f64, Box<dyn Error>> {
10    let codec = if v2 {
11        DataCodec::negotiate([42; 32], Some(2), HeaderProtocol::V2)?
12    } else {
13        DataCodec::legacy([42; 32])
14    };
15    if size == 0 {
16        let start = Instant::now();
17        for _ in 0..iterations {
18            black_box(black_box(codec).endpoint_codecs()?);
19        }
20        return Ok(start.elapsed().as_secs_f64() * 1e9 / iterations as f64);
21    }
22    let (_, mut writer) = codec.endpoint_codecs()?;
23    let (mut reader, _) = codec.relay_codecs()?;
24    let mut bytes = vec![42; size + 16];
25    let start = Instant::now();
26    for _ in 0..iterations {
27        let tag = writer
28            .encrypt(black_box(&mut bytes[..size]))
29            .map_err(|_| "encrypt failed")?;
30        bytes[size..].copy_from_slice(tag.as_ref());
31        black_box(
32            reader
33                .decrypt(black_box(&mut bytes))
34                .map_err(|_| "decrypt failed")?,
35        );
36    }
37    let elapsed = start.elapsed().as_secs_f64();
38    assert!(bytes[..size].iter().all(|&byte| byte == 42));
39    Ok(elapsed * 1e9 / iterations as f64)
40}
41
42fn main() -> Result<(), Box<dyn Error>> {
43    for (size, iterations) in [(0, 200_000), (256, 500_000), (16_384, 20_000)] {
44        let mut samples = [Vec::new(), Vec::new()];
45        // Warm both paths, then alternate order to limit clock/thermal bias.
46        for v2 in [false, true] {
47            black_box(measure(v2, size, iterations / 10)?);
48        }
49        for round in 0..9 {
50            for index in [round % 2, 1 - round % 2] {
51                samples[index].push(measure(index == 1, size, iterations)?);
52            }
53        }
54        for sample in &mut samples {
55            sample.sort_by(f64::total_cmp);
56        }
57        let legacy = samples[0][4];
58        let v2 = samples[1][4];
59        println!(
60            "{{\"payload_bytes\":{size},\"iterations\":{iterations},\"samples\":9,\"legacy_median_ns\":{legacy:.2},\"v2_median_ns\":{v2:.2},\"change_percent\":{:.2}}}",
61            (v2 / legacy - 1.0) * 100.0,
62        );
63    }
64    Ok(())
65}