Files
clawsync/crates/clawsync-onion/benches/iblt_bench.rs
osobhandClaude Sonnet 4.6 1c107fe58a Apply rustfmt to entire workspace
Runs cargo fmt --all; all 573 tests still passing, clippy still clean.
No logic changes — formatting only.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-04 20:31:33 -05:00

123 lines
4.8 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Criterion benchmarks for IBLT set reconciliation.
//!
//! Groups:
//! - `iblt_manifest/encode/N` — build + serialise an IBLT sketch
//! - `iblt_manifest/decode/D` — decode a difference sketch with D elements
//! - `iblt_manifest/roundtrip/N/D` — full encode-send-decode cycle
//! - `iblt_manifest/size/N` — report sketch bytes vs flat manifest bytes
//!
//! Run:
//! cargo bench -p clawsync-onion -- iblt_bench
use clawsync_onion::iblt::{DEFAULT_HASH_COUNT, IbltSketch, MIN_CELLS};
use criterion::{BenchmarkId, Criterion, black_box, criterion_group, criterion_main};
// ─────────────────────────────────────────────────────────────────────────────
const SEED: u64 = 0x0123_4567_89AB_CDEF;
fn keys(n: usize) -> Vec<u64> {
(0..n as u64).collect()
}
fn diff_sketches(n: usize, d: usize) -> (IbltSketch, Vec<u8>) {
// A has keys 0..n, B has keys 0..(n-d)
let a_keys = keys(n);
let b_keys = keys(n.saturating_sub(d));
// Use generous m to ensure reliable decode
let m = ((d * 4).max(MIN_CELLS)).max(IbltSketch::recommended_cells(n));
let mut a = IbltSketch::new(m, DEFAULT_HASH_COUNT, SEED);
let mut b = IbltSketch::new(m, DEFAULT_HASH_COUNT, SEED);
for &k in &a_keys {
a.insert(k);
}
for &k in &b_keys {
b.insert(k);
}
let b_bytes = b.to_bytes();
a.subtract(&b);
(a, b_bytes)
}
// ─────────────────────────────────────────────────────────────────────────────
fn bench_iblt(c: &mut Criterion) {
let ns = [10usize, 100, 1_000, 10_000];
let ds = [0usize, 1, 10, 50];
// ── Encode (build + serialise) ────────────────────────────────────────────
let mut group = c.benchmark_group("iblt_manifest/encode");
for &n in &ns {
let ks = keys(n);
group.bench_with_input(BenchmarkId::from_parameter(n), &ks, |b, k| {
b.iter(|| {
let s = IbltSketch::from_keys(black_box(k), SEED);
black_box(s.to_bytes())
});
});
}
group.finish();
// ── Decode diff sketch ────────────────────────────────────────────────────
let mut group = c.benchmark_group("iblt_manifest/decode");
for &d in &ds {
let n = 1_000usize;
let (diff_sketch, _) = diff_sketches(n, d);
group.bench_with_input(BenchmarkId::from_parameter(d), &diff_sketch, |b, s| {
b.iter(|| black_box(s.decode()));
});
}
group.finish();
// ── Full roundtrip (encode A, encode B, subtract, decode) ─────────────────
let mut group = c.benchmark_group("iblt_manifest/roundtrip");
for &n in &[100usize, 1_000, 10_000] {
for &d in &[0usize, 10] {
let a_keys = keys(n);
let b_keys = keys(n.saturating_sub(d));
group.bench_with_input(
BenchmarkId::new(format!("n{n}"), format!("d{d}")),
&(a_keys, b_keys),
|b, (ak, bk)| {
b.iter(|| {
let m = (d * 4).max(MIN_CELLS).max(IbltSketch::recommended_cells(n));
let mut a = IbltSketch::new(m, DEFAULT_HASH_COUNT, SEED);
let mut b_sk = IbltSketch::new(m, DEFAULT_HASH_COUNT, SEED);
for &k in black_box(ak) {
a.insert(k);
}
for &k in black_box(bk) {
b_sk.insert(k);
}
a.subtract(&b_sk);
black_box(a.decode())
});
},
);
}
}
group.finish();
// ── Wire size table (not timed) ───────────────────────────────────────────
println!("\n=== IBLT sketch size vs flat manifest (N × 60 B) ===");
println!(
"{:>8} {:>10} {:>12} {:>10}",
"N", "IBLT (B)", "Flat (B)", "ratio"
);
for &n in &[10usize, 100, 1_000, 10_000, 100_000] {
let ks = keys(n);
let sz = IbltSketch::from_keys(&ks, SEED).to_bytes().len();
let flat = n * 60;
println!(
"{:>8} {:>10} {:>12} {:>9.1}×",
n,
sz,
flat,
flat as f64 / sz as f64
);
}
}
criterion_group!(benches, bench_iblt);
criterion_main!(benches);