use std::{cell::RefCell, rc::Rc, time::Duration};
use codspeed::codspeed::CodSpeed;
use criterion::{measurement::Measurement, SamplingMode, Throughput};
use crate::{Bencher, Criterion};
pub struct BenchmarkGroup {
codspeed: Rc<RefCell<CodSpeed>>,
current_file: String,
macro_group: String,
group_name: String,
}
impl BenchmarkGroup {
pub fn new<M: Measurement>(criterion: &mut Criterion<M>, group_name: String) -> BenchmarkGroup {
BenchmarkGroup {
codspeed: criterion
.codspeed
.as_ref()
.expect("non instrumented codspeed interface")
.clone(),
current_file: criterion.current_file.clone(),
macro_group: criterion.macro_group.clone(),
group_name,
}
}
pub fn bench_function<ID: IntoBenchmarkId, F>(&mut self, id: ID, mut f: F) -> &mut Self
where
F: FnMut(&mut Bencher),
{
self.run_bench(id.into_benchmark_id(), &(), |b, _| f(b));
self
}
pub fn bench_with_input<ID: IntoBenchmarkId, F, I>(
&mut self,
id: ID,
input: &I,
f: F,
) -> &mut Self
where
F: FnMut(&mut Bencher, &I),
I: ?Sized,
{
self.run_bench(id.into_benchmark_id(), input, f);
self
}
fn run_bench<F, I>(&mut self, id: BenchmarkId, input: &I, mut f: F)
where
F: FnMut(&mut Bencher, &I),
I: ?Sized,
{
let mut uri = format!(
"{}::{}::{}",
self.current_file, self.macro_group, self.group_name,
);
if let Some(function_name) = id.function_name {
uri = format!("{}::{}", uri, function_name);
}
if let Some(parameter) = id.parameter {
uri = format!("{}[{}]", uri, parameter);
}
let mut b = Bencher::new(self.codspeed.clone(), uri);
f(&mut b, input);
}
}
#[allow(unused_variables)]
impl BenchmarkGroup {
pub fn sample_size(&mut self, n: usize) -> &mut Self {
self
}
pub fn warm_up_time(&mut self, dur: Duration) -> &mut Self {
self
}
pub fn measurement_time(&mut self, dur: Duration) -> &mut Self {
self
}
pub fn nresamples(&mut self, n: usize) -> &mut Self {
self
}
pub fn noise_threshold(&mut self, threshold: f64) -> &mut Self {
self
}
pub fn confidence_level(&mut self, cl: f64) -> &mut Self {
self
}
pub fn significance_level(&mut self, sl: f64) -> &mut Self {
self
}
pub fn throughput(&mut self, throughput: Throughput) -> &mut Self {
self
}
pub fn sampling_mode(&mut self, new_mode: SamplingMode) -> &mut Self {
self
}
pub fn finish(self) {}
}
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct BenchmarkId {
pub(crate) function_name: Option<String>,
pub(crate) parameter: Option<String>,
}
impl BenchmarkId {
pub fn new<S: Into<String>, P: ::std::fmt::Display>(
function_name: S,
parameter: P,
) -> BenchmarkId {
BenchmarkId {
function_name: Some(function_name.into()),
parameter: Some(format!("{}", parameter)),
}
}
pub fn from_parameter<P: ::std::fmt::Display>(parameter: P) -> BenchmarkId {
BenchmarkId {
function_name: None,
parameter: Some(format!("{}", parameter)),
}
}
pub(crate) fn no_function() -> BenchmarkId {
BenchmarkId {
function_name: None,
parameter: None,
}
}
pub(crate) fn no_function_with_input<P: ::std::fmt::Display>(parameter: P) -> BenchmarkId {
BenchmarkId {
function_name: None,
parameter: Some(format!("{}", parameter)),
}
}
}
mod private {
pub trait Sealed {}
impl Sealed for super::BenchmarkId {}
impl<S: Into<String>> Sealed for S {}
}
pub trait IntoBenchmarkId: private::Sealed {
fn into_benchmark_id(self) -> BenchmarkId;
}
impl IntoBenchmarkId for BenchmarkId {
fn into_benchmark_id(self) -> BenchmarkId {
self
}
}
impl<S: Into<String>> IntoBenchmarkId for S {
fn into_benchmark_id(self) -> BenchmarkId {
let function_name = self.into();
assert!(
!function_name.is_empty(),
"Function name must not be empty."
);
BenchmarkId {
function_name: Some(function_name),
parameter: None,
}
}
}