use super::engine::SampleRaw;
use super::state::Bencher;
use std::time::Duration;
impl Bencher {
#[inline]
pub fn iter_custom<F>(&mut self, mut routine: F)
where
F: FnMut(u64) -> Duration,
{
if !self.begin_iter() {
return;
}
self.run_loop(|b, n| {
b.alloc_reset();
let elapsed = routine(n);
let (alloc_b, alloc_c) = b.alloc_read();
SampleRaw {
ns: u64::try_from(elapsed.as_nanos()).unwrap_or(u64::MAX),
alloc_b,
alloc_c,
..SampleRaw::default()
}
});
}
}
#[cfg(test)]
mod tests {
use crate::bencher::test_support::{fixed, quick};
use crate::bencher::{Bencher, run_benchmark_loop};
use std::cell::Cell;
use std::time::Duration;
#[test]
fn reported_time_becomes_the_sample_mean() {
let result = run_benchmark_loop(Bencher::with_config(fixed(4, 25)), |b| {
b.iter_custom(|iters| Duration::from_nanos(iters * 100));
})
.expect("measurement succeeds");
assert_eq!(result.samples.len(), 4);
assert!(result.samples.iter().all(|s| s.duration_nanos == 100.0));
assert!(result.samples.iter().all(|s| s.iterations == 25));
assert_eq!(result.iterations, 100);
assert_eq!(result.total_time_ns, 100 * 100);
}
#[test]
fn every_requested_iteration_is_accounted() {
let requested = Cell::new(0_u64);
let result = run_benchmark_loop(Bencher::with_config(quick(10)), |b| {
b.iter_custom(|iters| {
requested.set(requested.get() + iters);
Duration::from_nanos(iters * 10)
});
})
.expect("measurement succeeds");
assert_eq!(result.samples.len(), 10);
assert!(result.warmup_iterations > 0);
assert_eq!(
requested.get(),
result.iterations + result.warmup_iterations
);
assert_eq!(result.total_time_ns, result.iterations * 10);
}
#[test]
fn warmup_sizes_samples_from_the_wall_clock() {
let result = run_benchmark_loop(Bencher::with_config(quick(5)), |b| {
b.iter_custom(|iters| {
std::thread::sleep(Duration::from_millis(iters));
Duration::from_nanos(iters)
});
})
.expect("measurement succeeds");
assert!(
result.iters_per_sample <= 10,
"ips: {}",
result.iters_per_sample
);
}
}