#![cfg_attr(feature = "fail-on-warnings", deny(warnings))] use criterion::{ black_box, criterion_group, criterion_main, Bencher, Benchmark, Criterion, Throughput, }; use fixed::{traits::Fixed, types::*}; use num_traits::{One, Zero}; use rand::{ distributions::{Distribution, Standard}, Rng, }; use rand_xoshiro::{rand_core::SeedableRng, Xoshiro256Plus}; use std::convert::TryInto; const SEED: u64 = 42_069; const DATASET_SIZE: usize = 10_000; fn gen_non_zero(rng: &mut R) -> T where R: Rng + ?Sized, T: Zero + One + PartialEq, Standard: Distribution, { let value: T = rng.gen(); if value != T::zero() { value } else { T::one() } } fn gen_tuple_dataset(cap: usize) -> Vec<(T, T)> where T: Zero + One + PartialEq, Standard: Distribution, { let mut rng: Xoshiro256Plus = Xoshiro256Plus::seed_from_u64(SEED); (0..cap) .map(|_| (rng.gen(), gen_non_zero(&mut rng))) .collect() } fn fixed_point_op(bencher: &mut Bencher, op: O) where F: Fixed, F::Bits: Zero + One + PartialEq, Standard: Distribution, O: Fn(F, F) -> F, { let bits_dataset: Vec<(F::Bits, F::Bits)> = gen_tuple_dataset(DATASET_SIZE); let fixed_dataset: Vec<(F, F)> = bits_dataset .into_iter() .map(|(l, r)| (Fixed::from_bits(l), Fixed::from_bits(r))) .collect(); bencher.iter(|| { for (l, r) in &fixed_dataset { let r = op(*l, *r); black_box(r); } }); } fn primitive_op(b: &mut Bencher, op: O) where Standard: Distribution

, P: Copy + PartialEq + Zero + One, O: Fn(P, P) -> P, { let primitive_dataset: Vec<(P, P)> = gen_tuple_dataset(DATASET_SIZE); b.iter(|| { for (l, r) in &primitive_dataset { let sum = op(*l, *r); black_box(sum); } }); } macro_rules! create_bench { ($bench:ident, $name:expr, $op:expr) => { pub(crate) fn $bench(c: &mut Criterion) { c.bench( &$name.to_owned(), // We only measure the overhead for the 64 bit test because // we found that the overhead is consistant accross sizes. Benchmark::new("benchmark overhead", move |b| { let f64_dataset: Vec<(f64, f64)> = gen_tuple_dataset(DATASET_SIZE); b.iter(|| { for (l, _) in &f64_dataset { black_box(l); } }); }) .with_function("u128", move |b| { primitive_op::(b, $op); }) .with_function("i128", move |b| { primitive_op::(b, $op); }) .with_function("FixedU128", move |b| { fixed_point_op::(b, $op); }) .with_function("FixedI128", move |b| { fixed_point_op::(b, $op); }) .with_function("f64", move |b| { primitive_op::(b, $op); }) .with_function("u64", move |b| { primitive_op::(b, $op); }) .with_function("i64", move |b| { primitive_op::(b, $op); }) .with_function("FixedU64", move |b| { fixed_point_op::(b, $op); }) .with_function("FixedI64", move |b| { fixed_point_op::(b, $op); }) .with_function("f32", move |b| { primitive_op::(b, $op); }) .with_function("u32", move |b| { primitive_op::(b, $op); }) .with_function("i32", move |b| { primitive_op::(b, $op); }) .with_function("FixedU32", move |b| { fixed_point_op::(b, $op); }) .with_function("FixedI32", move |b| { fixed_point_op::(b, $op); }) .with_function("u16", move |b| { primitive_op::(b, $op); }) .with_function("i16", move |b| { primitive_op::(b, $op); }) .with_function("FixedU16", move |b| { fixed_point_op::(b, $op); }) .with_function("FixedI16", move |b| { fixed_point_op::(b, $op); }) .with_function("u8", move |b| { primitive_op::(b, $op); }) .with_function("i8", move |b| { primitive_op::(b, $op); }) .with_function("FixedU8", move |b| { fixed_point_op::(b, $op); }) .with_function("FixedI8", move |b| { fixed_point_op::(b, $op); }) .throughput(Throughput::Elements(DATASET_SIZE.try_into().unwrap())), ); } }; } create_bench!(bench_add, "add", |l, r| l + r); create_bench!(bench_sub, "sub", |l, r| l - r); create_bench!(bench_mul, "mul", |l, r| l * r); create_bench!(bench_div, "div", |l, r| l / r); criterion_group!(benches, bench_add, bench_sub, bench_mul, bench_div); criterion_main!(benches);