about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTrevor Gross <tmgross@umich.edu>2024-10-21 18:27:01 -0500
committerTrevor Gross <tmgross@umich.edu>2024-10-31 22:40:30 -0500
commitabff7cd82a392c48e141d5f3f09bd02869352d9b (patch)
tree4f0a13ba50f74198c572d213afb6c6d4517d791c
parentbaae082fc5227a0e7e34fcee2e441d14d0044320 (diff)
downloadrust-abff7cd82a392c48e141d5f3f09bd02869352d9b.tar.gz
rust-abff7cd82a392c48e141d5f3f09bd02869352d9b.zip
Add benchmarks against musl libm
Add a benchmark for each function that checks against `musl_math_sys`.
-rw-r--r--library/compiler-builtins/libm/crates/libm-test/Cargo.toml13
-rw-r--r--library/compiler-builtins/libm/crates/libm-test/benches/random.rs119
2 files changed, 132 insertions, 0 deletions
diff --git a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml
index 72ac57232b3..fedf745ed7f 100644
--- a/library/compiler-builtins/libm/crates/libm-test/Cargo.toml
+++ b/library/compiler-builtins/libm/crates/libm-test/Cargo.toml
@@ -15,6 +15,12 @@ test-multiprecision = ["dep:az", "dep:rug"]
 # Build our own musl for testing and benchmarks
 build-musl = ["dep:musl-math-sys"]
 
+# Enable report generation without bringing in more dependencies by default
+benchmarking-reports = ["criterion/plotters", "criterion/html_reports"]
+
+# Run with a reduced set of benchmarks, such as for CI
+short-benchmarks = []
+
 [dependencies]
 anyhow = "1.0.90"
 az = { version = "1.2.1", optional = true }
@@ -32,3 +38,10 @@ getrandom = { version = "0.2", features = ["js"] }
 
 [build-dependencies]
 rand = { version = "0.8.5", optional = true }
+
+[dev-dependencies]
+criterion = { version = "0.5.1", default-features = false, features = ["cargo_bench_support"] }
+
+[[bench]]
+name = "random"
+harness = false
diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs
new file mode 100644
index 00000000000..6c9047c3cdb
--- /dev/null
+++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs
@@ -0,0 +1,119 @@
+use std::hint::black_box;
+use std::time::Duration;
+
+use criterion::{Criterion, criterion_main};
+use libm_test::gen::random;
+use libm_test::{CheckBasis, CheckCtx, TupleCall};
+
+/// Benchmark with this many items to get a variety
+const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 };
+
+macro_rules! musl_rand_benches {
+    (
+        fn_name: $fn_name:ident,
+        CFn: $CFn:ty,
+        CArgs: $CArgs:ty,
+        CRet: $CRet:ty,
+        RustFn: $RustFn:ty,
+        RustArgs: $RustArgs:ty,
+        RustRet: $RustRet:ty,
+        fn_extra: $skip_on_i586:expr,
+    ) => {
+        paste::paste! {
+            fn [< musl_bench_ $fn_name >](c: &mut Criterion) {
+                let fn_name = stringify!($fn_name);
+
+                let ulp = libm_test::musl_allowed_ulp(fn_name);
+                let ctx = CheckCtx::new(ulp, fn_name, CheckBasis::Musl);
+                let benchvec: Vec<_> = random::get_test_cases::<$RustArgs>(&ctx)
+                    .take(BENCH_ITER_ITEMS)
+                    .collect();
+
+                // Perform a sanity check that we are benchmarking the same thing
+                // Don't test against musl if it is not available
+                #[cfg(feature = "build-musl")]
+                for input in benchvec.iter().copied() {
+                    use anyhow::Context;
+                    use libm_test::{CheckBasis, CheckCtx, CheckOutput};
+
+                    if cfg!(x86_no_sse) && $skip_on_i586 {
+                        break;
+                    }
+
+                    let musl_res = input.call(musl_math_sys::$fn_name as $CFn);
+                    let crate_res = input.call(libm::$fn_name as $RustFn);
+
+                    let ctx = CheckCtx::new(ulp, fn_name, CheckBasis::Musl);
+                    crate_res.validate(musl_res, input, &ctx).context(fn_name).unwrap();
+                }
+
+                /* Function pointers are black boxed to avoid inlining in the benchmark loop */
+
+                let mut group = c.benchmark_group(fn_name);
+                group.bench_function("crate", |b| b.iter(|| {
+                    let f = black_box(libm::$fn_name as $RustFn);
+                    for input in benchvec.iter().copied() {
+                        input.call(f);
+                    }
+                }));
+
+                // Don't test against musl if it is not available
+                #[cfg(feature = "build-musl")]
+                group.bench_function("musl", |b| b.iter(|| {
+                    let f = black_box(musl_math_sys::$fn_name as $CFn);
+                    for input in benchvec.iter().copied() {
+                        input.call(f);
+                    }
+                }));
+            }
+        }
+    };
+}
+
+libm_macros::for_each_function! {
+    callback: musl_rand_benches,
+    skip: [],
+    fn_extra: match MACRO_FN_NAME {
+        // FIXME(correctness): wrong result on i586
+        exp10 | exp10f | exp2 | exp2f => true,
+        _ => false
+    }
+}
+
+macro_rules! run_callback {
+    (
+        fn_name: $fn_name:ident,
+        CFn: $_CFn:ty,
+        CArgs: $_CArgs:ty,
+        CRet: $_CRet:ty,
+        RustFn: $_RustFn:ty,
+        RustArgs: $_RustArgs:ty,
+        RustRet: $_RustRet:ty,
+        extra: [$criterion:ident],
+    ) => {
+        paste::paste! {
+            [< musl_bench_ $fn_name >](&mut $criterion)
+        }
+    };
+}
+
+pub fn musl_random() {
+    let mut criterion = Criterion::default();
+
+    // For CI, run a short 0.5s warmup and 1.0s tests. This makes benchmarks complete in
+    // about the same time as other tests.
+    if cfg!(feature = "short-benchmarks") {
+        criterion = criterion
+            .warm_up_time(Duration::from_millis(500))
+            .measurement_time(Duration::from_millis(1000));
+    }
+
+    criterion = criterion.configure_from_args();
+
+    libm_macros::for_each_function! {
+        callback: run_callback,
+        extra: [criterion],
+    };
+}
+
+criterion_main!(musl_random);