use std::time::{Duration, Instant};
pub fn bench_iterations<F: Fn()>(iterations: usize, f: F) -> Duration {
let mut total = Duration::ZERO;
for _ in 0..10 {
f();
}
for _ in 0..iterations {
let start = Instant::now();
f();
total += start.elapsed();
}
total / iterations as u32
}
pub fn bench<F: FnOnce()>(f: F) -> Duration {
let start = Instant::now();
f();
start.elapsed()
}
pub fn bench_compare<F: Fn(), G: Fn()>(f: F, g: G, iterations: usize) -> (Duration, Duration, f64) {
let time_f = bench_iterations(iterations, f);
let time_g = bench_iterations(iterations, g);
let speedup = time_f.as_secs_f64() / time_g.as_secs_f64();
(time_f, time_g, speedup)
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread;
#[test]
fn test_bench_iterations() {
let avg = bench_iterations(10, || {
thread::sleep(Duration::from_millis(1));
});
assert!(avg.as_millis() >= 1 && avg.as_millis() <= 5);
}
#[test]
fn test_bench() {
let duration = bench(|| {
thread::sleep(Duration::from_millis(10));
});
assert!(duration.as_millis() >= 10 && duration.as_millis() <= 20);
}
#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_bench_compare() {
let (time_slow, time_fast, speedup) = bench_compare(
|| {
let start = std::time::Instant::now();
let mut sum = 0u64;
while start.elapsed() < Duration::from_micros(100) {
sum = sum.wrapping_add(1);
}
},
|| {
let start = std::time::Instant::now();
let mut sum = 0u64;
while start.elapsed() < Duration::from_micros(50) {
sum = sum.wrapping_add(1);
}
},
3,
);
assert!(
time_slow > Duration::from_nanos(1),
"Slow function should take measurable time, got {:?}",
time_slow
);
assert!(
time_fast > Duration::from_nanos(1),
"Fast function should take measurable time, got {:?}",
time_fast
);
assert!(
speedup > 0.0 && speedup < 1000.0,
"Speedup should be reasonable, got {}",
speedup
);
}
}