| 1 | use criterion::{ |
| 2 | black_box, criterion_group, |
| 3 | measurement::{Measurement, ValueFormatter}, |
| 4 | Criterion, Throughput, |
| 5 | }; |
| 6 | use std::time::{Duration, Instant}; |
| 7 | |
| 8 | struct HalfSecFormatter; |
| 9 | impl ValueFormatter for HalfSecFormatter { |
| 10 | fn format_value(&self, value: f64) -> String { |
| 11 | // The value will be in nanoseconds so we have to convert to half-seconds. |
| 12 | format!("{} s/2" , value * 2f64 * 10f64.powi(-9)) |
| 13 | } |
| 14 | |
| 15 | fn format_throughput(&self, throughput: &Throughput, value: f64) -> String { |
| 16 | match *throughput { |
| 17 | Throughput::Bytes(bytes) | Throughput::BytesDecimal(bytes) => { |
| 18 | format!("{} b/s/2" , (bytes as f64) / (value * 2f64 * 10f64.powi(-9))) |
| 19 | } |
| 20 | Throughput::Elements(elems) => format!( |
| 21 | "{} elem/s/2" , |
| 22 | (elems as f64) / (value * 2f64 * 10f64.powi(-9)) |
| 23 | ), |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | fn scale_values(&self, _typical: f64, values: &mut [f64]) -> &'static str { |
| 28 | for val in values { |
| 29 | *val *= 2f64 * 10f64.powi(-9); |
| 30 | } |
| 31 | |
| 32 | "s/2" |
| 33 | } |
| 34 | |
| 35 | fn scale_throughputs( |
| 36 | &self, |
| 37 | _typical: f64, |
| 38 | throughput: &Throughput, |
| 39 | values: &mut [f64], |
| 40 | ) -> &'static str { |
| 41 | match *throughput { |
| 42 | Throughput::Bytes(bytes) | Throughput::BytesDecimal(bytes) => { |
| 43 | for val in values { |
| 44 | *val = (bytes as f64) / (*val * 2f64 * 10f64.powi(-9)) |
| 45 | } |
| 46 | |
| 47 | "b/s/2" |
| 48 | } |
| 49 | Throughput::Elements(elems) => { |
| 50 | for val in values { |
| 51 | *val = (elems as f64) / (*val * 2f64 * 10f64.powi(-9)) |
| 52 | } |
| 53 | |
| 54 | "elem/s/2" |
| 55 | } |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | fn scale_for_machines(&self, values: &mut [f64]) -> &'static str { |
| 60 | for val in values { |
| 61 | *val *= 2f64 * 10f64.powi(-9); |
| 62 | } |
| 63 | |
| 64 | "s/2" |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | const NANOS_PER_SEC: u64 = 1_000_000_000; |
| 69 | |
| 70 | /// Silly "measurement" that is really just wall-clock time reported in half-seconds. |
| 71 | struct HalfSeconds; |
| 72 | impl Measurement for HalfSeconds { |
| 73 | type Intermediate = Instant; |
| 74 | type Value = Duration; |
| 75 | |
| 76 | fn start(&self) -> Self::Intermediate { |
| 77 | Instant::now() |
| 78 | } |
| 79 | fn end(&self, i: Self::Intermediate) -> Self::Value { |
| 80 | i.elapsed() |
| 81 | } |
| 82 | fn add(&self, v1: &Self::Value, v2: &Self::Value) -> Self::Value { |
| 83 | *v1 + *v2 |
| 84 | } |
| 85 | fn zero(&self) -> Self::Value { |
| 86 | Duration::from_secs(0) |
| 87 | } |
| 88 | fn to_f64(&self, val: &Self::Value) -> f64 { |
| 89 | let nanos = val.as_secs() * NANOS_PER_SEC + u64::from(val.subsec_nanos()); |
| 90 | nanos as f64 |
| 91 | } |
| 92 | fn formatter(&self) -> &dyn ValueFormatter { |
| 93 | &HalfSecFormatter |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | fn fibonacci_slow(n: u64) -> u64 { |
| 98 | match n { |
| 99 | 0 | 1 => 1, |
| 100 | n => fibonacci_slow(n - 1) + fibonacci_slow(n - 2), |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | fn fibonacci_cycles(criterion: &mut Criterion<HalfSeconds>) { |
| 105 | criterion.bench_function("fibonacci_custom_measurement" , |bencher| { |
| 106 | bencher.iter(|| fibonacci_slow(black_box(10))) |
| 107 | }); |
| 108 | } |
| 109 | |
| 110 | fn alternate_measurement() -> Criterion<HalfSeconds> { |
| 111 | Criterion::default().with_measurement(HalfSeconds) |
| 112 | } |
| 113 | |
| 114 | criterion_group! { |
| 115 | name = benches; |
| 116 | config = alternate_measurement(); |
| 117 | targets = fibonacci_cycles |
| 118 | } |
| 119 | |