about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/core/benches/num/int_pow/mod.rs99
-rw-r--r--library/core/benches/num/mod.rs1
-rw-r--r--library/std/src/num.rs3
-rw-r--r--library/std/src/num/benches.rs9
4 files changed, 100 insertions, 12 deletions
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::<Vec<u32>>();
-    b.iter(|| {
-        v.iter().fold(0u32, |old, new| old.pow(*new as u32));
-    });
-}