use std::{env, hint::black_box, path::Path};
use criterion::{BatchSize, BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use repo::Repository;
use tempfile::TempDir;
fn synthetic_file_counts() -> Vec<usize> {
let mut counts = vec![1_000, 10_000];
if let Ok(value) = env::var("HEDDLE_BENCH_LARGE_SYNTHETIC")
&& let Ok(parsed) = value.parse::<usize>()
&& parsed > 10_000
{
counts.push(parsed);
}
counts
}
fn write_synthetic_files(root: &Path, count: usize) {
for i in 0..count {
let dir = root.join(format!("dir-{:02}", i % 20));
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(
dir.join(format!("file-{i:05}.txt")),
format!("synthetic file {i}\n{}\n", "x".repeat(64)),
)
.unwrap();
}
}
fn fixture_repo_with_files(count: usize) -> (TempDir, Repository) {
let dir = TempDir::new().unwrap();
let repo = Repository::init_default(dir.path()).unwrap();
write_synthetic_files(dir.path(), count);
repo.snapshot(Some(format!("seed {count} files")), None)
.unwrap();
(dir, repo)
}
fn bench_materialize_cold(c: &mut Criterion) {
let mut group = c.benchmark_group("clonefile_threads/materialize_cold");
for &count in &synthetic_file_counts() {
group.throughput(Throughput::Elements(count as u64));
group.bench_with_input(BenchmarkId::from_parameter(count), &count, |b, &count| {
let (_fixture, repo) = fixture_repo_with_files(count);
b.iter_batched_ref(
|| TempDir::new().unwrap(),
|dest| {
let path = dest.path().join("out");
let manifest = repo
.materialize_thread("main", &path, &repo::AudienceTier::Internal)
.expect("materialize");
black_box(manifest);
},
BatchSize::PerIteration,
);
});
}
group.finish();
}
fn bench_capture_noop_fast_path(c: &mut Criterion) {
let mut group = c.benchmark_group("clonefile_threads/capture_noop_fast_path");
for &count in &synthetic_file_counts() {
group.throughput(Throughput::Elements(count as u64));
group.bench_with_input(BenchmarkId::from_parameter(count), &count, |b, &count| {
b.iter_batched_ref(
|| {
let (fixture, repo) = fixture_repo_with_files(count);
let dest = TempDir::new().unwrap();
let dest_path = dest.path().join("out");
repo.materialize_thread("main", &dest_path, &repo::AudienceTier::Internal)
.unwrap();
(fixture, repo, dest, dest_path)
},
|(_fixture, repo, _dest, dest_path)| {
let outcome = repo
.capture_thread_from_disk("main", dest_path)
.expect("capture");
black_box(outcome);
},
BatchSize::PerIteration,
);
});
}
group.finish();
}
fn bench_capture_single_edit(c: &mut Criterion) {
let mut group = c.benchmark_group("clonefile_threads/capture_single_edit");
for &count in &synthetic_file_counts() {
group.throughput(Throughput::Elements(count as u64));
group.bench_with_input(BenchmarkId::from_parameter(count), &count, |b, &count| {
b.iter_batched_ref(
|| {
let (fixture, repo) = fixture_repo_with_files(count);
let dest = TempDir::new().unwrap();
let dest_path = dest.path().join("out");
repo.materialize_thread("main", &dest_path, &repo::AudienceTier::Internal)
.unwrap();
let edited = dest_path.join("dir-00").join("file-00000.txt");
std::fs::write(&edited, b"edited\n").unwrap();
(fixture, repo, dest, dest_path)
},
|(_fixture, repo, _dest, dest_path)| {
let outcome = repo
.capture_thread_from_disk("main", dest_path)
.expect("capture");
black_box(outcome);
},
BatchSize::PerIteration,
);
});
}
group.finish();
}
criterion_group!(
clonefile_threads,
bench_materialize_cold,
bench_capture_noop_fast_path,
bench_capture_single_edit,
);
criterion_main!(clonefile_threads);