// Benchmark the `v1` version of the algorithm #[cfg(feature = "ffi")] use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; #[cfg(feature = "ffi")] use std::ffi::c_void; // FFI declaration for the C implementation #[cfg(feature = "ffi")] extern "C" { fn chibihash64(key: *const c_void, len: isize, seed: u64) -> u64; } #[cfg(feature = "ffi")] fn bench_cross_language(c: &mut Criterion) { let mut group = c.benchmark_group("rust_vs_c"); // Test different input patterns let test_cases = vec![ ("zeros", vec![0u8; 1024]), ("ones", vec![1u8; 1024]), ("alternating", (0..1024).map(|i| (i % 2) as u8).collect()), ("incremental", (0..1024).map(|i| (i % 256) as u8).collect()), ("random", { let mut v = vec![0u8; 1024]; for i in 0..1024 { v[i] = ((i * 7 + 13) % 256) as u8; } v }), ]; // Test different sizes to see where performance characteristics differ let sizes = [8, 16, 32, 64, 128, 256, 512, 1024]; for (pattern_name, pattern) in test_cases { for size in sizes.iter() { let input = &pattern[..*size]; // Benchmark Rust implementation group.bench_with_input( BenchmarkId::new(format!("rust_{}", pattern_name), size), &input, |b, input| { b.iter(|| black_box(chibihash::chibi_hash64(black_box(input), black_box(0)))) }, ); // Benchmark C implementation group.bench_with_input( BenchmarkId::new(format!("c_{}", pattern_name), size), &input, |b, input| { b.iter(|| unsafe { black_box(chibihash64( black_box(input.as_ptr() as *const c_void), black_box(input.len() as isize), black_box(0), )) }) }, ); } } // Test alignment sensitivity let aligned_data = vec![0u8; 1024]; let mut unaligned_data = vec![0u8; 1025]; unaligned_data.remove(0); // Create unaligned slice for size in [32, 64, 128, 256].iter() { group.bench_with_input( BenchmarkId::new("rust_aligned", size), &aligned_data[..*size], |b, input| b.iter(|| black_box(chibihash::chibi_hash64(black_box(input), 0))), ); group.bench_with_input( BenchmarkId::new("rust_unaligned", size), &unaligned_data[..*size], |b, input| b.iter(|| black_box(chibihash::chibi_hash64(black_box(input), 0))), ); // Same for C implementation group.bench_with_input( BenchmarkId::new("c_aligned", size), &aligned_data[..*size], |b, input| unsafe { b.iter(|| { black_box(chibihash64( black_box(input.as_ptr() as *const c_void), black_box(input.len() as isize), 0, )) }) }, ); group.bench_with_input( BenchmarkId::new("c_unaligned", size), &unaligned_data[..*size], |b, input| unsafe { b.iter(|| { black_box(chibihash64( black_box(input.as_ptr() as *const c_void), black_box(input.len() as isize), 0, )) }) }, ); } group.finish(); } #[cfg(feature = "ffi")] criterion_group!(benches, bench_cross_language); #[cfg(feature = "ffi")] criterion_main!(benches); // Add this fallback main function for when FFI is disabled #[cfg(not(feature = "ffi"))] fn main() { println!("This benchmark requires the 'ffi' feature to be enabled."); println!("Please run with: cargo bench --features ffi"); }