diff --git a/library/core/benches/num/int_pow/mod.rs b/library/core/benches/num/int_pow/mod.rs new file mode 100644 index 00000000000..063d722bdd1 --- /dev/null +++ b/library/core/benches/num/int_pow/mod.rs @@ -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); diff --git a/library/core/benches/num/mod.rs b/library/core/benches/num/mod.rs index b97014d9bf9..4922ee150d9 100644 --- a/library/core/benches/num/mod.rs +++ b/library/core/benches/num/mod.rs @@ -1,6 +1,7 @@ mod dec2flt; mod flt2dec; mod int_log; +mod int_pow; use std::str::FromStr; use test::{black_box, Bencher}; diff --git a/library/std/src/num.rs b/library/std/src/num.rs index 3cd5fa458e0..55f6ddcf77f 100644 --- a/library/std/src/num.rs +++ b/library/std/src/num.rs @@ -9,9 +9,6 @@ #[cfg(test)] mod tests; -#[cfg(test)] -mod benches; - #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub use core::num::Saturating; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/num/benches.rs b/library/std/src/num/benches.rs deleted file mode 100644 index 233ea0506c0..00000000000 --- a/library/std/src/num/benches.rs +++ /dev/null @@ -1,9 +0,0 @@ -use test::Bencher; - -#[bench] -fn bench_pow_function(b: &mut Bencher) { - let v = (0..1024).collect::>(); - b.iter(|| { - v.iter().fold(0u32, |old, new| old.pow(*new as u32)); - }); -}