use std::time::{Duration, Instant};
use codspeed::instrument_hooks::InstrumentHooks;
#[cfg(feature = "async")]
use crate::async_executor::AsyncExecutor;
use crate::black_box;
use crate::measurement::Measurement;
#[cfg(feature = "async")]
use crate::AsyncBencher;
use crate::Bencher;
#[cfg(feature = "async")]
use std::future::Future;
#[derive(Debug, Clone, Copy)]
pub struct IterManualOptions {
rounds: u64,
iters: u64,
warmup_rounds: u64,
}
impl Default for IterManualOptions {
fn default() -> Self {
Self {
rounds: 1,
iters: 1,
warmup_rounds: 0,
}
}
}
impl IterManualOptions {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn rounds(mut self, rounds: u64) -> Self {
self.rounds = rounds;
self
}
#[must_use]
pub fn iters(mut self, iters: u64) -> Self {
self.iters = iters;
self
}
#[must_use]
pub fn warmup(mut self, warmup_rounds: u64) -> Self {
self.warmup_rounds = warmup_rounds;
self
}
}
pub(crate) struct ManualMeasurement {
pub samples: Vec<f64>,
pub iterations: u64,
}
impl<'a, M: Measurement> Bencher<'a, M> {
#[inline(never)]
pub fn iter_manual_unstable<O, R>(&mut self, opts: IterManualOptions, routine: R)
where
R: FnMut() -> O,
{
self.__codspeed_root_frame__iter_manual_unstable(opts, routine);
}
#[inline(never)]
#[allow(missing_docs, non_snake_case)]
pub fn __codspeed_root_frame__iter_manual_unstable<O, R>(
&mut self,
opts: IterManualOptions,
mut routine: R,
) where
R: FnMut() -> O,
{
self.iterated = true;
for _ in 0..opts.warmup_rounds {
for _ in 0..opts.iters {
black_box(routine());
}
}
self.elapsed_time = Duration::ZERO;
let mut samples = Vec::with_capacity(opts.rounds as usize);
for _ in 0..opts.rounds {
let bench_start = InstrumentHooks::current_timestamp();
let round_start = Instant::now();
let start = self.measurement.start();
for _ in 0..opts.iters {
black_box(routine());
}
let value = self.measurement.end(start);
self.elapsed_time += round_start.elapsed();
let bench_end = InstrumentHooks::current_timestamp();
InstrumentHooks::instance().add_benchmark_timestamps(bench_start, bench_end);
samples.push(self.measurement.to_f64(&value));
}
self.codspeed_manual = Some(ManualMeasurement {
samples,
iterations: opts.iters,
});
}
}
#[cfg(feature = "async")]
impl<'a, 'b, A: AsyncExecutor, M: Measurement> AsyncBencher<'a, 'b, A, M> {
#[inline(never)]
pub fn iter_manual_unstable<O, R, F>(&mut self, opts: IterManualOptions, routine: R)
where
R: FnMut() -> F,
F: Future<Output = O>,
{
self.__codspeed_root_frame__iter_manual_unstable(opts, routine);
}
#[inline(never)]
#[allow(missing_docs, non_snake_case)]
pub fn __codspeed_root_frame__iter_manual_unstable<O, R, F>(
&mut self,
opts: IterManualOptions,
mut routine: R,
) where
R: FnMut() -> F,
F: Future<Output = O>,
{
let AsyncBencher { b, runner } = self;
runner.block_on(async {
b.iterated = true;
for _ in 0..opts.warmup_rounds {
for _ in 0..opts.iters {
black_box(routine().await);
}
}
b.elapsed_time = Duration::ZERO;
let mut samples = Vec::with_capacity(opts.rounds as usize);
for _ in 0..opts.rounds {
let bench_start = InstrumentHooks::current_timestamp();
let round_start = Instant::now();
let start = b.measurement.start();
for _ in 0..opts.iters {
black_box(routine().await);
}
let value = b.measurement.end(start);
b.elapsed_time += round_start.elapsed();
let bench_end = InstrumentHooks::current_timestamp();
InstrumentHooks::instance().add_benchmark_timestamps(bench_start, bench_end);
samples.push(b.measurement.to_f64(&value));
}
b.codspeed_manual = Some(ManualMeasurement {
samples,
iterations: opts.iters,
});
});
}
}