diff --git a/src/lib.rs b/src/lib.rs index e4de765ab..efd2396ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1084,7 +1084,7 @@ https://bheisler.github.io/criterion.rs/book/faq.html /// // Now we can perform benchmarks with this group /// group.bench_function("Bench 1", |b| b.iter(|| 1 )); /// group.bench_function("Bench 2", |b| b.iter(|| 2 )); - /// + /// /// group.finish(); /// } /// criterion_group!(benches, bench_simple); @@ -1104,6 +1104,79 @@ https://bheisler.github.io/criterion.rs/book/faq.html BenchmarkGroup::new(self, group_name) } } +impl<M: Measurement + Clone> Criterion<M> { + /// Returns a clone of the measurement. + /// + /// This can be used when [`Bencher::iter_custom`](struct.Bencher.html#method.iter_custom) + /// is called from a function generic over the measurement to perform manual measurements. + /// + /// # Example + /// + /// ```rust + /// #[macro_use] extern crate criterion; + /// use criterion::*; + /// use criterion::measurement::{Measurement, WallTime}; + /// # // stub for cycles, criterion only has WallTime as only measurement for now + /// # use criterion::measurement::ValueFormatter; + /// # use std::time::Duration; + /// #[derive(Clone)] + /// pub struct Cycles; + /// + /// impl Measurement for Cycles { + /// // ... + /// # type Intermediate = (); type Value = u64; + /// # fn start(&self) -> Self::Intermediate {} + /// # fn end(&self, start_cycles: ()) -> u64 { 10 } + /// # fn add(&self, c1: &u64, c2: &u64) -> u64 { c1 + c2 } + /// # fn zero(&self) -> u64 { 0 } + /// # fn to_f64(&self, value: &u64) -> f64 { *value as f64 } + /// # fn formatter(&self) -> &dyn ValueFormatter { &CyclesFormatter } + /// } + /// # struct CyclesFormatter; + /// # impl ValueFormatter for CyclesFormatter { + /// # fn scale_throughputs(&self, _typical: f64, _throughput: &Throughput, _values: &mut [f64]) -> &'static str { panic!() } + /// # fn scale_values(&self, _reference: f64, _values: &mut [f64]) -> &'static str { "cycles" } + /// # fn scale_for_machines(&self, _values: &mut [f64]) -> &'static str { "cycles" } + /// # } + /// + /// fn foo(input: u64) { + /// // ... + /// } + /// + /// fn bench(name: &str, c: &mut Criterion<impl Measurement + Clone + 'static>) { + /// let measurement = c.measurement(); + /// c.bench_function(name, move |b| { + /// b.iter_custom(|iters| { + /// let input = black_box(1337); + /// let start = measurement.start(); + /// for _i in 0..iters { + /// foo(input); + /// } + /// measurement.end(start) + /// }) + /// }); + /// } + /// + /// fn main() { + /// let mut criterion_time = Criterion::default() + /// # .warm_up_time(Duration::from_millis(50)) + /// # .measurement_time(Duration::from_millis(100)) + /// # .sample_size(10) + /// .with_measurement(WallTime); + /// bench("time", &mut criterion_time); + /// let mut criterion_cycles = Criterion::default() + /// # .warm_up_time(Duration::from_millis(50)) + /// # .measurement_time(Duration::from_millis(100)) + /// # .sample_size(10) + /// .with_measurement(Cycles); + /// bench("cycles", &mut criterion_cycles); + /// } + /// ``` + #[allow(clippy::needless_doctest_main)] + pub fn measurement(&self) -> M { + self.measurement.clone() + } +} impl<M> Criterion<M> where M: Measurement + 'static, diff --git a/src/measurement.rs b/src/measurement.rs index e253670fc..8abd062a5 100644 --- a/src/measurement.rs +++ b/src/measurement.rs @@ -186,6 +186,7 @@ impl ValueFormatter for DurationFormatter { /// `WallTime` is the default measurement in Criterion.rs. It measures the elapsed time from the /// beginning of a series of iterations to the end. +#[derive(Clone, Copy)] pub struct WallTime; impl Measurement for WallTime { type Intermediate = Instant;