Files
clawsync/crates/clawsync-core/benches/cdc_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

116 lines
5.1 KiB
Rust

//! Criterion benchmarks: FastCDC vs SIMD Gear hash CDC.
//!
//! Run:
//! cargo bench -p clawsync-core --features simd-cdc -- cdc_bench
//!
//! Groups:
//! - `cdc/fastcdc/{data_type}/{size}` — baseline (FastCDC from `fastcdc` crate)
//! - `cdc/simd/{data_type}/{size}` — SIMD Gear hash path
//! - `cdc/scalar/{data_type}/{size}` — scalar Gear hash (same algorithm, no SIMD skip)
use clawsync_core::cdc::{chunk_data, chunk_data_simd};
#[cfg(feature = "simd-cdc")]
use clawsync_core::simd_cdc::chunk_scalar;
use criterion::{BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main};
// ─────────────────────────────────────────────────────────────────────────────
// Data generators
// ─────────────────────────────────────────────────────────────────────────────
fn random_data(n: usize) -> Vec<u8> {
(0..n)
.map(|i| {
let v = (i as u64)
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
(v ^ (v >> 33)) as u8
})
.collect()
}
/// Simulates IEEE 754 float array bytes: exponent bytes cluster in 0x3F-0x45,
/// mantissa bytes spread across 0x00-0xFF.
fn float_data(n: usize) -> Vec<u8> {
let mut v = Vec::with_capacity(n);
let mut i = 0usize;
while i + 4 <= n {
// Synthetic f32: sign(0) | exp(127±small) | mantissa
let exp_byte = 0x3Fu8.wrapping_add((i % 16) as u8);
let mant0 = (i.wrapping_mul(2654435769) >> 24) as u8;
let mant1 = (i.wrapping_mul(0x811c9dc5) >> 16) as u8;
let mant2 = (i.wrapping_mul(0x01000193)) as u8;
v.push(mant2); // byte 0: low mantissa (often < 64 → hot)
v.push(mant1);
v.push(mant0);
v.push(exp_byte); // byte 3: exponent (often 0x3F-0x45 ≥ 64 → cold)
i += 4;
}
v.truncate(n);
v
}
/// All bytes are cold (≥ 64) — worst case for SIMD skip, exercises batch-shift path.
fn cold_data(n: usize) -> Vec<u8> {
(0..n).map(|i| 64u8 + ((i * 7) % 192) as u8).collect()
}
// ─────────────────────────────────────────────────────────────────────────────
// Benchmark
// ─────────────────────────────────────────────────────────────────────────────
fn bench_cdc(c: &mut Criterion) {
let datasets: &[(&str, fn(usize) -> Vec<u8>)] = &[
("random", random_data),
("float", float_data),
("cold_only", cold_data),
];
let sizes = [1 << 20, 4 << 20, 16 << 20]; // 1 MB, 4 MB, 16 MB
for &(label, make) in datasets {
// ── FastCDC (baseline) ───────────────────────────────────────────────
let mut group = c.benchmark_group(format!("cdc/fastcdc/{label}"));
for &size in &sizes {
let data = make(size);
group.throughput(Throughput::Bytes(size as u64));
group.bench_with_input(
BenchmarkId::new("chunk_data", format!("{}MB", size >> 20)),
&data,
|b, d| b.iter(|| chunk_data(black_box(d))),
);
}
group.finish();
// ── SIMD Gear hash ───────────────────────────────────────────────────
let mut group = c.benchmark_group(format!("cdc/simd/{label}"));
for &size in &sizes {
let data = make(size);
group.throughput(Throughput::Bytes(size as u64));
group.bench_with_input(
BenchmarkId::new("chunk_data_simd", format!("{}MB", size >> 20)),
&data,
|b, d| b.iter(|| chunk_data_simd(black_box(d))),
);
}
group.finish();
// ── Scalar Gear hash (no SIMD skip) ──────────────────────────────────
#[cfg(feature = "simd-cdc")]
{
let mut group = c.benchmark_group(format!("cdc/scalar/{label}"));
for &size in &sizes {
let data = make(size);
group.throughput(Throughput::Bytes(size as u64));
group.bench_with_input(
BenchmarkId::new("chunk_scalar", format!("{}MB", size >> 20)),
&data,
|b, d| b.iter(|| chunk_scalar(black_box(d), 8192, 65536, 262144)),
);
}
group.finish();
}
}
}
criterion_group!(benches, bench_cdc);
criterion_main!(benches);