Auto merge of #119430 - NCGThompson:int-pow-bench, r=cuviper
Add Benchmarks for int_pow Methods. There is quite a bit of room for improvement in performance of the `int_pow` family of methods. I added benchmarks for those functions. In particular, there are benchmarks for small compile-time bases to measure the effect of #114390. ~~I added a lot (245), but all but 22 of them are marked with `#[ignore]`. There are a lot of macros, and I would appreciate feedback on how to simplify them.~~ ~~To run benches relevant to #114390, use `./x bench core --stage 1 -- pow_base_const --include-ignored`.~~
This commit is contained in:
commit
6029085a6f
99
library/core/benches/num/int_pow/mod.rs
Normal file
99
library/core/benches/num/int_pow/mod.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use rand::Rng;
|
||||||
|
use test::{black_box, Bencher};
|
||||||
|
|
||||||
|
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 propogate 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);
|
@ -1,6 +1,7 @@
|
|||||||
mod dec2flt;
|
mod dec2flt;
|
||||||
mod flt2dec;
|
mod flt2dec;
|
||||||
mod int_log;
|
mod int_log;
|
||||||
|
mod int_pow;
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use test::{black_box, Bencher};
|
use test::{black_box, Bencher};
|
||||||
|
@ -9,9 +9,6 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod benches;
|
|
||||||
|
|
||||||
#[stable(feature = "saturating_int_impl", since = "1.74.0")]
|
#[stable(feature = "saturating_int_impl", since = "1.74.0")]
|
||||||
pub use core::num::Saturating;
|
pub use core::num::Saturating;
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
use test::Bencher;
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
fn bench_pow_function(b: &mut Bencher) {
|
|
||||||
let v = (0..1024).collect::<Vec<u32>>();
|
|
||||||
b.iter(|| {
|
|
||||||
v.iter().fold(0u32, |old, new| old.pow(*new as u32));
|
|
||||||
});
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user