use alux_bench::{BenchAlg, BenchCases, BenchGroup, BenchRounds, BenchSampling, BenchStated, MeasureBenchAlg};
use core::time::Duration;
use criterion::measurement::WallTime;
use criterion::{BenchmarkGroup, Criterion};
use derive_new::new as New;
const SAMPLE_FLOOR: usize = 10;
const LEAST: Duration = Duration::from_millis(1);
#[derive(New)]
pub struct CriterionBench<'bench> {
bench: &'bench mut Criterion,
}
impl CriterionBench<'_> {
pub fn sampled(sampling: BenchSampling) -> Criterion {
let spend = sampling.spend().unwrap_or(LEAST);
Criterion::default()
.sample_size(sampling.samples().max(SAMPLE_FLOOR))
.warm_up_time(spend)
.measurement_time(spend)
.without_plots()
}
pub fn measuring<Stating>(criterion: &mut Criterion, stating: Stating)
where
Stating: FnOnce(&CriterionBench<'_>) -> BenchStated<'static>,
{
let mut bench = CriterionBench::new(criterion);
let stated = stating(&bench);
bench.measure(stated);
}
}
impl BenchAlg for CriterionBench<'_> {
type Bench = BenchStated<'static>;
fn nothing(&self) -> Self::Bench {
BenchStated::new()
}
fn group(&self, group: &'static str, cases: BenchCases<'static>) -> Self::Bench {
BenchStated::new().group(BenchGroup::new(group, cases))
}
fn then(&self, first: Self::Bench, next: Self::Bench) -> Self::Bench {
first.then(next)
}
}
impl MeasureBenchAlg for CriterionBench<'_> {
type Bench = BenchStated<'static>;
fn measure(&mut self, bench: Self::Bench) {
for stated in bench.into_groups() {
let mut group = self.bench.benchmark_group(stated.group());
match stated.cases() {
BenchCases::OneAtATime(cases) => {
for (subject, routine) in cases {
case(&mut group, subject, routine);
}
}
BenchCases::Together(cases) => {
for (subject, routine) in cases {
case(&mut group, subject, routine);
}
}
}
}
}
}
fn case<Routine>(group: &mut BenchmarkGroup<'_, WallTime>, subject: &'static str, mut routine: Routine)
where
Routine: FnMut(BenchRounds) -> Duration,
{
group.bench_function(subject, |sampling| {
sampling.iter_custom(|count| routine(BenchRounds::new(count)));
});
}