1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
|
use rand::Rng;
use test::{Bencher, black_box};
const ITERATIONS: usize = 128; // Uses an ITERATIONS * 20 Byte stack allocation
type IntType = i128; // Hardest native type to multiply
const EXPONENT_MAX: u32 = 31;
const MAX_BASE: IntType = 17; // +-17 ** 31 <= IntType::MAX
macro_rules! pow_bench_template {
($name:ident, $inner_macro:ident, $base_macro:ident) => {
#[bench]
fn $name(bench: &mut Bencher) {
// Frequent black_box calls can add latency and prevent optimizations, so for
// variable parameters we premake an array and pass the
// reference through black_box outside of the loop.
let mut rng = crate::bench_rng();
let base_array: [IntType; ITERATIONS] =
core::array::from_fn(|_| rng.gen_range((-MAX_BASE..=MAX_BASE)));
let exp_array: [u32; ITERATIONS] =
core::array::from_fn(|_| rng.gen_range((0..=EXPONENT_MAX)));
bench.iter(|| {
#[allow(unused, unused_mut)]
let mut base_iter = black_box(&base_array).into_iter();
let mut exp_iter = black_box(&exp_array).into_iter();
(0..ITERATIONS).fold((0 as IntType, false), |acc, _| {
// Sometimes constants don't propagate all the way to the
// inside of the loop, so we call a custom expression every cycle
// rather than iter::repeat(CONST)
let base: IntType = $base_macro!(base_iter);
let exp: u32 = *exp_iter.next().unwrap();
let r: (IntType, bool) = $inner_macro!(base, exp);
(acc.0 ^ r.0, acc.1 ^ r.1)
})
});
}
};
}
// This may panic if it overflows.
macro_rules! inner_pow {
($base:ident, $exp:ident) => {
($base.pow($exp), false)
};
}
macro_rules! inner_wrapping {
($base:ident, $exp:ident) => {
($base.wrapping_pow($exp), false)
};
}
macro_rules! inner_overflowing {
($base:ident, $exp:ident) => {
$base.overflowing_pow($exp)
};
}
// This will panic if it overflows.
macro_rules! inner_checked_unwrapped {
($base:ident, $exp:ident) => {
($base.checked_pow($exp).unwrap(), false)
};
}
macro_rules! inner_saturating {
($base:ident, $exp:ident) => {
($base.saturating_pow($exp), false)
};
}
macro_rules! make_const_base {
($name:ident, $x:literal) => {
macro_rules! $name {
($iter:ident) => {
$x
};
}
};
}
make_const_base!(const_base_m7, -7);
make_const_base!(const_base_m8, -8);
macro_rules! variable_base {
($iter:ident) => {
*$iter.next().unwrap()
};
}
pow_bench_template!(pow_variable, inner_pow, variable_base);
pow_bench_template!(wrapping_pow_variable, inner_wrapping, variable_base);
pow_bench_template!(overflowing_pow_variable, inner_overflowing, variable_base);
pow_bench_template!(checked_pow_variable, inner_checked_unwrapped, variable_base);
pow_bench_template!(saturating_pow_variable, inner_saturating, variable_base);
pow_bench_template!(pow_m7, inner_pow, const_base_m7);
pow_bench_template!(pow_m8, inner_pow, const_base_m8);
|