use criterion::{Criterion, criterion_group, criterion_main}; use rustfs_object_capacity::{CapacityDiskRef, scan_used_capacity_disks}; use std::fs; use std::hint::black_box; use std::path::{Path, PathBuf}; use std::time::Duration; use tempfile::TempDir; const EXACT_FILE_SIZE: usize = 4 * 1024; const SAMPLED_FILE_SIZE: usize = 1; const DEFAULT_SAMPLE_TRIGGER_FILE_COUNT: usize = 202_048; #[derive(Clone, Copy)] struct DiskSpec { file_count: usize, file_size: usize, } struct CapacityScanFixture { _dirs: Vec, disks: Vec, } impl CapacityScanFixture { fn new(specs: &[DiskSpec]) -> Self { let mut dirs = Vec::with_capacity(specs.len()); let mut disks = Vec::with_capacity(specs.len()); for (idx, spec) in specs.iter().enumerate() { let dir = TempDir::new().expect("create temp dir"); populate_files(dir.path(), spec.file_count, spec.file_size).expect("populate files"); disks.push(CapacityDiskRef { endpoint: format!("bench-disk-{idx}"), drive_path: dir.path().to_string_lossy().into_owned(), }); dirs.push(dir); } Self { _dirs: dirs, disks } } } fn populate_files(root: &Path, file_count: usize, file_size: usize) -> std::io::Result<()> { let payload = vec![b'x'; file_size]; let shard_count = (file_count / 512).clamp(1, 256); for shard_idx in 0..shard_count { fs::create_dir_all(root.join(format!("bucket-{shard_idx:03}")))?; } for file_idx in 0..file_count { let subdir = root.join(format!("bucket-{:03}", file_idx % shard_count)); let file_path: PathBuf = subdir.join(format!("object-{file_idx:08}.bin")); fs::write(file_path, &payload)?; } Ok(()) } fn bench_capacity_scan(c: &mut Criterion) { let runtime = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .expect("create runtime"); let exact_fixture = CapacityScanFixture::new(&[DiskSpec { file_count: 10_000, file_size: EXACT_FILE_SIZE, }]); let sampled_fixture = CapacityScanFixture::new(&[DiskSpec { file_count: DEFAULT_SAMPLE_TRIGGER_FILE_COUNT, file_size: SAMPLED_FILE_SIZE, }]); let multi_disk_fixture = CapacityScanFixture::new(&[ DiskSpec { file_count: 4_000, file_size: 1024, }, DiskSpec { file_count: 6_000, file_size: 2048, }, DiskSpec { file_count: 8_000, file_size: 4096, }, DiskSpec { file_count: 10_000, file_size: 1024, }, ]); let mut exact_group = c.benchmark_group("capacity_scan_exact"); exact_group.sample_size(10); exact_group.measurement_time(Duration::from_secs(10)); exact_group.bench_function("single_disk_10k_4k", |b| { b.iter(|| { let summary = runtime .block_on(scan_used_capacity_disks(black_box(&exact_fixture.disks))) .expect("exact scan"); black_box(summary); }); }); exact_group.finish(); let mut sampled_group = c.benchmark_group("capacity_scan_sampled"); sampled_group.sample_size(10); sampled_group.measurement_time(Duration::from_secs(10)); sampled_group.bench_function("single_disk_202k_1b", |b| { b.iter(|| { let summary = runtime .block_on(scan_used_capacity_disks(black_box(&sampled_fixture.disks))) .expect("sampled scan"); black_box(summary); }); }); sampled_group.finish(); let mut multi_disk_group = c.benchmark_group("capacity_scan_multi_disk"); multi_disk_group.sample_size(10); multi_disk_group.measurement_time(Duration::from_secs(10)); multi_disk_group.bench_function("four_disks_mixed_exact", |b| { b.iter(|| { let summary = runtime .block_on(scan_used_capacity_disks(black_box(&multi_disk_fixture.disks))) .expect("multi-disk scan"); black_box(summary); }); }); multi_disk_group.finish(); } criterion_group!(benches, bench_capacity_scan); criterion_main!(benches);