174 lines
5.6 KiB
Rust
174 lines
5.6 KiB
Rust
#![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<T, R>(rng: &mut R) -> T
|
|
where
|
|
R: Rng + ?Sized,
|
|
T: Zero + One + PartialEq,
|
|
Standard: Distribution<T>,
|
|
{
|
|
let value: T = rng.gen();
|
|
if value != T::zero() {
|
|
value
|
|
} else {
|
|
T::one()
|
|
}
|
|
}
|
|
|
|
fn gen_tuple_dataset<T>(cap: usize) -> Vec<(T, T)>
|
|
where
|
|
T: Zero + One + PartialEq,
|
|
Standard: Distribution<T>,
|
|
{
|
|
let mut rng: Xoshiro256Plus = Xoshiro256Plus::seed_from_u64(SEED);
|
|
(0..cap)
|
|
.map(|_| (rng.gen(), gen_non_zero(&mut rng)))
|
|
.collect()
|
|
}
|
|
|
|
fn fixed_point_op<F, O>(bencher: &mut Bencher, op: O)
|
|
where
|
|
F: Fixed,
|
|
F::Bits: Zero + One + PartialEq,
|
|
Standard: Distribution<F::Bits>,
|
|
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<P, O>(b: &mut Bencher, op: O)
|
|
where
|
|
Standard: Distribution<P>,
|
|
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::<u128, _>(b, $op);
|
|
})
|
|
.with_function("i128", move |b| {
|
|
primitive_op::<i128, _>(b, $op);
|
|
})
|
|
.with_function("FixedU128", move |b| {
|
|
fixed_point_op::<U64F64, _>(b, $op);
|
|
})
|
|
.with_function("FixedI128", move |b| {
|
|
fixed_point_op::<I64F64, _>(b, $op);
|
|
})
|
|
.with_function("f64", move |b| {
|
|
primitive_op::<f64, _>(b, $op);
|
|
})
|
|
.with_function("u64", move |b| {
|
|
primitive_op::<u64, _>(b, $op);
|
|
})
|
|
.with_function("i64", move |b| {
|
|
primitive_op::<i64, _>(b, $op);
|
|
})
|
|
.with_function("FixedU64", move |b| {
|
|
fixed_point_op::<U32F32, _>(b, $op);
|
|
})
|
|
.with_function("FixedI64", move |b| {
|
|
fixed_point_op::<I32F32, _>(b, $op);
|
|
})
|
|
.with_function("f32", move |b| {
|
|
primitive_op::<f32, _>(b, $op);
|
|
})
|
|
.with_function("u32", move |b| {
|
|
primitive_op::<u32, _>(b, $op);
|
|
})
|
|
.with_function("i32", move |b| {
|
|
primitive_op::<i32, _>(b, $op);
|
|
})
|
|
.with_function("FixedU32", move |b| {
|
|
fixed_point_op::<U16F16, _>(b, $op);
|
|
})
|
|
.with_function("FixedI32", move |b| {
|
|
fixed_point_op::<I16F16, _>(b, $op);
|
|
})
|
|
.with_function("u16", move |b| {
|
|
primitive_op::<u16, _>(b, $op);
|
|
})
|
|
.with_function("i16", move |b| {
|
|
primitive_op::<i16, _>(b, $op);
|
|
})
|
|
.with_function("FixedU16", move |b| {
|
|
fixed_point_op::<U8F8, _>(b, $op);
|
|
})
|
|
.with_function("FixedI16", move |b| {
|
|
fixed_point_op::<I8F8, _>(b, $op);
|
|
})
|
|
.with_function("u8", move |b| {
|
|
primitive_op::<u8, _>(b, $op);
|
|
})
|
|
.with_function("i8", move |b| {
|
|
primitive_op::<i8, _>(b, $op);
|
|
})
|
|
.with_function("FixedU8", move |b| {
|
|
fixed_point_op::<U4F4, _>(b, $op);
|
|
})
|
|
.with_function("FixedI8", move |b| {
|
|
fixed_point_op::<I4F4, _>(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);
|