use criterion::{ black_box, criterion_group, measurement::{Measurement, ValueFormatter}, Criterion, Throughput, }; use std::time::{Duration, Instant}; struct HalfSecFormatter; impl ValueFormatter for HalfSecFormatter { fn format_value(&self, value: f64) -> String { // The value will be in nanoseconds so we have to convert to half-seconds. format!("{} s/2", value * 2f64 * 10f64.powi(-9)) } fn format_throughput(&self, throughput: &Throughput, value: f64) -> String { match *throughput { Throughput::Bytes(bytes) | Throughput::BytesDecimal(bytes) => { format!("{} b/s/2", (bytes as f64) / (value * 2f64 * 10f64.powi(-9))) } Throughput::Elements(elems) => format!( "{} elem/s/2", (elems as f64) / (value * 2f64 * 10f64.powi(-9)) ), } } fn scale_values(&self, _typical: f64, values: &mut [f64]) -> &'static str { for val in values { *val *= 2f64 * 10f64.powi(-9); } "s/2" } fn scale_throughputs( &self, _typical: f64, throughput: &Throughput, values: &mut [f64], ) -> &'static str { match *throughput { Throughput::Bytes(bytes) | Throughput::BytesDecimal(bytes) => { for val in values { *val = (bytes as f64) / (*val * 2f64 * 10f64.powi(-9)) } "b/s/2" } Throughput::Elements(elems) => { for val in values { *val = (elems as f64) / (*val * 2f64 * 10f64.powi(-9)) } "elem/s/2" } } } fn scale_for_machines(&self, values: &mut [f64]) -> &'static str { for val in values { *val *= 2f64 * 10f64.powi(-9); } "s/2" } } const NANOS_PER_SEC: u64 = 1_000_000_000; /// Silly "measurement" that is really just wall-clock time reported in half-seconds. struct HalfSeconds; impl Measurement for HalfSeconds { type Intermediate = Instant; type Value = Duration; fn start(&self) -> Self::Intermediate { Instant::now() } fn end(&self, i: Self::Intermediate) -> Self::Value { i.elapsed() } fn add(&self, v1: &Self::Value, v2: &Self::Value) -> Self::Value { *v1 + *v2 } fn zero(&self) -> Self::Value { Duration::from_secs(0) } fn to_f64(&self, val: &Self::Value) -> f64 { let nanos = val.as_secs() * NANOS_PER_SEC + u64::from(val.subsec_nanos()); nanos as f64 } fn formatter(&self) -> &dyn ValueFormatter { &HalfSecFormatter } } fn fibonacci_slow(n: u64) -> u64 { match n { 0 | 1 => 1, n => fibonacci_slow(n - 1) + fibonacci_slow(n - 2), } } fn fibonacci_cycles(criterion: &mut Criterion) { criterion.bench_function("fibonacci_custom_measurement", |bencher| { bencher.iter(|| fibonacci_slow(black_box(10))) }); } fn alternate_measurement() -> Criterion { Criterion::default().with_measurement(HalfSeconds) } criterion_group! { name = benches; config = alternate_measurement(); targets = fibonacci_cycles }