//! Object serialize + BLAKE3 hash microbenchmarks. //! //! Every commit, push, and clone pays this cost — content addressing //! depends on serialize→hash being fast. Three object types, three //! sizes each. use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; use levcs_core::hash::blake3_hash; use levcs_core::{Blob, Commit, CommitFlags, EntryType, FileMode, ObjectId, Tree, TreeEntry}; fn lcg_bytes(seed: u64, n: usize) -> Vec { let mut s = seed; (0..n) .map(|_| { s = s .wrapping_mul(6364136223846793005) .wrapping_add(1442695040888963407); (s >> 33) as u8 }) .collect() } fn make_tree(n_entries: usize) -> Tree { let mut t = Tree::new(); for i in 0..n_entries { t.entries.push(TreeEntry { name: format!("file_{i:04}.txt"), entry_type: EntryType::Blob, mode: FileMode::REGULAR, hash: ObjectId([(i & 0xff) as u8; 32]), }); } t.sort_and_validate().unwrap(); t } fn make_commit(message_size: usize) -> Commit { Commit { tree: ObjectId([1; 32]), parents: vec![ObjectId([2; 32])], authority: ObjectId([3; 32]), author_key: [4; 32], timestamp_micros: 1_700_000_000_000_000, flags: CommitFlags::NONE, message: "x".repeat(message_size), } } fn bench_blob(c: &mut Criterion) { let mut g = c.benchmark_group("blob_serialize_hash"); for &(label, size) in &[ ("1KiB", 1024usize), ("100KiB", 100 * 1024), ("1MiB", 1024 * 1024), ] { let bytes = lcg_bytes(0x1234_5678, size); g.throughput(Throughput::Bytes(size as u64)); g.bench_with_input(BenchmarkId::from_parameter(label), &bytes, |b, bytes| { b.iter(|| { let blob = Blob::new(bytes.clone()); black_box(blake3_hash(&blob.serialize())) }) }); } g.finish(); } fn bench_tree(c: &mut Criterion) { let mut g = c.benchmark_group("tree_serialize_hash"); for &n in &[10usize, 100, 1000] { let t = make_tree(n); g.bench_with_input( BenchmarkId::from_parameter(format!("{n}_entries")), &t, |b, t| b.iter(|| black_box(blake3_hash(&t.serialize()))), ); } g.finish(); } fn bench_commit(c: &mut Criterion) { let mut g = c.benchmark_group("commit_serialize_hash"); for &(label, msg_size) in &[("short", 32usize), ("medium", 1024), ("long", 16 * 1024)] { let commit = make_commit(msg_size); g.bench_with_input(BenchmarkId::from_parameter(label), &commit, |b, commit| { b.iter(|| { let body = commit.body().unwrap(); black_box(blake3_hash(&body)) }) }); } g.finish(); } criterion_group!(benches, bench_blob, bench_tree, bench_commit); criterion_main!(benches);