From cb5caad68f996b28803cbcdabdefdfae6f437f00 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 13 May 2026 06:42:48 +0000 Subject: [PATCH 1/2] chore(ndarray): migrate benches off nightly #![feature(test)] to criterion 0.5 + Tier A clippy fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User directive: stable Rust 1.94.1 only — no nightly features anywhere. The bench tests used #![feature(test)] + extern crate test + #[bench] (unstable libtest_bench framework), blocking CI on stable. Migrated all 13 benches to criterion 0.5 (already established workspace pattern via crates/p64 + crates/phyllotactic-manifold). Files migrated (10 source files; append.rs/construct.rs/numeric.rs were already criterion-based; Cargo.toml + ndarray-rand/Cargo.toml had the [[bench]] + criterion dev-dep prep already in working tree): benches/bench1.rs (1106 LOC, ~80 #[bench] fns + mat_mul! macro) benches/iter.rs (436 LOC, ~30 #[bench] fns) benches/par_rayon.rs (182 LOC, rayon-feature-gated) benches/zip.rs (133 LOC) benches/to_shape.rs (95 LOC) benches/higher-order.rs (93 LOC) benches/chunks.rs (87 LOC) benches/gemv_gemm.rs (75 LOC) benches/reserve.rs (31 LOC) ndarray-rand/benches/bench.rs (31 LOC) Mechanical conversion pattern: BEFORE: #[bench] fn name(b: &mut Bencher) { b.iter(|| ...); } AFTER: fn name(c: &mut Criterion) { c.bench_function("name", |b| b.iter(|| ...)); } criterion_group!(benches, name1, name2, ...); criterion_main!(benches); Bench function names preserved exactly so `cargo bench --bench foo name` keeps working. Wrapped inputs with criterion's black_box where the original used test::black_box. Special handling: - bench1.rs's mat_mul! macro now generates pub fn $name(c: &mut Criterion) inside each module + a pub fn group(c) that calls them all. Top-level criterion_group!(matmul_benches, mat_mul_f32::group, ...) registers all 30 generated benches. - bench1.rs split into 11 criterion_groups (iter/sum/add/scalar/ add_strided/iadd_scalar/iter_misc/dot/dimensionality/matmul/std) for readability; criterion_main! aggregates them all. - iter.rs splits #[cfg(feature = "std")] benches into a separate criterion_group with conditional criterion_main! inclusion. Tier A clippy fixes (per user request to ship clean): - examples/life.rs:1 + tests/assign.rs:1 + tests/array.rs:1 + benches/bench1.rs:1 + benches/iter.rs:1 — added #[allow(clippy::reversed_empty_ranges)] for the s![1..-1, ..] Python-style negative-indexing macro pattern (false positive — clippy can't see through s! macro). - tests/oper.rs:300 — replaced unsafe Vec::with_capacity + set_len uninit pattern with proper MaybeUninit::uninit + write per slot + ManuallyDrop transmute. SAFETY comments document each unsafe block. Verification (per user "use clippy not check"): cargo clippy --benches --tests --examples --features rayon --no-deps → 0 errors in benches/tests/examples (down from 18+). 5 pre-existing lib code errors remain (NOT introduced here, NOT in scope for this commit): - src/hpc/quantized.rs:431 + src/hpc/blackboard.rs:484-485 + src/hpc/jitson/parser.rs:487 — clippy::approx_constant (literal PI values; should use std::f{32,64}::consts::PI) - src/hpc/renderer.rs:428 — clippy::absurd_extreme_comparisons These are lib-level tech debt visible to `cargo clippy --lib` and require separate fix commits. --- Cargo.lock | 2 + Cargo.toml | 50 ++ benches/append.rs | 34 +- benches/bench1.rs | 1053 +++++++++++++++++++-------------- benches/chunks.rs | 97 +-- benches/construct.rs | 42 +- benches/gemv_gemm.rs | 53 +- benches/higher-order.rs | 71 ++- benches/iter.rs | 450 ++++++++------ benches/numeric.rs | 36 +- benches/par_rayon.rs | 169 +++--- benches/reserve.rs | 41 +- benches/to_shape.rs | 99 ++-- benches/zip.rs | 69 +-- examples/life.rs | 11 +- ndarray-rand/Cargo.toml | 5 + ndarray-rand/benches/bench.rs | 31 +- tests/array.rs | 4 + tests/assign.rs | 5 + tests/oper.rs | 20 +- 20 files changed, 1387 insertions(+), 955 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac5379bc..23abfa50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2055,6 +2055,7 @@ dependencies = [ "cranelift-frontend", "cranelift-jit", "cranelift-module", + "criterion", "defmac", "itertools 0.13.0", "libc", @@ -2086,6 +2087,7 @@ dependencies = [ name = "ndarray-rand" version = "0.16.0" dependencies = [ + "criterion", "ndarray", "quickcheck", "rand 0.9.2", diff --git a/Cargo.toml b/Cargo.toml index 870271e5..c3e82afb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,6 +71,56 @@ quickcheck = { workspace = true } approx = { workspace = true, default-features = true } itertools = { workspace = true } ndarray-gen = { workspace = true } +criterion = { version = "0.5", features = ["html_reports"] } + +[[bench]] +name = "append" +harness = false + +[[bench]] +name = "bench1" +harness = false + +[[bench]] +name = "chunks" +harness = false + +[[bench]] +name = "construct" +harness = false + +[[bench]] +name = "gemv_gemm" +harness = false + +[[bench]] +name = "higher-order" +harness = false + +[[bench]] +name = "iter" +harness = false + +[[bench]] +name = "numeric" +harness = false + +[[bench]] +name = "par_rayon" +harness = false +required-features = ["rayon"] + +[[bench]] +name = "reserve" +harness = false + +[[bench]] +name = "to_shape" +harness = false + +[[bench]] +name = "zip" +harness = false [features] default = ["std"] diff --git a/benches/append.rs b/benches/append.rs index a37df256..aecb60cf 100644 --- a/benches/append.rs +++ b/benches/append.rs @@ -1,32 +1,30 @@ -#![feature(test)] - -extern crate test; -use test::Bencher; - +use criterion::{black_box, criterion_group, criterion_main, Criterion}; use ndarray::prelude::*; -#[bench] -fn select_axis0(bench: &mut Bencher) -{ +fn select_axis0(c: &mut Criterion) { let a = Array::::zeros((256, 256)); let selectable = vec![0, 1, 2, 0, 1, 3, 0, 4, 16, 32, 128, 147, 149, 220, 221, 255, 221, 0, 1]; - bench.iter(|| a.select(Axis(0), &selectable)); + c.bench_function("select_axis0", |b| { + b.iter(|| black_box(&a).select(Axis(0), black_box(&selectable))) + }); } -#[bench] -fn select_axis1(bench: &mut Bencher) -{ +fn select_axis1(c: &mut Criterion) { let a = Array::::zeros((256, 256)); let selectable = vec![0, 1, 2, 0, 1, 3, 0, 4, 16, 32, 128, 147, 149, 220, 221, 255, 221, 0, 1]; - bench.iter(|| a.select(Axis(1), &selectable)); + c.bench_function("select_axis1", |b| { + b.iter(|| black_box(&a).select(Axis(1), black_box(&selectable))) + }); } -#[bench] -fn select_1d(bench: &mut Bencher) -{ +fn select_1d(c: &mut Criterion) { let a = Array::::zeros(1024); let mut selectable = (0..a.len()).step_by(17).collect::>(); selectable.extend(selectable.clone().iter().rev()); - - bench.iter(|| a.select(Axis(0), &selectable)); + c.bench_function("select_1d", |b| { + b.iter(|| black_box(&a).select(Axis(0), black_box(&selectable))) + }); } + +criterion_group!(benches, select_axis0, select_axis1, select_1d); +criterion_main!(benches); diff --git a/benches/bench1.rs b/benches/bench1.rs index 3b540532..e06676d5 100644 --- a/benches/bench1.rs +++ b/benches/bench1.rs @@ -1,813 +1,845 @@ -#![feature(test)] +// `s![1..-1, 1..-1]` — ndarray's `s!` macro uses Python-style negative +// indexing. Clippy can't see through the macro and reads `1..-1` as a +// plain (empty) Rust range; the actual semantics are correct. #![allow(unused_imports)] -#![allow(clippy::many_single_char_names, clippy::deref_addrof, clippy::unreadable_literal)] - -extern crate test; +#![allow(clippy::many_single_char_names, clippy::deref_addrof, clippy::unreadable_literal, clippy::reversed_empty_ranges)] use std::mem::MaybeUninit; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; use ndarray::{arr0, arr1, arr2, azip, s}; use ndarray::{Array, Array1, Array2, Axis, Ix, Zip}; use ndarray::{Array3, Array4, ShapeBuilder}; use ndarray::{Ix1, Ix2, Ix3, Ix5, IxDyn}; -use test::black_box; - -#[bench] -fn iter_sum_1d_regular(bench: &mut test::Bencher) +fn iter_sum_1d_regular(c: &mut Criterion) { let a = Array::::zeros(64 * 64); let a = black_box(a); - bench.iter(|| { - let mut sum = 0; - for &elt in a.iter() { - sum += elt; - } - sum + c.bench_function("iter_sum_1d_regular", |bn| { + bn.iter(|| { + let mut sum = 0; + for &elt in a.iter() { + sum += elt; + } + sum + }) }); } -#[bench] -fn iter_sum_1d_raw(bench: &mut test::Bencher) +fn iter_sum_1d_raw(c: &mut Criterion) { - // this is autovectorized to death (= great performance) let a = Array::::zeros(64 * 64); let a = black_box(a); - bench.iter(|| { - let mut sum = 0; - for &elt in a.as_slice_memory_order().unwrap() { - sum += elt; - } - sum + c.bench_function("iter_sum_1d_raw", |bn| { + bn.iter(|| { + let mut sum = 0; + for &elt in a.as_slice_memory_order().unwrap() { + sum += elt; + } + sum + }) }); } -#[bench] -fn iter_sum_2d_regular(bench: &mut test::Bencher) +fn iter_sum_2d_regular(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let a = black_box(a); - bench.iter(|| { - let mut sum = 0; - for &elt in a.iter() { - sum += elt; - } - sum + c.bench_function("iter_sum_2d_regular", |bn| { + bn.iter(|| { + let mut sum = 0; + for &elt in a.iter() { + sum += elt; + } + sum + }) }); } -#[bench] -fn iter_sum_2d_by_row(bench: &mut test::Bencher) +fn iter_sum_2d_by_row(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let a = black_box(a); - bench.iter(|| { - let mut sum = 0; - for row in a.rows() { - for &elt in row { - sum += elt; + c.bench_function("iter_sum_2d_by_row", |bn| { + bn.iter(|| { + let mut sum = 0; + for row in a.rows() { + for &elt in row { + sum += elt; + } } - } - sum + sum + }) }); } -#[bench] -fn iter_sum_2d_raw(bench: &mut test::Bencher) +fn iter_sum_2d_raw(c: &mut Criterion) { - // this is autovectorized to death (= great performance) let a = Array::::zeros((64, 64)); let a = black_box(a); - bench.iter(|| { - let mut sum = 0; - for &elt in a.as_slice_memory_order().unwrap() { - sum += elt; - } - sum + c.bench_function("iter_sum_2d_raw", |bn| { + bn.iter(|| { + let mut sum = 0; + for &elt in a.as_slice_memory_order().unwrap() { + sum += elt; + } + sum + }) }); } -#[bench] -fn iter_sum_2d_cutout(bench: &mut test::Bencher) +fn iter_sum_2d_cutout(c: &mut Criterion) { let a = Array::::zeros((66, 66)); let av = a.slice(s![1..-1, 1..-1]); let a = black_box(av); - bench.iter(|| { - let mut sum = 0; - for &elt in a.iter() { - sum += elt; - } - sum + c.bench_function("iter_sum_2d_cutout", |bn| { + bn.iter(|| { + let mut sum = 0; + for &elt in a.iter() { + sum += elt; + } + sum + }) }); } -#[bench] -fn iter_sum_2d_cutout_by_row(bench: &mut test::Bencher) +fn iter_sum_2d_cutout_by_row(c: &mut Criterion) { let a = Array::::zeros((66, 66)); let av = a.slice(s![1..-1, 1..-1]); let a = black_box(av); - bench.iter(|| { - let mut sum = 0; - for row in 0..a.shape()[0] { - for &elt in a.row(row) { - sum += elt; + c.bench_function("iter_sum_2d_cutout_by_row", |bn| { + bn.iter(|| { + let mut sum = 0; + for row in 0..a.shape()[0] { + for &elt in a.row(row) { + sum += elt; + } } - } - sum + sum + }) }); } -#[bench] -fn iter_sum_2d_cutout_outer_iter(bench: &mut test::Bencher) +fn iter_sum_2d_cutout_outer_iter(c: &mut Criterion) { let a = Array::::zeros((66, 66)); let av = a.slice(s![1..-1, 1..-1]); let a = black_box(av); - bench.iter(|| { - let mut sum = 0; - for row in a.rows() { - for &elt in row { - sum += elt; + c.bench_function("iter_sum_2d_cutout_outer_iter", |bn| { + bn.iter(|| { + let mut sum = 0; + for row in a.rows() { + for &elt in row { + sum += elt; + } } - } - sum + sum + }) }); } -#[bench] -fn iter_sum_2d_transpose_regular(bench: &mut test::Bencher) +fn iter_sum_2d_transpose_regular(c: &mut Criterion) { let mut a = Array::::zeros((64, 64)); a.swap_axes(0, 1); let a = black_box(a); - bench.iter(|| { - let mut sum = 0; - for &elt in a.iter() { - sum += elt; - } - sum + c.bench_function("iter_sum_2d_transpose_regular", |bn| { + bn.iter(|| { + let mut sum = 0; + for &elt in a.iter() { + sum += elt; + } + sum + }) }); } -#[bench] -fn iter_sum_2d_transpose_by_row(bench: &mut test::Bencher) +fn iter_sum_2d_transpose_by_row(c: &mut Criterion) { let mut a = Array::::zeros((64, 64)); a.swap_axes(0, 1); let a = black_box(a); - bench.iter(|| { - let mut sum = 0; - for row in 0..a.shape()[0] { - for &elt in a.row(row) { - sum += elt; + c.bench_function("iter_sum_2d_transpose_by_row", |bn| { + bn.iter(|| { + let mut sum = 0; + for row in 0..a.shape()[0] { + for &elt in a.row(row) { + sum += elt; + } } - } - sum + sum + }) }); } -#[bench] -fn sum_2d_regular(bench: &mut test::Bencher) +fn sum_2d_regular(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let a = black_box(a); - bench.iter(|| a.sum()); + c.bench_function("sum_2d_regular", |bn| bn.iter(|| a.sum())); } -#[bench] -fn sum_2d_cutout(bench: &mut test::Bencher) +fn sum_2d_cutout(c: &mut Criterion) { let a = Array::::zeros((66, 66)); let av = a.slice(s![1..-1, 1..-1]); let a = black_box(av); - bench.iter(|| a.sum()); + c.bench_function("sum_2d_cutout", |bn| bn.iter(|| a.sum())); } -#[bench] -fn sum_2d_float(bench: &mut test::Bencher) +fn sum_2d_float(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let a = black_box(a.view()); - bench.iter(|| a.sum()); + c.bench_function("sum_2d_float", |bn| bn.iter(|| a.sum())); } -#[bench] -fn sum_2d_float_cutout(bench: &mut test::Bencher) +fn sum_2d_float_cutout(c: &mut Criterion) { let a = Array::::zeros((66, 66)); let av = a.slice(s![1..-1, 1..-1]); let a = black_box(av); - bench.iter(|| a.sum()); + c.bench_function("sum_2d_float_cutout", |bn| bn.iter(|| a.sum())); } -#[bench] -fn sum_2d_float_t_cutout(bench: &mut test::Bencher) +fn sum_2d_float_t_cutout(c: &mut Criterion) { let a = Array::::zeros((66, 66)); let av = a.slice(s![1..-1, 1..-1]).reversed_axes(); let a = black_box(av); - bench.iter(|| a.sum()); + c.bench_function("sum_2d_float_t_cutout", |bn| bn.iter(|| a.sum())); } -#[bench] -fn fold_sum_i32_2d_regular(bench: &mut test::Bencher) +fn fold_sum_i32_2d_regular(c: &mut Criterion) { let a = Array::::zeros((64, 64)); - bench.iter(|| a.fold(0, |acc, &x| acc + x)); + c.bench_function("fold_sum_i32_2d_regular", |bn| { + bn.iter(|| a.fold(0, |acc, &x| acc + x)) + }); } -#[bench] -fn fold_sum_i32_2d_cutout(bench: &mut test::Bencher) +fn fold_sum_i32_2d_cutout(c: &mut Criterion) { let a = Array::::zeros((66, 66)); let av = a.slice(s![1..-1, 1..-1]); let a = black_box(av); - bench.iter(|| a.fold(0, |acc, &x| acc + x)); + c.bench_function("fold_sum_i32_2d_cutout", |bn| { + bn.iter(|| a.fold(0, |acc, &x| acc + x)) + }); } -#[bench] -fn fold_sum_i32_2d_stride(bench: &mut test::Bencher) +fn fold_sum_i32_2d_stride(c: &mut Criterion) { let a = Array::::zeros((64, 128)); let av = a.slice(s![.., ..;2]); let a = black_box(av); - bench.iter(|| a.fold(0, |acc, &x| acc + x)); + c.bench_function("fold_sum_i32_2d_stride", |bn| { + bn.iter(|| a.fold(0, |acc, &x| acc + x)) + }); } -#[bench] -fn fold_sum_i32_2d_transpose(bench: &mut test::Bencher) +fn fold_sum_i32_2d_transpose(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let a = a.t(); - bench.iter(|| a.fold(0, |acc, &x| acc + x)); + c.bench_function("fold_sum_i32_2d_transpose", |bn| { + bn.iter(|| a.fold(0, |acc, &x| acc + x)) + }); } -#[bench] -fn fold_sum_i32_2d_cutout_transpose(bench: &mut test::Bencher) +fn fold_sum_i32_2d_cutout_transpose(c: &mut Criterion) { let a = Array::::zeros((66, 66)); let mut av = a.slice(s![1..-1, 1..-1]); av.swap_axes(0, 1); let a = black_box(av); - bench.iter(|| a.fold(0, |acc, &x| acc + x)); + c.bench_function("fold_sum_i32_2d_cutout_transpose", |bn| { + bn.iter(|| a.fold(0, |acc, &x| acc + x)) + }); } const ADD2DSZ: usize = 64; -#[bench] -fn add_2d_regular(bench: &mut test::Bencher) +fn add_2d_regular(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ)); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); let bv = b.view(); - bench.iter(|| { - a += &bv; + c.bench_function("add_2d_regular", |bn| { + bn.iter(|| { + a += &bv; + }) }); } -#[bench] -fn add_2d_zip(bench: &mut test::Bencher) +fn add_2d_zip(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ)); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); - bench.iter(|| { - Zip::from(&mut a).and(&b).for_each(|a, &b| *a += b); + c.bench_function("add_2d_zip", |bn| { + bn.iter(|| { + Zip::from(&mut a).and(&b).for_each(|a, &b| *a += b); + }) }); } -#[bench] -fn add_2d_alloc_plus(bench: &mut test::Bencher) +fn add_2d_alloc_plus(c: &mut Criterion) { let a = Array::::zeros((ADD2DSZ, ADD2DSZ)); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); - bench.iter(|| &a + &b); + c.bench_function("add_2d_alloc_plus", |bn| bn.iter(|| &a + &b)); } -#[bench] -fn add_2d_alloc_zip_uninit(bench: &mut test::Bencher) +fn add_2d_alloc_zip_uninit(c: &mut Criterion) { let a = Array::::zeros((ADD2DSZ, ADD2DSZ)); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); - bench.iter(|| unsafe { - let mut c = Array::::uninit(a.dim()); - azip!((&a in &a, &b in &b, c in c.raw_view_mut().cast::()) - c.write(a + b) - ); - c + c.bench_function("add_2d_alloc_zip_uninit", |bn| { + bn.iter(|| unsafe { + let mut c_arr = Array::::uninit(a.dim()); + azip!((&a in &a, &b in &b, c in c_arr.raw_view_mut().cast::()) + c.write(a + b) + ); + c_arr + }) }); } -#[bench] -fn add_2d_alloc_zip_collect(bench: &mut test::Bencher) +fn add_2d_alloc_zip_collect(c: &mut Criterion) { let a = Array::::zeros((ADD2DSZ, ADD2DSZ)); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); - bench.iter(|| Zip::from(&a).and(&b).map_collect(|&x, &y| x + y)); + c.bench_function("add_2d_alloc_zip_collect", |bn| { + bn.iter(|| Zip::from(&a).and(&b).map_collect(|&x, &y| x + y)) + }); } -#[bench] -fn vec_string_collect(bench: &mut test::Bencher) +fn vec_string_collect(c: &mut Criterion) { let v = vec![""; 10240]; - bench.iter(|| v.iter().map(|s| s.to_owned()).collect::>()); + c.bench_function("vec_string_collect", |bn| { + bn.iter(|| v.iter().map(|s| s.to_owned()).collect::>()) + }); } -#[bench] -fn array_string_collect(bench: &mut test::Bencher) +fn array_string_collect(c: &mut Criterion) { let v = Array::from(vec![""; 10240]); - bench.iter(|| Zip::from(&v).map_collect(|s| s.to_owned())); + c.bench_function("array_string_collect", |bn| { + bn.iter(|| Zip::from(&v).map_collect(|s| s.to_owned())) + }); } -#[bench] -fn vec_f64_collect(bench: &mut test::Bencher) +fn vec_f64_collect(c: &mut Criterion) { let v = vec![1.; 10240]; - bench.iter(|| v.iter().map(|s| s + 1.).collect::>()); + c.bench_function("vec_f64_collect", |bn| { + bn.iter(|| v.iter().map(|s| s + 1.).collect::>()) + }); } -#[bench] -fn array_f64_collect(bench: &mut test::Bencher) +fn array_f64_collect(c: &mut Criterion) { let v = Array::from(vec![1.; 10240]); - bench.iter(|| Zip::from(&v).map_collect(|s| s + 1.)); + c.bench_function("array_f64_collect", |bn| { + bn.iter(|| Zip::from(&v).map_collect(|s| s + 1.)) + }); } -#[bench] -fn add_2d_assign_ops(bench: &mut test::Bencher) +fn add_2d_assign_ops(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ)); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); let bv = b.view(); - bench.iter(|| { - let mut x = a.view_mut(); - x += &bv; - black_box(x); + c.bench_function("add_2d_assign_ops", |bn| { + bn.iter(|| { + let mut x = a.view_mut(); + x += &bv; + black_box(x); + }) }); } -#[bench] -fn add_2d_cutout(bench: &mut test::Bencher) +fn add_2d_cutout(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ + 2, ADD2DSZ + 2)); let mut acut = a.slice_mut(s![1..-1, 1..-1]); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); let bv = b.view(); - bench.iter(|| { - acut += &bv; + c.bench_function("add_2d_cutout", |bn| { + bn.iter(|| { + acut += &bv; + }) }); } -#[bench] -fn add_2d_zip_cutout(bench: &mut test::Bencher) +fn add_2d_zip_cutout(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ + 2, ADD2DSZ + 2)); let mut acut = a.slice_mut(s![1..-1, 1..-1]); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); - bench.iter(|| { - Zip::from(&mut acut).and(&b).for_each(|a, &b| *a += b); + c.bench_function("add_2d_zip_cutout", |bn| { + bn.iter(|| { + Zip::from(&mut acut).and(&b).for_each(|a, &b| *a += b); + }) }); } -#[bench] #[allow(clippy::identity_op)] -fn add_2d_cutouts_by_4(bench: &mut test::Bencher) +fn add_2d_cutouts_by_4(c: &mut Criterion) { let mut a = Array::::zeros((64 * 1, 64 * 1)); let b = Array::::zeros((64 * 1, 64 * 1)); let chunksz = (4, 4); - bench.iter(|| { - Zip::from(a.exact_chunks_mut(chunksz)) - .and(b.exact_chunks(chunksz)) - .for_each(|mut a, b| a += &b); + c.bench_function("add_2d_cutouts_by_4", |bn| { + bn.iter(|| { + Zip::from(a.exact_chunks_mut(chunksz)) + .and(b.exact_chunks(chunksz)) + .for_each(|mut a, b| a += &b); + }) }); } -#[bench] #[allow(clippy::identity_op)] -fn add_2d_cutouts_by_16(bench: &mut test::Bencher) +fn add_2d_cutouts_by_16(c: &mut Criterion) { let mut a = Array::::zeros((64 * 1, 64 * 1)); let b = Array::::zeros((64 * 1, 64 * 1)); let chunksz = (16, 16); - bench.iter(|| { - Zip::from(a.exact_chunks_mut(chunksz)) - .and(b.exact_chunks(chunksz)) - .for_each(|mut a, b| a += &b); + c.bench_function("add_2d_cutouts_by_16", |bn| { + bn.iter(|| { + Zip::from(a.exact_chunks_mut(chunksz)) + .and(b.exact_chunks(chunksz)) + .for_each(|mut a, b| a += &b); + }) }); } -#[bench] #[allow(clippy::identity_op)] -fn add_2d_cutouts_by_32(bench: &mut test::Bencher) +fn add_2d_cutouts_by_32(c: &mut Criterion) { let mut a = Array::::zeros((64 * 1, 64 * 1)); let b = Array::::zeros((64 * 1, 64 * 1)); let chunksz = (32, 32); - bench.iter(|| { - Zip::from(a.exact_chunks_mut(chunksz)) - .and(b.exact_chunks(chunksz)) - .for_each(|mut a, b| a += &b); + c.bench_function("add_2d_cutouts_by_32", |bn| { + bn.iter(|| { + Zip::from(a.exact_chunks_mut(chunksz)) + .and(b.exact_chunks(chunksz)) + .for_each(|mut a, b| a += &b); + }) }); } -#[bench] -fn add_2d_broadcast_1_to_2(bench: &mut test::Bencher) +fn add_2d_broadcast_1_to_2(c: &mut Criterion) { let mut a = Array2::::zeros((ADD2DSZ, ADD2DSZ)); let b = Array1::::zeros(ADD2DSZ); let bv = b.view(); - bench.iter(|| { - a += &bv; + c.bench_function("add_2d_broadcast_1_to_2", |bn| { + bn.iter(|| { + a += &bv; + }) }); } -#[bench] -fn add_2d_broadcast_0_to_2(bench: &mut test::Bencher) +fn add_2d_broadcast_0_to_2(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ)); let b = Array::::zeros(()); let bv = b.view(); - bench.iter(|| { - a += &bv; + c.bench_function("add_2d_broadcast_0_to_2", |bn| { + bn.iter(|| { + a += &bv; + }) }); } -#[bench] -fn scalar_toowned(bench: &mut test::Bencher) +fn scalar_toowned(c: &mut Criterion) { let a = Array::::zeros((64, 64)); - bench.iter(|| a.to_owned()); + c.bench_function("scalar_toowned", |bn| bn.iter(|| a.to_owned())); } -#[bench] -fn scalar_add_1(bench: &mut test::Bencher) +fn scalar_add_1(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let n = 1.; - bench.iter(|| &a + n); + c.bench_function("scalar_add_1", |bn| bn.iter(|| &a + n)); } -#[bench] -fn scalar_add_2(bench: &mut test::Bencher) +fn scalar_add_2(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let n = 1.; - bench.iter(|| n + &a); + c.bench_function("scalar_add_2", |bn| bn.iter(|| n + &a)); } -#[bench] -fn scalar_add_strided_1(bench: &mut test::Bencher) +fn scalar_add_strided_1(c: &mut Criterion) { let a = Array::from_shape_fn((64, 64 * 2), |(i, j)| (i * 64 + j) as f32).slice_move(s![.., ..;2]); let n = 1.; - bench.iter(|| &a + n); + c.bench_function("scalar_add_strided_1", |bn| bn.iter(|| &a + n)); } -#[bench] -fn scalar_add_strided_2(bench: &mut test::Bencher) +fn scalar_add_strided_2(c: &mut Criterion) { let a = Array::from_shape_fn((64, 64 * 2), |(i, j)| (i * 64 + j) as f32).slice_move(s![.., ..;2]); let n = 1.; - bench.iter(|| n + &a); + c.bench_function("scalar_add_strided_2", |bn| bn.iter(|| n + &a)); } -#[bench] -fn scalar_sub_1(bench: &mut test::Bencher) +fn scalar_sub_1(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let n = 1.; - bench.iter(|| &a - n); + c.bench_function("scalar_sub_1", |bn| bn.iter(|| &a - n)); } -#[bench] -fn scalar_sub_2(bench: &mut test::Bencher) +fn scalar_sub_2(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let n = 1.; - bench.iter(|| n - &a); + c.bench_function("scalar_sub_2", |bn| bn.iter(|| n - &a)); } -// This is for comparison with add_2d_broadcast_0_to_2 -#[bench] -fn add_2d_0_to_2_iadd_scalar(bench: &mut test::Bencher) +fn add_2d_0_to_2_iadd_scalar(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ)); let n = black_box(0); - bench.iter(|| { - a += n; + c.bench_function("add_2d_0_to_2_iadd_scalar", |bn| { + bn.iter(|| { + a += n; + }) }); } -#[bench] -fn add_2d_strided(bench: &mut test::Bencher) +fn add_2d_strided(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ * 2)); let mut a = a.slice_mut(s![.., ..;2]); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); let bv = b.view(); - bench.iter(|| { - a += &bv; + c.bench_function("add_2d_strided", |bn| { + bn.iter(|| { + a += &bv; + }) }); } -#[bench] -fn add_2d_regular_dyn(bench: &mut test::Bencher) +fn add_2d_regular_dyn(c: &mut Criterion) { let mut a = Array::::zeros(&[ADD2DSZ, ADD2DSZ][..]); let b = Array::::zeros(&[ADD2DSZ, ADD2DSZ][..]); let bv = b.view(); - bench.iter(|| { - a += &bv; + c.bench_function("add_2d_regular_dyn", |bn| { + bn.iter(|| { + a += &bv; + }) }); } -#[bench] -fn add_2d_strided_dyn(bench: &mut test::Bencher) +fn add_2d_strided_dyn(c: &mut Criterion) { let mut a = Array::::zeros(&[ADD2DSZ, ADD2DSZ * 2][..]); let mut a = a.slice_mut(s![.., ..;2]); let b = Array::::zeros(&[ADD2DSZ, ADD2DSZ][..]); let bv = b.view(); - bench.iter(|| { - a += &bv; + c.bench_function("add_2d_strided_dyn", |bn| { + bn.iter(|| { + a += &bv; + }) }); } -#[bench] -fn add_2d_zip_strided(bench: &mut test::Bencher) +fn add_2d_zip_strided(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ * 2)); let mut a = a.slice_mut(s![.., ..;2]); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); - bench.iter(|| { - Zip::from(&mut a).and(&b).for_each(|a, &b| *a += b); + c.bench_function("add_2d_zip_strided", |bn| { + bn.iter(|| { + Zip::from(&mut a).and(&b).for_each(|a, &b| *a += b); + }) }); } -#[bench] -fn add_2d_one_transposed(bench: &mut test::Bencher) +fn add_2d_one_transposed(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ)); a.swap_axes(0, 1); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); - bench.iter(|| { - a += &b; + c.bench_function("add_2d_one_transposed", |bn| { + bn.iter(|| { + a += &b; + }) }); } -#[bench] -fn add_2d_zip_one_transposed(bench: &mut test::Bencher) +fn add_2d_zip_one_transposed(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ)); a.swap_axes(0, 1); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); - bench.iter(|| { - Zip::from(&mut a).and(&b).for_each(|a, &b| *a += b); + c.bench_function("add_2d_zip_one_transposed", |bn| { + bn.iter(|| { + Zip::from(&mut a).and(&b).for_each(|a, &b| *a += b); + }) }); } -#[bench] -fn add_2d_both_transposed(bench: &mut test::Bencher) +fn add_2d_both_transposed(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ)); a.swap_axes(0, 1); let mut b = Array::::zeros((ADD2DSZ, ADD2DSZ)); b.swap_axes(0, 1); - bench.iter(|| { - a += &b; + c.bench_function("add_2d_both_transposed", |bn| { + bn.iter(|| { + a += &b; + }) }); } -#[bench] -fn add_2d_zip_both_transposed(bench: &mut test::Bencher) +fn add_2d_zip_both_transposed(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ)); a.swap_axes(0, 1); let mut b = Array::::zeros((ADD2DSZ, ADD2DSZ)); b.swap_axes(0, 1); - bench.iter(|| { - Zip::from(&mut a).and(&b).for_each(|a, &b| *a += b); + c.bench_function("add_2d_zip_both_transposed", |bn| { + bn.iter(|| { + Zip::from(&mut a).and(&b).for_each(|a, &b| *a += b); + }) }); } -#[bench] -fn add_2d_f32_regular(bench: &mut test::Bencher) +fn add_2d_f32_regular(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ)); let b = Array::::zeros((ADD2DSZ, ADD2DSZ)); let bv = b.view(); - bench.iter(|| { - a += &bv; + c.bench_function("add_2d_f32_regular", |bn| { + bn.iter(|| { + a += &bv; + }) }); } const ADD3DSZ: usize = 16; -#[bench] -fn add_3d_strided(bench: &mut test::Bencher) +fn add_3d_strided(c: &mut Criterion) { let mut a = Array::::zeros((ADD3DSZ, ADD3DSZ, ADD3DSZ * 2)); let mut a = a.slice_mut(s![.., .., ..;2]); let b = Array::::zeros(a.dim()); let bv = b.view(); - bench.iter(|| { - a += &bv; + c.bench_function("add_3d_strided", |bn| { + bn.iter(|| { + a += &bv; + }) }); } -#[bench] -fn add_3d_strided_dyn(bench: &mut test::Bencher) +fn add_3d_strided_dyn(c: &mut Criterion) { let mut a = Array::::zeros(&[ADD3DSZ, ADD3DSZ, ADD3DSZ * 2][..]); let mut a = a.slice_mut(s![.., .., ..;2]); let b = Array::::zeros(a.dim()); let bv = b.view(); - bench.iter(|| { - a += &bv; + c.bench_function("add_3d_strided_dyn", |bn| { + bn.iter(|| { + a += &bv; + }) }); } const ADD1D_SIZE: usize = 64 * 64; -#[bench] -fn add_1d_regular(bench: &mut test::Bencher) +fn add_1d_regular(c: &mut Criterion) { let mut a = Array::::zeros(ADD1D_SIZE); let b = Array::::zeros(a.dim()); - bench.iter(|| { - a += &b; + c.bench_function("add_1d_regular", |bn| { + bn.iter(|| { + a += &b; + }) }); } -#[bench] -fn add_1d_strided(bench: &mut test::Bencher) +fn add_1d_strided(c: &mut Criterion) { let mut a = Array::::zeros(ADD1D_SIZE * 2); let mut av = a.slice_mut(s![..;2]); let b = Array::::zeros(av.dim()); - bench.iter(|| { - av += &b; + c.bench_function("add_1d_strided", |bn| { + bn.iter(|| { + av += &b; + }) }); } -#[bench] -fn iadd_scalar_2d_regular(bench: &mut test::Bencher) +fn iadd_scalar_2d_regular(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ)); - bench.iter(|| { - a += 1.; + c.bench_function("iadd_scalar_2d_regular", |bn| { + bn.iter(|| { + a += 1.; + }) }); } -#[bench] -fn iadd_scalar_2d_strided(bench: &mut test::Bencher) +fn iadd_scalar_2d_strided(c: &mut Criterion) { let mut a = Array::::zeros((ADD2DSZ, ADD2DSZ * 2)); let mut a = a.slice_mut(s![.., ..;2]); - bench.iter(|| { - a += 1.; + c.bench_function("iadd_scalar_2d_strided", |bn| { + bn.iter(|| { + a += 1.; + }) }); } -#[bench] -fn iadd_scalar_2d_regular_dyn(bench: &mut test::Bencher) +fn iadd_scalar_2d_regular_dyn(c: &mut Criterion) { let mut a = Array::::zeros(vec![ADD2DSZ, ADD2DSZ]); - bench.iter(|| { - a += 1.; + c.bench_function("iadd_scalar_2d_regular_dyn", |bn| { + bn.iter(|| { + a += 1.; + }) }); } -#[bench] -fn iadd_scalar_2d_strided_dyn(bench: &mut test::Bencher) +fn iadd_scalar_2d_strided_dyn(c: &mut Criterion) { let mut a = Array::::zeros(vec![ADD2DSZ, ADD2DSZ * 2]); let mut a = a.slice_mut(s![.., ..;2]); - bench.iter(|| { - a += 1.; + c.bench_function("iadd_scalar_2d_strided_dyn", |bn| { + bn.iter(|| { + a += 1.; + }) }); } -#[bench] -fn scaled_add_2d_f32_regular(bench: &mut test::Bencher) +fn scaled_add_2d_f32_regular(c: &mut Criterion) { let mut av = Array::::zeros((ADD2DSZ, ADD2DSZ)); let bv = Array::::zeros((ADD2DSZ, ADD2DSZ)); let scalar = std::f32::consts::PI; - bench.iter(|| { - av.scaled_add(scalar, &bv); + c.bench_function("scaled_add_2d_f32_regular", |bn| { + bn.iter(|| { + av.scaled_add(scalar, &bv); + }) }); } -#[bench] -fn assign_scalar_2d_corder(bench: &mut test::Bencher) +fn assign_scalar_2d_corder(c: &mut Criterion) { let a = Array::zeros((ADD2DSZ, ADD2DSZ)); let mut a = black_box(a); let s = 3.; - bench.iter(move || a.fill(s)) + c.bench_function("assign_scalar_2d_corder", |bn| bn.iter(|| a.fill(s))); } -#[bench] -fn assign_scalar_2d_cutout(bench: &mut test::Bencher) +fn assign_scalar_2d_cutout(c: &mut Criterion) { let mut a = Array::zeros((66, 66)); let a = a.slice_mut(s![1..-1, 1..-1]); let mut a = black_box(a); let s = 3.; - bench.iter(move || a.fill(s)) + c.bench_function("assign_scalar_2d_cutout", |bn| bn.iter(|| a.fill(s))); } -#[bench] -fn assign_scalar_2d_forder(bench: &mut test::Bencher) +fn assign_scalar_2d_forder(c: &mut Criterion) { let mut a = Array::zeros((ADD2DSZ, ADD2DSZ)); a.swap_axes(0, 1); let mut a = black_box(a); let s = 3.; - bench.iter(move || a.fill(s)) + c.bench_function("assign_scalar_2d_forder", |bn| bn.iter(|| a.fill(s))); } -#[bench] -fn assign_zero_2d_corder(bench: &mut test::Bencher) +fn assign_zero_2d_corder(c: &mut Criterion) { let a = Array::zeros((ADD2DSZ, ADD2DSZ)); let mut a = black_box(a); - bench.iter(|| a.fill(0.)) + c.bench_function("assign_zero_2d_corder", |bn| bn.iter(|| a.fill(0.))); } -#[bench] -fn assign_zero_2d_cutout(bench: &mut test::Bencher) +fn assign_zero_2d_cutout(c: &mut Criterion) { let mut a = Array::zeros((66, 66)); let a = a.slice_mut(s![1..-1, 1..-1]); let mut a = black_box(a); - bench.iter(|| a.fill(0.)) + c.bench_function("assign_zero_2d_cutout", |bn| bn.iter(|| a.fill(0.))); } -#[bench] -fn assign_zero_2d_forder(bench: &mut test::Bencher) +fn assign_zero_2d_forder(c: &mut Criterion) { let mut a = Array::zeros((ADD2DSZ, ADD2DSZ)); a.swap_axes(0, 1); let mut a = black_box(a); - bench.iter(|| a.fill(0.)) + c.bench_function("assign_zero_2d_forder", |bn| bn.iter(|| a.fill(0.))); } -#[bench] -fn bench_iter_diag(bench: &mut test::Bencher) +fn bench_iter_diag(c: &mut Criterion) { let a = Array::::zeros((1024, 1024)); - bench.iter(|| { - for elt in a.diag() { - black_box(elt); - } - }) + c.bench_function("bench_iter_diag", |bn| { + bn.iter(|| { + for elt in a.diag() { + black_box(elt); + } + }) + }); } -#[bench] -fn bench_row_iter(bench: &mut test::Bencher) +fn bench_row_iter(c: &mut Criterion) { let a = Array::::zeros((1024, 1024)); let it = a.row(17); - bench.iter(|| { - for elt in it { - black_box(elt); - } - }) + c.bench_function("bench_row_iter", |bn| { + bn.iter(|| { + for elt in it { + black_box(elt); + } + }) + }); } -#[bench] -fn bench_col_iter(bench: &mut test::Bencher) +fn bench_col_iter(c: &mut Criterion) { let a = Array::::zeros((1024, 1024)); let it = a.column(17); - bench.iter(|| { - for elt in it { - black_box(elt); - } - }) + c.bench_function("bench_col_iter", |bn| { + bn.iter(|| { + for elt in it { + black_box(elt); + } + }) + }); } macro_rules! mat_mul { ($modname:ident, $ty:ident, $(($name:ident, $m:expr, $n:expr, $k:expr))+) => { mod $modname { - use test::{black_box, Bencher}; + use criterion::{black_box, Criterion}; use ndarray::Array; $( - #[bench] - fn $name(bench: &mut Bencher) - { + pub fn $name(c: &mut Criterion) { let a = Array::<$ty, _>::zeros(($m, $n)); let b = Array::<$ty, _>::zeros(($n, $k)); let a = black_box(a.view()); let b = black_box(b.view()); - bench.iter(|| a.dot(&b)); + let bench_name = concat!(stringify!($modname), "::", stringify!($name)); + c.bench_function(bench_name, |bn| bn.iter(|| a.dot(&b))); } )+ + pub fn group(c: &mut Criterion) { + $( $name(c); )+ + } } }; } @@ -851,114 +883,101 @@ mat_mul! {mat_mul_i32, i32, (m127, 127, 127, 127) } -#[bench] -fn create_iter_4d(bench: &mut test::Bencher) +fn create_iter_4d(c: &mut Criterion) { let mut a = Array::from_elem((4, 5, 3, 2), 1.0); a.swap_axes(0, 1); a.swap_axes(2, 1); let v = black_box(a.view()); - bench.iter(|| v.into_iter()); + c.bench_function("create_iter_4d", |bn| bn.iter(|| v.into_iter())); } -#[bench] -fn bench_to_owned_n(bench: &mut test::Bencher) +fn bench_to_owned_n(c: &mut Criterion) { let a = Array::::zeros((32, 32)); - bench.iter(|| a.to_owned()); + c.bench_function("bench_to_owned_n", |bn| bn.iter(|| a.to_owned())); } -#[bench] -fn bench_to_owned_t(bench: &mut test::Bencher) +fn bench_to_owned_t(c: &mut Criterion) { let mut a = Array::::zeros((32, 32)); a.swap_axes(0, 1); - bench.iter(|| a.to_owned()); + c.bench_function("bench_to_owned_t", |bn| bn.iter(|| a.to_owned())); } -#[bench] -fn bench_to_owned_strided(bench: &mut test::Bencher) +fn bench_to_owned_strided(c: &mut Criterion) { let a = Array::::zeros((32, 64)); let a = a.slice(s![.., ..;2]); - bench.iter(|| a.to_owned()); + c.bench_function("bench_to_owned_strided", |bn| bn.iter(|| a.to_owned())); } -#[bench] -fn equality_i32(bench: &mut test::Bencher) + +fn equality_i32(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let b = Array::::zeros((64, 64)); - bench.iter(|| a == b); + c.bench_function("equality_i32", |bn| bn.iter(|| a == b)); } -#[bench] -fn equality_f32(bench: &mut test::Bencher) +fn equality_f32(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let b = Array::::zeros((64, 64)); - bench.iter(|| a == b); + c.bench_function("equality_f32", |bn| bn.iter(|| a == b)); } -#[bench] -fn equality_f32_mixorder(bench: &mut test::Bencher) +fn equality_f32_mixorder(c: &mut Criterion) { let a = Array::::zeros((64, 64)); let b = Array::::zeros((64, 64).f()); - bench.iter(|| a == b); + c.bench_function("equality_f32_mixorder", |bn| bn.iter(|| a == b)); } -#[bench] -fn dot_f32_16(bench: &mut test::Bencher) +fn dot_f32_16(c: &mut Criterion) { let a = Array::::zeros(16); let b = Array::::zeros(16); - bench.iter(|| a.dot(&b)); + c.bench_function("dot_f32_16", |bn| bn.iter(|| a.dot(&b))); } -#[bench] -fn dot_f32_20(bench: &mut test::Bencher) +fn dot_f32_20(c: &mut Criterion) { let a = Array::::zeros(20); let b = Array::::zeros(20); - bench.iter(|| a.dot(&b)); + c.bench_function("dot_f32_20", |bn| bn.iter(|| a.dot(&b))); } -#[bench] -fn dot_f32_32(bench: &mut test::Bencher) +fn dot_f32_32(c: &mut Criterion) { let a = Array::::zeros(32); let b = Array::::zeros(32); - bench.iter(|| a.dot(&b)); + c.bench_function("dot_f32_32", |bn| bn.iter(|| a.dot(&b))); } -#[bench] -fn dot_f32_256(bench: &mut test::Bencher) +fn dot_f32_256(c: &mut Criterion) { let a = Array::::zeros(256); let b = Array::::zeros(256); - bench.iter(|| a.dot(&b)); + c.bench_function("dot_f32_256", |bn| bn.iter(|| a.dot(&b))); } -#[bench] -fn dot_f32_1024(bench: &mut test::Bencher) +fn dot_f32_1024(c: &mut Criterion) { let av = Array::::zeros(1024); let bv = Array::::zeros(1024); - bench.iter(|| av.dot(&bv)); + c.bench_function("dot_f32_1024", |bn| bn.iter(|| av.dot(&bv))); } -#[bench] -fn dot_f32_10e6(bench: &mut test::Bencher) +fn dot_f32_10e6(c: &mut Criterion) { let n = 1_000_000; let av = Array::::zeros(n); let bv = Array::::zeros(n); - bench.iter(|| av.dot(&bv)); + c.bench_function("dot_f32_10e6", |bn| bn.iter(|| av.dot(&bv))); } -#[bench] -fn dot_extended(bench: &mut test::Bencher) +fn dot_extended(c: &mut Criterion) { let m = 10; let n = 33; @@ -966,16 +985,17 @@ fn dot_extended(bench: &mut test::Bencher) let av = Array::::zeros((m, n)); let bv = Array::::zeros((n, k)); let mut res = Array::::zeros((m, k)); - // make a manual simple matrix multiply to test - bench.iter(|| { - for i in 0..m { - for j in 0..k { - unsafe { - *res.uget_mut((i, j)) = av.row(i).dot(&bv.column(j)); + c.bench_function("dot_extended", |bn| { + bn.iter(|| { + for i in 0..m { + for j in 0..k { + unsafe { + *res.uget_mut((i, j)) = av.row(i).dot(&bv.column(j)); + } } } - } - }) + }) + }); } const MEAN_SUM_N: usize = 127; @@ -990,117 +1010,290 @@ fn range_mat(m: Ix, n: Ix) -> Array2 } #[cfg(feature = "std")] -#[bench] -fn mean_axis0(bench: &mut test::Bencher) +fn mean_axis0(c: &mut Criterion) { let a = range_mat(MEAN_SUM_N, MEAN_SUM_N); - bench.iter(|| a.mean_axis(Axis(0))); + c.bench_function("mean_axis0", |bn| bn.iter(|| a.mean_axis(Axis(0)))); } #[cfg(feature = "std")] -#[bench] -fn mean_axis1(bench: &mut test::Bencher) +fn mean_axis1(c: &mut Criterion) { let a = range_mat(MEAN_SUM_N, MEAN_SUM_N); - bench.iter(|| a.mean_axis(Axis(1))); + c.bench_function("mean_axis1", |bn| bn.iter(|| a.mean_axis(Axis(1)))); } #[cfg(feature = "std")] -#[bench] -fn sum_axis0(bench: &mut test::Bencher) +fn sum_axis0(c: &mut Criterion) { let a = range_mat(MEAN_SUM_N, MEAN_SUM_N); - bench.iter(|| a.sum_axis(Axis(0))); + c.bench_function("sum_axis0", |bn| bn.iter(|| a.sum_axis(Axis(0)))); } #[cfg(feature = "std")] -#[bench] -fn sum_axis1(bench: &mut test::Bencher) +fn sum_axis1(c: &mut Criterion) { let a = range_mat(MEAN_SUM_N, MEAN_SUM_N); - bench.iter(|| a.sum_axis(Axis(1))); + c.bench_function("sum_axis1", |bn| bn.iter(|| a.sum_axis(Axis(1)))); } -#[bench] -fn into_dimensionality_ix1_ok(bench: &mut test::Bencher) +fn into_dimensionality_ix1_ok(c: &mut Criterion) { let a = Array::::zeros(Ix1(10)); let a = a.view(); - bench.iter(|| a.into_dimensionality::()); + c.bench_function("into_dimensionality_ix1_ok", |bn| { + bn.iter(|| a.into_dimensionality::()) + }); } -#[bench] -fn into_dimensionality_ix3_ok(bench: &mut test::Bencher) +fn into_dimensionality_ix3_ok(c: &mut Criterion) { let a = Array::::zeros(Ix3(10, 10, 10)); let a = a.view(); - bench.iter(|| a.into_dimensionality::()); + c.bench_function("into_dimensionality_ix3_ok", |bn| { + bn.iter(|| a.into_dimensionality::()) + }); } -#[bench] -fn into_dimensionality_ix3_err(bench: &mut test::Bencher) +fn into_dimensionality_ix3_err(c: &mut Criterion) { let a = Array::::zeros(Ix3(10, 10, 10)); let a = a.view(); - bench.iter(|| a.into_dimensionality::()); + c.bench_function("into_dimensionality_ix3_err", |bn| { + bn.iter(|| a.into_dimensionality::()) + }); } -#[bench] -fn into_dimensionality_dyn_to_ix3(bench: &mut test::Bencher) +fn into_dimensionality_dyn_to_ix3(c: &mut Criterion) { let a = Array::::zeros(IxDyn(&[10, 10, 10])); let a = a.view(); - bench.iter(|| a.clone().into_dimensionality::()); + c.bench_function("into_dimensionality_dyn_to_ix3", |bn| { + bn.iter(|| a.clone().into_dimensionality::()) + }); } -#[bench] -fn into_dimensionality_dyn_to_dyn(bench: &mut test::Bencher) +fn into_dimensionality_dyn_to_dyn(c: &mut Criterion) { let a = Array::::zeros(IxDyn(&[10, 10, 10])); let a = a.view(); - bench.iter(|| a.clone().into_dimensionality::()); + c.bench_function("into_dimensionality_dyn_to_dyn", |bn| { + bn.iter(|| a.clone().into_dimensionality::()) + }); } -#[bench] -fn into_dyn_ix3(bench: &mut test::Bencher) +fn into_dyn_ix3(c: &mut Criterion) { let a = Array::::zeros(Ix3(10, 10, 10)); let a = a.view(); - bench.iter(|| a.into_dyn()); + c.bench_function("into_dyn_ix3", |bn| bn.iter(|| a.into_dyn())); } -#[bench] -fn into_dyn_ix5(bench: &mut test::Bencher) +fn into_dyn_ix5(c: &mut Criterion) { let a = Array::::zeros(Ix5(2, 2, 2, 2, 2)); let a = a.view(); - bench.iter(|| a.into_dyn()); + c.bench_function("into_dyn_ix5", |bn| bn.iter(|| a.into_dyn())); } -#[bench] -fn into_dyn_dyn(bench: &mut test::Bencher) +fn into_dyn_dyn(c: &mut Criterion) { let a = Array::::zeros(IxDyn(&[10, 10, 10])); let a = a.view(); - bench.iter(|| a.clone().into_dyn()); + c.bench_function("into_dyn_dyn", |bn| bn.iter(|| a.clone().into_dyn())); } -#[bench] -fn broadcast_same_dim(bench: &mut test::Bencher) +fn broadcast_same_dim(c: &mut Criterion) { let s = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; let s = Array4::from_shape_vec((2, 2, 3, 2), s.to_vec()).unwrap(); let a = s.slice(s![.., ..;-1, ..;2, ..]); let b = s.slice(s![.., .., ..;2, ..]); - bench.iter(|| &a + &b); + c.bench_function("broadcast_same_dim", |bn| bn.iter(|| &a + &b)); } -#[bench] -fn broadcast_one_side(bench: &mut test::Bencher) +fn broadcast_one_side(c: &mut Criterion) { let s = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; let s2 = [1, 2, 3, 4, 5, 6]; let a = Array4::from_shape_vec((4, 1, 3, 2), s.to_vec()).unwrap(); let b = Array3::from_shape_vec((1, 3, 2), s2.to_vec()).unwrap(); - bench.iter(|| &a + &b); -} + c.bench_function("broadcast_one_side", |bn| bn.iter(|| &a + &b)); +} + +criterion_group!( + iter_benches, + iter_sum_1d_regular, + iter_sum_1d_raw, + iter_sum_2d_regular, + iter_sum_2d_by_row, + iter_sum_2d_raw, + iter_sum_2d_cutout, + iter_sum_2d_cutout_by_row, + iter_sum_2d_cutout_outer_iter, + iter_sum_2d_transpose_regular, + iter_sum_2d_transpose_by_row, +); + +criterion_group!( + sum_benches, + sum_2d_regular, + sum_2d_cutout, + sum_2d_float, + sum_2d_float_cutout, + sum_2d_float_t_cutout, + fold_sum_i32_2d_regular, + fold_sum_i32_2d_cutout, + fold_sum_i32_2d_stride, + fold_sum_i32_2d_transpose, + fold_sum_i32_2d_cutout_transpose, +); + +criterion_group!( + add_benches, + add_2d_regular, + add_2d_zip, + add_2d_alloc_plus, + add_2d_alloc_zip_uninit, + add_2d_alloc_zip_collect, + vec_string_collect, + array_string_collect, + vec_f64_collect, + array_f64_collect, + add_2d_assign_ops, + add_2d_cutout, + add_2d_zip_cutout, + add_2d_cutouts_by_4, + add_2d_cutouts_by_16, + add_2d_cutouts_by_32, + add_2d_broadcast_1_to_2, + add_2d_broadcast_0_to_2, +); + +criterion_group!( + scalar_benches, + scalar_toowned, + scalar_add_1, + scalar_add_2, + scalar_add_strided_1, + scalar_add_strided_2, + scalar_sub_1, + scalar_sub_2, + add_2d_0_to_2_iadd_scalar, +); + +criterion_group!( + add_strided_benches, + add_2d_strided, + add_2d_regular_dyn, + add_2d_strided_dyn, + add_2d_zip_strided, + add_2d_one_transposed, + add_2d_zip_one_transposed, + add_2d_both_transposed, + add_2d_zip_both_transposed, + add_2d_f32_regular, + add_3d_strided, + add_3d_strided_dyn, + add_1d_regular, + add_1d_strided, +); + +criterion_group!( + iadd_scalar_benches, + iadd_scalar_2d_regular, + iadd_scalar_2d_strided, + iadd_scalar_2d_regular_dyn, + iadd_scalar_2d_strided_dyn, + scaled_add_2d_f32_regular, + assign_scalar_2d_corder, + assign_scalar_2d_cutout, + assign_scalar_2d_forder, + assign_zero_2d_corder, + assign_zero_2d_cutout, + assign_zero_2d_forder, +); + +criterion_group!( + iter_misc_benches, + bench_iter_diag, + bench_row_iter, + bench_col_iter, + create_iter_4d, + bench_to_owned_n, + bench_to_owned_t, + bench_to_owned_strided, + equality_i32, + equality_f32, + equality_f32_mixorder, +); + +criterion_group!( + dot_benches, + dot_f32_16, + dot_f32_20, + dot_f32_32, + dot_f32_256, + dot_f32_1024, + dot_f32_10e6, + dot_extended, +); + +criterion_group!( + dimensionality_benches, + into_dimensionality_ix1_ok, + into_dimensionality_ix3_ok, + into_dimensionality_ix3_err, + into_dimensionality_dyn_to_ix3, + into_dimensionality_dyn_to_dyn, + into_dyn_ix3, + into_dyn_ix5, + into_dyn_dyn, + broadcast_same_dim, + broadcast_one_side, +); + +criterion_group!( + matmul_benches, + mat_mul_f32::group, + mat_mul_f64::group, + mat_mul_i32::group, +); + +#[cfg(feature = "std")] +criterion_group!( + std_benches, + mean_axis0, + mean_axis1, + sum_axis0, + sum_axis1, +); + +#[cfg(feature = "std")] +criterion_main!( + iter_benches, + sum_benches, + add_benches, + scalar_benches, + add_strided_benches, + iadd_scalar_benches, + iter_misc_benches, + dot_benches, + dimensionality_benches, + matmul_benches, + std_benches, +); + +#[cfg(not(feature = "std"))] +criterion_main!( + iter_benches, + sum_benches, + add_benches, + scalar_benches, + add_strided_benches, + iadd_scalar_benches, + iter_misc_benches, + dot_benches, + dimensionality_benches, + matmul_benches, +); diff --git a/benches/chunks.rs b/benches/chunks.rs index 46780492..702727c9 100644 --- a/benches/chunks.rs +++ b/benches/chunks.rs @@ -1,87 +1,98 @@ -#![feature(test)] - -extern crate test; -use test::Bencher; - +use criterion::{criterion_group, criterion_main, Criterion}; use ndarray::prelude::*; use ndarray::NdProducer; -#[bench] -fn chunk2x2_iter_sum(bench: &mut Bencher) +fn chunk2x2_iter_sum(c: &mut Criterion) { let a = Array::::zeros((256, 256)); let chunksz = (2, 2); let mut sum = Array::zeros(a.exact_chunks(chunksz).raw_dim()); - bench.iter(|| { - azip!((a in a.exact_chunks(chunksz), sum in &mut sum) { - *sum = a.iter().sum::(); + c.bench_function("chunk2x2_iter_sum", |b| { + b.iter(|| { + azip!((a in a.exact_chunks(chunksz), sum in &mut sum) { + *sum = a.iter().sum::(); + }); }); }); } -#[bench] -fn chunk2x2_sum(bench: &mut Bencher) +fn chunk2x2_sum(c: &mut Criterion) { let a = Array::::zeros((256, 256)); let chunksz = (2, 2); let mut sum = Array::zeros(a.exact_chunks(chunksz).raw_dim()); - bench.iter(|| { - azip!((a in a.exact_chunks(chunksz), sum in &mut sum) { - *sum = a.sum(); + c.bench_function("chunk2x2_sum", |b| { + b.iter(|| { + azip!((a in a.exact_chunks(chunksz), sum in &mut sum) { + *sum = a.sum(); + }); }); }); } -#[bench] -fn chunk2x2_sum_get1(bench: &mut Bencher) +fn chunk2x2_sum_get1(c: &mut Criterion) { let a = Array::::zeros((256, 256)); let chunksz = (2, 2); let mut sum = Array::::zeros(a.exact_chunks(chunksz).raw_dim()); - bench.iter(|| { - let (m, n) = a.dim(); - for i in 0..m { - for j in 0..n { - sum[[i / 2, j / 2]] += a[[i, j]]; + c.bench_function("chunk2x2_sum_get1", |b| { + b.iter(|| { + let (m, n) = a.dim(); + for i in 0..m { + for j in 0..n { + sum[[i / 2, j / 2]] += a[[i, j]]; + } } - } + }); }); } -#[bench] -fn chunk2x2_sum_uget1(bench: &mut Bencher) +fn chunk2x2_sum_uget1(c: &mut Criterion) { let a = Array::::zeros((256, 256)); let chunksz = (2, 2); let mut sum = Array::::zeros(a.exact_chunks(chunksz).raw_dim()); - bench.iter(|| { - let (m, n) = a.dim(); - for i in 0..m { - for j in 0..n { - unsafe { - *sum.uget_mut([i / 2, j / 2]) += *a.uget([i, j]); + c.bench_function("chunk2x2_sum_uget1", |b| { + b.iter(|| { + let (m, n) = a.dim(); + for i in 0..m { + for j in 0..n { + unsafe { + *sum.uget_mut([i / 2, j / 2]) += *a.uget([i, j]); + } } } - } + }); }); } -#[bench] #[allow(clippy::identity_op)] -fn chunk2x2_sum_get2(bench: &mut Bencher) +fn chunk2x2_sum_get2(c: &mut Criterion) { let a = Array::::zeros((256, 256)); let chunksz = (2, 2); let mut sum = Array::::zeros(a.exact_chunks(chunksz).raw_dim()); - bench.iter(|| { - let (m, n) = sum.dim(); - for i in 0..m { - for j in 0..n { - sum[[i, j]] += a[[i * 2 + 0, j * 2 + 0]]; - sum[[i, j]] += a[[i * 2 + 0, j * 2 + 1]]; - sum[[i, j]] += a[[i * 2 + 1, j * 2 + 1]]; - sum[[i, j]] += a[[i * 2 + 1, j * 2 + 0]]; + c.bench_function("chunk2x2_sum_get2", |b| { + b.iter(|| { + let (m, n) = sum.dim(); + for i in 0..m { + for j in 0..n { + sum[[i, j]] += a[[i * 2 + 0, j * 2 + 0]]; + sum[[i, j]] += a[[i * 2 + 0, j * 2 + 1]]; + sum[[i, j]] += a[[i * 2 + 1, j * 2 + 1]]; + sum[[i, j]] += a[[i * 2 + 1, j * 2 + 0]]; + } } - } + }); }); } + +criterion_group!( + benches, + chunk2x2_iter_sum, + chunk2x2_sum, + chunk2x2_sum_get1, + chunk2x2_sum_uget1, + chunk2x2_sum_get2 +); +criterion_main!(benches); diff --git a/benches/construct.rs b/benches/construct.rs index 958eaa3b..3cc53650 100644 --- a/benches/construct.rs +++ b/benches/construct.rs @@ -1,39 +1,43 @@ -#![feature(test)] #![allow(clippy::many_single_char_names, clippy::deref_addrof, clippy::unreadable_literal)] -extern crate test; -use test::Bencher; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; use ndarray::prelude::*; -#[bench] -fn default_f64(bench: &mut Bencher) -{ - bench.iter(|| Array::::default((128, 128))) +fn default_f64(c: &mut Criterion) { + c.bench_function("default_f64", |b| { + b.iter(|| Array::::default(black_box((128, 128)))) + }); } -#[bench] -fn zeros_f64(bench: &mut Bencher) -{ - bench.iter(|| Array::::zeros((128, 128))) +fn zeros_f64(c: &mut Criterion) { + c.bench_function("zeros_f64", |b| { + b.iter(|| Array::::zeros(black_box((128, 128)))) + }); } #[cfg(feature = "std")] -#[bench] -fn map_regular(bench: &mut test::Bencher) -{ +fn map_regular(c: &mut Criterion) { let a = Array::linspace(0.0..=127.0, 128) .into_shape_with_order((8, 16)) .unwrap(); - bench.iter(|| a.map(|&x| 2. * x)); + c.bench_function("map_regular", |b| { + b.iter(|| black_box(&a).map(|&x| 2. * x)) + }); } #[cfg(feature = "std")] -#[bench] -fn map_stride(bench: &mut test::Bencher) -{ +fn map_stride(c: &mut Criterion) { let a = Array::linspace(0.0..=127.0, 256) .into_shape_with_order((8, 32)) .unwrap(); let av = a.slice(s![.., ..;2]); - bench.iter(|| av.map(|&x| 2. * x)); + c.bench_function("map_stride", |b| { + b.iter(|| black_box(&av).map(|&x| 2. * x)) + }); } + +#[cfg(feature = "std")] +criterion_group!(benches, default_f64, zeros_f64, map_regular, map_stride); +#[cfg(not(feature = "std"))] +criterion_group!(benches, default_f64, zeros_f64); +criterion_main!(benches); diff --git a/benches/gemv_gemm.rs b/benches/gemv_gemm.rs index ccd98725..4b7bc19c 100644 --- a/benches/gemv_gemm.rs +++ b/benches/gemv_gemm.rs @@ -1,9 +1,6 @@ -#![feature(test)] #![allow(clippy::many_single_char_names, clippy::deref_addrof, clippy::unreadable_literal)] -extern crate test; -use test::Bencher; - +use criterion::{criterion_group, criterion_main, Criterion}; use num_complex::Complex; use num_traits::{Float, One, Zero}; @@ -13,55 +10,56 @@ use ndarray::linalg::general_mat_mul; use ndarray::linalg::general_mat_vec_mul; use ndarray::LinalgScalar; -#[bench] -fn gemv_64_64c(bench: &mut Bencher) +fn gemv_64_64c(c: &mut Criterion) { let a = Array::zeros((64, 64)); let (m, n) = a.dim(); let x = Array::zeros(n); let mut y = Array::zeros(m); - bench.iter(|| { - general_mat_vec_mul(1.0, &a, &x, 1.0, &mut y); + c.bench_function("gemv_64_64c", |b| { + b.iter(|| { + general_mat_vec_mul(1.0, &a, &x, 1.0, &mut y); + }); }); } -#[bench] -fn gemv_64_64f(bench: &mut Bencher) +fn gemv_64_64f(c: &mut Criterion) { let a = Array::zeros((64, 64).f()); let (m, n) = a.dim(); let x = Array::zeros(n); let mut y = Array::zeros(m); - bench.iter(|| { - general_mat_vec_mul(1.0, &a, &x, 1.0, &mut y); + c.bench_function("gemv_64_64f", |b| { + b.iter(|| { + general_mat_vec_mul(1.0, &a, &x, 1.0, &mut y); + }); }); } -#[bench] -fn gemv_64_32(bench: &mut Bencher) +fn gemv_64_32(c: &mut Criterion) { let a = Array::zeros((64, 32)); let (m, n) = a.dim(); let x = Array::zeros(n); let mut y = Array::zeros(m); - bench.iter(|| { - general_mat_vec_mul(1.0, &a, &x, 1.0, &mut y); + c.bench_function("gemv_64_32", |b| { + b.iter(|| { + general_mat_vec_mul(1.0, &a, &x, 1.0, &mut y); + }); }); } -#[bench] -fn cgemm_100(bench: &mut Bencher) +fn cgemm_100(c: &mut Criterion) { - cgemm_bench::(100, bench); + cgemm_bench::("cgemm_100", 100, c); } -#[bench] -fn zgemm_100(bench: &mut Bencher) +fn zgemm_100(c: &mut Criterion) { - cgemm_bench::(100, bench); + cgemm_bench::("zgemm_100", 100, c); } -fn cgemm_bench(size: usize, bench: &mut Bencher) +fn cgemm_bench(name: &str, size: usize, c: &mut Criterion) where A: LinalgScalar + Float { let (m, k, n) = (size, size, size); @@ -69,7 +67,12 @@ where A: LinalgScalar + Float let x = Array::zeros((k, n)); let mut y = Array::zeros((m, n)); - bench.iter(|| { - general_mat_mul(Complex::one(), &a, &x, Complex::zero(), &mut y); + c.bench_function(name, |b| { + b.iter(|| { + general_mat_mul(Complex::one(), &a, &x, Complex::zero(), &mut y); + }); }); } + +criterion_group!(benches, gemv_64_64c, gemv_64_64f, gemv_64_32, cgemm_100, zgemm_100); +criterion_main!(benches); diff --git a/benches/higher-order.rs b/benches/higher-order.rs index 6356687f..09bbcbc3 100644 --- a/benches/higher-order.rs +++ b/benches/higher-order.rs @@ -1,9 +1,6 @@ -#![feature(test)] #![allow(clippy::many_single_char_names, clippy::deref_addrof, clippy::unreadable_literal)] -extern crate test; -use test::black_box; -use test::Bencher; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; use ndarray::prelude::*; const N: usize = 1024; @@ -11,13 +8,14 @@ const X: usize = 64; const Y: usize = 16; #[cfg(feature = "std")] -#[bench] -fn map_regular(bench: &mut Bencher) +fn map_regular(c: &mut Criterion) { let a = Array::linspace(0.0..=127.0, N) .into_shape_with_order((X, Y)) .unwrap(); - bench.iter(|| a.map(|&x| 2. * x)); + c.bench_function("map_regular", |b| { + b.iter(|| a.map(|&x| 2. * x)); + }); } pub fn double_array(mut a: ArrayViewMut2<'_, f64>) @@ -26,68 +24,89 @@ pub fn double_array(mut a: ArrayViewMut2<'_, f64>) } #[cfg(feature = "std")] -#[bench] -fn map_stride_double_f64(bench: &mut Bencher) +fn map_stride_double_f64(c: &mut Criterion) { let mut a = Array::linspace(0.0..=127.0, N * 2) .into_shape_with_order([X, Y * 2]) .unwrap(); let mut av = a.slice_mut(s![.., ..;2]); - bench.iter(|| { - double_array(av.view_mut()); + c.bench_function("map_stride_double_f64", |b| { + b.iter(|| { + double_array(av.view_mut()); + }); }); } #[cfg(feature = "std")] -#[bench] -fn map_stride_f64(bench: &mut Bencher) +fn map_stride_f64(c: &mut Criterion) { let a = Array::linspace(0.0..=127.0, N * 2) .into_shape_with_order([X, Y * 2]) .unwrap(); let av = a.slice(s![.., ..;2]); - bench.iter(|| av.map(|&x| 2. * x)); + c.bench_function("map_stride_f64", |b| { + b.iter(|| av.map(|&x| 2. * x)); + }); } #[cfg(feature = "std")] -#[bench] -fn map_stride_u32(bench: &mut Bencher) +fn map_stride_u32(c: &mut Criterion) { let a = Array::linspace(0.0..=127.0, N * 2) .into_shape_with_order([X, Y * 2]) .unwrap(); let b = a.mapv(|x| x as u32); let av = b.slice(s![.., ..;2]); - bench.iter(|| av.map(|&x| 2 * x)); + c.bench_function("map_stride_u32", |b| { + b.iter(|| av.map(|&x| 2 * x)); + }); } #[cfg(feature = "std")] -#[bench] -fn fold_axis(bench: &mut Bencher) +fn fold_axis(c: &mut Criterion) { let a = Array::linspace(0.0..=127.0, N * 2) .into_shape_with_order([X, Y * 2]) .unwrap(); - bench.iter(|| a.fold_axis(Axis(0), 0., |&acc, &elt| acc + elt)); + c.bench_function("fold_axis", |b| { + b.iter(|| a.fold_axis(Axis(0), 0., |&acc, &elt| acc + elt)); + }); } const MA: usize = 64; const MASZ: usize = MA * MA; -#[bench] -fn map_axis_0(bench: &mut Bencher) +fn map_axis_0(c: &mut Criterion) { let a = Array::from_iter(0..MASZ as i32) .into_shape_with_order([MA, MA]) .unwrap(); - bench.iter(|| a.map_axis(Axis(0), black_box)); + c.bench_function("map_axis_0", |b| { + b.iter(|| a.map_axis(Axis(0), black_box)); + }); } -#[bench] -fn map_axis_1(bench: &mut Bencher) +fn map_axis_1(c: &mut Criterion) { let a = Array::from_iter(0..MASZ as i32) .into_shape_with_order([MA, MA]) .unwrap(); - bench.iter(|| a.map_axis(Axis(1), black_box)); + c.bench_function("map_axis_1", |b| { + b.iter(|| a.map_axis(Axis(1), black_box)); + }); } + +#[cfg(feature = "std")] +criterion_group!( + benches, + map_regular, + map_stride_double_f64, + map_stride_f64, + map_stride_u32, + fold_axis, + map_axis_0, + map_axis_1 +); +#[cfg(not(feature = "std"))] +criterion_group!(benches, map_axis_0, map_axis_1); +criterion_main!(benches); diff --git a/benches/iter.rs b/benches/iter.rs index 0e18f123..6e782002 100644 --- a/benches/iter.rs +++ b/benches/iter.rs @@ -1,216 +1,226 @@ -#![feature(test)] -#![allow(clippy::many_single_char_names, clippy::deref_addrof, clippy::unreadable_literal)] +// `s![1..-1, 1..-1]` — ndarray's `s!` macro uses Python-style negative +// indexing where `-1` means "from end". Clippy can't see through the macro +// and reads `1..-1` as a plain (empty) Rust range; the actual semantics are +// correct. +#![allow(clippy::many_single_char_names, clippy::deref_addrof, clippy::unreadable_literal, clippy::reversed_empty_ranges)] -extern crate test; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; use rawpointer::PointerExt; -use test::black_box; -use test::Bencher; use ndarray::prelude::*; use ndarray::Slice; use ndarray::{FoldWhile, Zip}; -#[bench] -fn iter_sum_2d_regular(bench: &mut Bencher) +fn iter_sum_2d_regular(c: &mut Criterion) { let a = Array::::zeros((64, 64)); - bench.iter(|| a.iter().sum::()); + c.bench_function("iter_sum_2d_regular", |b| b.iter(|| a.iter().sum::())); } -#[bench] -fn iter_sum_2d_cutout(bench: &mut Bencher) +fn iter_sum_2d_cutout(c: &mut Criterion) { let a = Array::::zeros((66, 66)); let av = a.slice(s![1..-1, 1..-1]); let a = av; - bench.iter(|| a.iter().sum::()); + c.bench_function("iter_sum_2d_cutout", |b| b.iter(|| a.iter().sum::())); } -#[bench] -fn iter_all_2d_cutout(bench: &mut Bencher) +fn iter_all_2d_cutout(c: &mut Criterion) { let a = Array::::zeros((66, 66)); let av = a.slice(s![1..-1, 1..-1]); let a = av; - bench.iter(|| a.iter().all(|&x| x >= 0)); + c.bench_function("iter_all_2d_cutout", |b| b.iter(|| a.iter().all(|&x| x >= 0))); } -#[bench] -fn iter_sum_2d_transpose(bench: &mut Bencher) +fn iter_sum_2d_transpose(c: &mut Criterion) { let a = Array::::zeros((66, 66)); let a = a.t(); - bench.iter(|| a.iter().sum::()); + c.bench_function("iter_sum_2d_transpose", |b| b.iter(|| a.iter().sum::())); } #[cfg(feature = "std")] -#[bench] -fn iter_filter_sum_2d_u32(bench: &mut Bencher) +fn iter_filter_sum_2d_u32(c: &mut Criterion) { let a = Array::linspace(0.0..=1.0, 256) .into_shape_with_order((16, 16)) .unwrap(); let b = a.mapv(|x| (x * 100.) as u32); - bench.iter(|| b.iter().filter(|&&x| x < 75).sum::()); + c.bench_function("iter_filter_sum_2d_u32", |bn| { + bn.iter(|| b.iter().filter(|&&x| x < 75).sum::()) + }); } #[cfg(feature = "std")] -#[bench] -fn iter_filter_sum_2d_f32(bench: &mut Bencher) +fn iter_filter_sum_2d_f32(c: &mut Criterion) { let a = Array::linspace(0.0..=1.0, 256) .into_shape_with_order((16, 16)) .unwrap(); let b = a * 100.; - bench.iter(|| b.iter().filter(|&&x| x < 75.).sum::()); + c.bench_function("iter_filter_sum_2d_f32", |bn| { + bn.iter(|| b.iter().filter(|&&x| x < 75.).sum::()) + }); } #[cfg(feature = "std")] -#[bench] -fn iter_filter_sum_2d_stride_u32(bench: &mut Bencher) +fn iter_filter_sum_2d_stride_u32(c: &mut Criterion) { let a = Array::linspace(0.0..=1.0, 256) .into_shape_with_order((16, 16)) .unwrap(); let b = a.mapv(|x| (x * 100.) as u32); let b = b.slice(s![.., ..;2]); - bench.iter(|| b.iter().filter(|&&x| x < 75).sum::()); + c.bench_function("iter_filter_sum_2d_stride_u32", |bn| { + bn.iter(|| b.iter().filter(|&&x| x < 75).sum::()) + }); } #[cfg(feature = "std")] -#[bench] -fn iter_filter_sum_2d_stride_f32(bench: &mut Bencher) +fn iter_filter_sum_2d_stride_f32(c: &mut Criterion) { let a = Array::linspace(0.0..=1.0, 256) .into_shape_with_order((16, 16)) .unwrap(); let b = a * 100.; let b = b.slice(s![.., ..;2]); - bench.iter(|| b.iter().filter(|&&x| x < 75.).sum::()); + c.bench_function("iter_filter_sum_2d_stride_f32", |bn| { + bn.iter(|| b.iter().filter(|&&x| x < 75.).sum::()) + }); } #[cfg(feature = "std")] -#[bench] -fn iter_rev_step_by_contiguous(bench: &mut Bencher) +fn iter_rev_step_by_contiguous(c: &mut Criterion) { let a = Array::linspace(0.0..=1.0, 512); - bench.iter(|| { - a.iter().rev().step_by(2).for_each(|x| { - black_box(x); + c.bench_function("iter_rev_step_by_contiguous", |bn| { + bn.iter(|| { + a.iter().rev().step_by(2).for_each(|x| { + black_box(x); + }) }) }); } #[cfg(feature = "std")] -#[bench] -fn iter_rev_step_by_discontiguous(bench: &mut Bencher) +fn iter_rev_step_by_discontiguous(c: &mut Criterion) { let mut a = Array::linspace(0.0..=1.0, 1024); a.slice_axis_inplace(Axis(0), Slice::new(0, None, 2)); - bench.iter(|| { - a.iter().rev().step_by(2).for_each(|x| { - black_box(x); + c.bench_function("iter_rev_step_by_discontiguous", |bn| { + bn.iter(|| { + a.iter().rev().step_by(2).for_each(|x| { + black_box(x); + }) }) }); } const ZIPSZ: usize = 10_000; -#[bench] -fn sum_3_std_zip1(bench: &mut Bencher) +fn sum_3_std_zip1(c: &mut Criterion) { let a = vec![1; ZIPSZ]; let b = vec![1; ZIPSZ]; - let c = vec![1; ZIPSZ]; - bench.iter(|| { - a.iter() - .zip(b.iter().zip(&c)) - .fold(0, |acc, (&a, (&b, &c))| acc + a + b + c) + let c_vec = vec![1; ZIPSZ]; + c.bench_function("sum_3_std_zip1", |bn| { + bn.iter(|| { + a.iter() + .zip(b.iter().zip(&c_vec)) + .fold(0, |acc, (&a, (&b, &c))| acc + a + b + c) + }) }); } -#[bench] -fn sum_3_std_zip2(bench: &mut Bencher) +fn sum_3_std_zip2(c: &mut Criterion) { let a = vec![1; ZIPSZ]; let b = vec![1; ZIPSZ]; - let c = vec![1; ZIPSZ]; - bench.iter(|| { - a.iter() - .zip(b.iter()) - .zip(&c) - .fold(0, |acc, ((&a, &b), &c)| acc + a + b + c) + let c_vec = vec![1; ZIPSZ]; + c.bench_function("sum_3_std_zip2", |bn| { + bn.iter(|| { + a.iter() + .zip(b.iter()) + .zip(&c_vec) + .fold(0, |acc, ((&a, &b), &c)| acc + a + b + c) + }) }); } -#[bench] -fn sum_3_std_zip3(bench: &mut Bencher) +fn sum_3_std_zip3(c: &mut Criterion) { let a = vec![1; ZIPSZ]; let b = vec![1; ZIPSZ]; - let c = vec![1; ZIPSZ]; - bench.iter(|| { - let mut s = 0; - for ((&a, &b), &c) in a.iter().zip(b.iter()).zip(&c) { - s += a + b + c - } - s + let c_vec = vec![1; ZIPSZ]; + c.bench_function("sum_3_std_zip3", |bn| { + bn.iter(|| { + let mut s = 0; + for ((&a, &b), &c) in a.iter().zip(b.iter()).zip(&c_vec) { + s += a + b + c + } + s + }) }); } -#[bench] -fn vector_sum_3_std_zip(bench: &mut Bencher) +fn vector_sum_3_std_zip(c: &mut Criterion) { let a = vec![1.; ZIPSZ]; let b = vec![1.; ZIPSZ]; - let mut c = vec![1.; ZIPSZ]; - bench.iter(|| { - for ((&a, &b), c) in a.iter().zip(b.iter()).zip(&mut c) { - *c += a + b; - } + let mut c_vec = vec![1.; ZIPSZ]; + c.bench_function("vector_sum_3_std_zip", |bn| { + bn.iter(|| { + for ((&a, &b), c) in a.iter().zip(b.iter()).zip(&mut c_vec) { + *c += a + b; + } + }) }); } -#[bench] -fn sum_3_azip(bench: &mut Bencher) +fn sum_3_azip(c: &mut Criterion) { let a = vec![1; ZIPSZ]; let b = vec![1; ZIPSZ]; - let c = vec![1; ZIPSZ]; - bench.iter(|| { - let mut s = 0; - azip!((&a in &a, &b in &b, &c in &c) { - s += a + b + c; - }); - s + let c_vec = vec![1; ZIPSZ]; + c.bench_function("sum_3_azip", |bn| { + bn.iter(|| { + let mut s = 0; + azip!((&a in &a, &b in &b, &c in &c_vec) { + s += a + b + c; + }); + s + }) }); } -#[bench] -fn sum_3_azip_fold(bench: &mut Bencher) +fn sum_3_azip_fold(c: &mut Criterion) { let a = vec![1; ZIPSZ]; let b = vec![1; ZIPSZ]; - let c = vec![1; ZIPSZ]; - bench.iter(|| { - Zip::from(&a) - .and(&b) - .and(&c) - .fold_while(0, |acc, &a, &b, &c| FoldWhile::Continue(acc + a + b + c)) - .into_inner() + let c_vec = vec![1; ZIPSZ]; + c.bench_function("sum_3_azip_fold", |bn| { + bn.iter(|| { + Zip::from(&a) + .and(&b) + .and(&c_vec) + .fold_while(0, |acc, &a, &b, &c| FoldWhile::Continue(acc + a + b + c)) + .into_inner() + }) }); } -#[bench] -fn vector_sum_3_azip(bench: &mut Bencher) +fn vector_sum_3_azip(c: &mut Criterion) { let a = vec![1.; ZIPSZ]; let b = vec![1.; ZIPSZ]; - let mut c = vec![1.; ZIPSZ]; - bench.iter(|| { - azip!((&a in &a, &b in &b, c in &mut c) { - *c += a + b; - }); + let mut c_vec = vec![1.; ZIPSZ]; + c.bench_function("vector_sum_3_azip", |bn| { + bn.iter(|| { + azip!((&a in &a, &b in &b, c in &mut c_vec) { + *c += a + b; + }); + }) }); } @@ -223,31 +233,33 @@ fn vector_sum3_unchecked(a: &[f64], b: &[f64], c: &mut [f64]) } } -#[bench] -fn vector_sum_3_zip_unchecked(bench: &mut Bencher) +fn vector_sum_3_zip_unchecked(c: &mut Criterion) { let a = vec![1.; ZIPSZ]; let b = vec![1.; ZIPSZ]; - let mut c = vec![1.; ZIPSZ]; - bench.iter(move || { - vector_sum3_unchecked(&a, &b, &mut c); + let mut c_vec = vec![1.; ZIPSZ]; + c.bench_function("vector_sum_3_zip_unchecked", |bn| { + bn.iter(|| { + vector_sum3_unchecked(&a, &b, &mut c_vec); + }) }); } -#[bench] -fn vector_sum_3_zip_unchecked_manual(bench: &mut Bencher) +fn vector_sum_3_zip_unchecked_manual(c: &mut Criterion) { let a = vec![1.; ZIPSZ]; let b = vec![1.; ZIPSZ]; - let mut c = vec![1.; ZIPSZ]; - bench.iter(move || unsafe { - let mut ap = a.as_ptr(); - let mut bp = b.as_ptr(); - let mut cp = c.as_mut_ptr(); - let cend = cp.add(c.len()); - while cp != cend { - *cp.post_inc() += *ap.post_inc() + *bp.post_inc(); - } + let mut c_vec = vec![1.; ZIPSZ]; + c.bench_function("vector_sum_3_zip_unchecked_manual", |bn| { + bn.iter(|| unsafe { + let mut ap = a.as_ptr(); + let mut bp = b.as_ptr(); + let mut cp = c_vec.as_mut_ptr(); + let cend = cp.add(c_vec.len()); + while cp != cend { + *cp.post_inc() += *ap.post_inc() + *bp.post_inc(); + } + }) }); } @@ -255,103 +267,103 @@ fn vector_sum_3_zip_unchecked_manual(bench: &mut Bencher) const ISZ: usize = 16; const I2DSZ: usize = 64; -#[bench] -fn indexed_iter_1d_ix1(bench: &mut Bencher) +fn indexed_iter_1d_ix1(c: &mut Criterion) { let mut a = Array::::zeros(I2DSZ * I2DSZ); for (i, elt) in a.indexed_iter_mut() { *elt = i as _; } - bench.iter(|| { - for (i, &_elt) in a.indexed_iter() { - //assert!(a[i] == elt); - black_box(i); - } - }) + c.bench_function("indexed_iter_1d_ix1", |bn| { + bn.iter(|| { + for (i, &_elt) in a.indexed_iter() { + black_box(i); + } + }) + }); } -#[bench] -fn indexed_zip_1d_ix1(bench: &mut Bencher) +fn indexed_zip_1d_ix1(c: &mut Criterion) { let mut a = Array::::zeros(I2DSZ * I2DSZ); for (i, elt) in a.indexed_iter_mut() { *elt = i as _; } - bench.iter(|| { - Zip::indexed(&a).for_each(|i, &_elt| { - black_box(i); - //assert!(a[i] == elt); - }); - }) + c.bench_function("indexed_zip_1d_ix1", |bn| { + bn.iter(|| { + Zip::indexed(&a).for_each(|i, &_elt| { + black_box(i); + }); + }) + }); } -#[bench] -fn indexed_iter_2d_ix2(bench: &mut Bencher) +fn indexed_iter_2d_ix2(c: &mut Criterion) { let mut a = Array::::zeros((I2DSZ, I2DSZ)); for ((i, j), elt) in a.indexed_iter_mut() { *elt = (i + 100 * j) as _; } - bench.iter(|| { - for (i, &_elt) in a.indexed_iter() { - //assert!(a[i] == elt); - black_box(i); - } - }) + c.bench_function("indexed_iter_2d_ix2", |bn| { + bn.iter(|| { + for (i, &_elt) in a.indexed_iter() { + black_box(i); + } + }) + }); } -#[bench] -fn indexed_zip_2d_ix2(bench: &mut Bencher) + +fn indexed_zip_2d_ix2(c: &mut Criterion) { let mut a = Array::::zeros((I2DSZ, I2DSZ)); for ((i, j), elt) in a.indexed_iter_mut() { *elt = (i + 100 * j) as _; } - bench.iter(|| { - Zip::indexed(&a).for_each(|i, &_elt| { - black_box(i); - //assert!(a[i] == elt); - }); - }) + c.bench_function("indexed_zip_2d_ix2", |bn| { + bn.iter(|| { + Zip::indexed(&a).for_each(|i, &_elt| { + black_box(i); + }); + }) + }); } -#[bench] -fn indexed_iter_3d_ix3(bench: &mut Bencher) +fn indexed_iter_3d_ix3(c: &mut Criterion) { let mut a = Array::::zeros((ISZ, ISZ, ISZ)); for ((i, j, k), elt) in a.indexed_iter_mut() { *elt = (i + 100 * j + 10000 * k) as _; } - bench.iter(|| { - for (i, &_elt) in a.indexed_iter() { - //assert!(a[i] == elt); - black_box(i); - } - }) + c.bench_function("indexed_iter_3d_ix3", |bn| { + bn.iter(|| { + for (i, &_elt) in a.indexed_iter() { + black_box(i); + } + }) + }); } -#[bench] -fn indexed_zip_3d_ix3(bench: &mut Bencher) +fn indexed_zip_3d_ix3(c: &mut Criterion) { let mut a = Array::::zeros((ISZ, ISZ, ISZ)); for ((i, j, k), elt) in a.indexed_iter_mut() { *elt = (i + 100 * j + 10000 * k) as _; } - bench.iter(|| { - Zip::indexed(&a).for_each(|i, &_elt| { - black_box(i); - //assert!(a[i] == elt); - }); - }) + c.bench_function("indexed_zip_3d_ix3", |bn| { + bn.iter(|| { + Zip::indexed(&a).for_each(|i, &_elt| { + black_box(i); + }); + }) + }); } -#[bench] -fn indexed_iter_3d_dyn(bench: &mut Bencher) +fn indexed_iter_3d_dyn(c: &mut Criterion) { let mut a = Array::::zeros((ISZ, ISZ, ISZ)); for ((i, j, k), elt) in a.indexed_iter_mut() { @@ -359,56 +371,60 @@ fn indexed_iter_3d_dyn(bench: &mut Bencher) } let a = a.into_shape_with_order(&[ISZ; 3][..]).unwrap(); - bench.iter(|| { - for (i, &_elt) in a.indexed_iter() { - //assert!(a[i] == elt); - black_box(i); - } - }) + c.bench_function("indexed_iter_3d_dyn", |bn| { + bn.iter(|| { + for (i, &_elt) in a.indexed_iter() { + black_box(i); + } + }) + }); } -#[bench] -fn iter_sum_1d_strided_fold(bench: &mut Bencher) +fn iter_sum_1d_strided_fold(c: &mut Criterion) { let mut a = Array::::ones(10240); a.slice_axis_inplace(Axis(0), Slice::new(0, None, 2)); - bench.iter(|| a.iter().sum::()); + c.bench_function("iter_sum_1d_strided_fold", |bn| bn.iter(|| a.iter().sum::())); } -#[bench] -fn iter_sum_1d_strided_rfold(bench: &mut Bencher) +fn iter_sum_1d_strided_rfold(c: &mut Criterion) { let mut a = Array::::ones(10240); a.slice_axis_inplace(Axis(0), Slice::new(0, None, 2)); - bench.iter(|| a.iter().rfold(0, |acc, &x| acc + x)); + c.bench_function("iter_sum_1d_strided_rfold", |bn| { + bn.iter(|| a.iter().rfold(0, |acc, &x| acc + x)) + }); } -#[bench] -fn iter_axis_iter_sum(bench: &mut Bencher) +fn iter_axis_iter_sum(c: &mut Criterion) { let a = Array::::zeros((64, 64)); - bench.iter(|| a.axis_iter(Axis(0)).map(|plane| plane.sum()).sum::()); + c.bench_function("iter_axis_iter_sum", |bn| { + bn.iter(|| a.axis_iter(Axis(0)).map(|plane| plane.sum()).sum::()) + }); } -#[bench] -fn iter_axis_chunks_1_iter_sum(bench: &mut Bencher) +fn iter_axis_chunks_1_iter_sum(c: &mut Criterion) { let a = Array::::zeros((64, 64)); - bench.iter(|| { - a.axis_chunks_iter(Axis(0), 1) - .map(|plane| plane.sum()) - .sum::() + c.bench_function("iter_axis_chunks_1_iter_sum", |bn| { + bn.iter(|| { + a.axis_chunks_iter(Axis(0), 1) + .map(|plane| plane.sum()) + .sum::() + }) }); } -#[bench] -fn iter_axis_chunks_5_iter_sum(bench: &mut Bencher) +fn iter_axis_chunks_5_iter_sum(c: &mut Criterion) { let a = Array::::zeros((64, 64)); - bench.iter(|| { - a.axis_chunks_iter(Axis(0), 5) - .map(|plane| plane.sum()) - .sum::() + c.bench_function("iter_axis_chunks_5_iter_sum", |bn| { + bn.iter(|| { + a.axis_chunks_iter(Axis(0), 5) + .map(|plane| plane.sum()) + .sum::() + }) }); } @@ -419,18 +435,64 @@ pub fn zip_mut_with(data: &Array3, out: &mut Array3) }); } -#[bench] -fn zip_mut_with_cc(b: &mut Bencher) +fn zip_mut_with_cc(c: &mut Criterion) { let data: Array3 = Array3::zeros((ISZ, ISZ, ISZ)); let mut out = Array3::zeros(data.dim()); - b.iter(|| zip_mut_with(&data, &mut out)); + c.bench_function("zip_mut_with_cc", |b| b.iter(|| zip_mut_with(&data, &mut out))); } -#[bench] -fn zip_mut_with_ff(b: &mut Bencher) +fn zip_mut_with_ff(c: &mut Criterion) { let data: Array3 = Array3::zeros((ISZ, ISZ, ISZ).f()); let mut out = Array3::zeros(data.dim().f()); - b.iter(|| zip_mut_with(&data, &mut out)); + c.bench_function("zip_mut_with_ff", |b| b.iter(|| zip_mut_with(&data, &mut out))); } + +#[cfg(feature = "std")] +criterion_group!( + benches_std, + iter_filter_sum_2d_u32, + iter_filter_sum_2d_f32, + iter_filter_sum_2d_stride_u32, + iter_filter_sum_2d_stride_f32, + iter_rev_step_by_contiguous, + iter_rev_step_by_discontiguous, +); + +criterion_group!( + benches, + iter_sum_2d_regular, + iter_sum_2d_cutout, + iter_all_2d_cutout, + iter_sum_2d_transpose, + sum_3_std_zip1, + sum_3_std_zip2, + sum_3_std_zip3, + vector_sum_3_std_zip, + sum_3_azip, + sum_3_azip_fold, + vector_sum_3_azip, + vector_sum_3_zip_unchecked, + vector_sum_3_zip_unchecked_manual, + indexed_iter_1d_ix1, + indexed_zip_1d_ix1, + indexed_iter_2d_ix2, + indexed_zip_2d_ix2, + indexed_iter_3d_ix3, + indexed_zip_3d_ix3, + indexed_iter_3d_dyn, + iter_sum_1d_strided_fold, + iter_sum_1d_strided_rfold, + iter_axis_iter_sum, + iter_axis_chunks_1_iter_sum, + iter_axis_chunks_5_iter_sum, + zip_mut_with_cc, + zip_mut_with_ff, +); + +#[cfg(feature = "std")] +criterion_main!(benches, benches_std); + +#[cfg(not(feature = "std"))] +criterion_main!(benches); diff --git a/benches/numeric.rs b/benches/numeric.rs index 5dcde52d..46fcace0 100644 --- a/benches/numeric.rs +++ b/benches/numeric.rs @@ -1,8 +1,4 @@ -#![feature(test)] - -extern crate test; -use test::Bencher; - +use criterion::{black_box, criterion_group, criterion_main, Criterion}; use ndarray::prelude::*; const N: usize = 1024; @@ -10,23 +6,29 @@ const X: usize = 64; const Y: usize = 16; #[cfg(feature = "std")] -#[bench] -fn clip(bench: &mut Bencher) -{ +fn clip(c: &mut Criterion) { let mut a = Array::linspace(0.0..=127.0, N * 2) .into_shape_with_order([X, Y * 2]) .unwrap(); let min = 2.; let max = 5.; - bench.iter(|| { - a.mapv_inplace(|mut x| { - if x < min { - x = min - } - if x > max { - x = max - } - x + c.bench_function("clip", |b| { + b.iter(|| { + black_box(&mut a).mapv_inplace(|mut x| { + if x < min { + x = min + } + if x > max { + x = max + } + x + }) }) }); } + +#[cfg(feature = "std")] +criterion_group!(benches, clip); +#[cfg(not(feature = "std"))] +criterion_group!(benches,); +criterion_main!(benches); diff --git a/benches/par_rayon.rs b/benches/par_rayon.rs index 95b51427..857660ee 100644 --- a/benches/par_rayon.rs +++ b/benches/par_rayon.rs @@ -1,12 +1,8 @@ #![cfg(feature = "rayon")] -#![feature(test)] +use criterion::{criterion_group, criterion_main, Criterion}; use ndarray::parallel::prelude::*; use ndarray::prelude::*; - -extern crate test; -use test::Bencher; - use ndarray::Zip; const EXP_N: usize = 256; @@ -20,24 +16,26 @@ fn set_threads() // let _ = rayon::ThreadPoolBuilder::new().num_threads(n).build_global(); } -#[bench] -fn map_exp_regular(bench: &mut Bencher) +fn map_exp_regular(c: &mut Criterion) { let mut a = Array2::::zeros((EXP_N, EXP_N)); a.swap_axes(0, 1); - bench.iter(|| { - a.mapv_inplace(|x| x.exp()); + c.bench_function("map_exp_regular", |b| { + b.iter(|| { + a.mapv_inplace(|x| x.exp()); + }); }); } -#[bench] -fn rayon_exp_regular(bench: &mut Bencher) +fn rayon_exp_regular(c: &mut Criterion) { set_threads(); let mut a = Array2::::zeros((EXP_N, EXP_N)); a.swap_axes(0, 1); - bench.iter(|| { - a.view_mut().into_par_iter().for_each(|x| *x = x.exp()); + c.bench_function("rayon_exp_regular", |b| { + b.iter(|| { + a.view_mut().into_par_iter().for_each(|x| *x = x.exp()); + }); }); } @@ -50,102 +48,107 @@ fn fastexp(x: f64) -> f64 x.powi(1024) } -#[bench] -fn map_fastexp_regular(bench: &mut Bencher) +fn map_fastexp_regular(c: &mut Criterion) { let mut a = Array2::::zeros((FASTEXP, FASTEXP)); - bench.iter(|| a.mapv_inplace(fastexp)); + c.bench_function("map_fastexp_regular", |b| b.iter(|| a.mapv_inplace(fastexp))); } -#[bench] -fn rayon_fastexp_regular(bench: &mut Bencher) +fn rayon_fastexp_regular(c: &mut Criterion) { set_threads(); let mut a = Array2::::zeros((FASTEXP, FASTEXP)); - bench.iter(|| { - a.view_mut().into_par_iter().for_each(|x| *x = fastexp(*x)); + c.bench_function("rayon_fastexp_regular", |b| { + b.iter(|| { + a.view_mut().into_par_iter().for_each(|x| *x = fastexp(*x)); + }); }); } -#[bench] -fn map_fastexp_cut(bench: &mut Bencher) +fn map_fastexp_cut(c: &mut Criterion) { let mut a = Array2::::zeros((FASTEXP, FASTEXP)); let mut a = a.slice_mut(s![.., ..-1]); - bench.iter(|| a.mapv_inplace(fastexp)); + c.bench_function("map_fastexp_cut", |b| b.iter(|| a.mapv_inplace(fastexp))); } -#[bench] -fn rayon_fastexp_cut(bench: &mut Bencher) +fn rayon_fastexp_cut(c: &mut Criterion) { set_threads(); let mut a = Array2::::zeros((FASTEXP, FASTEXP)); let mut a = a.slice_mut(s![.., ..-1]); - bench.iter(|| { - a.view_mut().into_par_iter().for_each(|x| *x = fastexp(*x)); + c.bench_function("rayon_fastexp_cut", |b| { + b.iter(|| { + a.view_mut().into_par_iter().for_each(|x| *x = fastexp(*x)); + }); }); } -#[bench] -fn map_fastexp_by_axis(bench: &mut Bencher) +fn map_fastexp_by_axis(c: &mut Criterion) { let mut a = Array2::::zeros((FASTEXP, FASTEXP)); - bench.iter(|| { - for mut sheet in a.axis_iter_mut(Axis(0)) { - sheet.mapv_inplace(fastexp) - } + c.bench_function("map_fastexp_by_axis", |b| { + b.iter(|| { + for mut sheet in a.axis_iter_mut(Axis(0)) { + sheet.mapv_inplace(fastexp) + } + }); }); } -#[bench] -fn rayon_fastexp_by_axis(bench: &mut Bencher) +fn rayon_fastexp_by_axis(c: &mut Criterion) { set_threads(); let mut a = Array2::::zeros((FASTEXP, FASTEXP)); - bench.iter(|| { - a.axis_iter_mut(Axis(0)) - .into_par_iter() - .for_each(|mut sheet| sheet.mapv_inplace(fastexp)); + c.bench_function("rayon_fastexp_by_axis", |b| { + b.iter(|| { + a.axis_iter_mut(Axis(0)) + .into_par_iter() + .for_each(|mut sheet| sheet.mapv_inplace(fastexp)); + }); }); } -#[bench] -fn rayon_fastexp_zip(bench: &mut Bencher) +fn rayon_fastexp_zip(c: &mut Criterion) { set_threads(); let mut a = Array2::::zeros((FASTEXP, FASTEXP)); - bench.iter(|| { - Zip::from(&mut a) - .into_par_iter() - .for_each(|(elt,)| *elt = fastexp(*elt)); + c.bench_function("rayon_fastexp_zip", |b| { + b.iter(|| { + Zip::from(&mut a) + .into_par_iter() + .for_each(|(elt,)| *elt = fastexp(*elt)); + }); }); } -#[bench] -fn add(bench: &mut Bencher) +fn add(c: &mut Criterion) { let mut a = Array2::::zeros((ADDN, ADDN)); - let b = Array2::::zeros((ADDN, ADDN)); - let c = Array2::::zeros((ADDN, ADDN)); + let b_arr = Array2::::zeros((ADDN, ADDN)); + let c_arr = Array2::::zeros((ADDN, ADDN)); let d = Array2::::zeros((ADDN, ADDN)); - bench.iter(|| { - azip!((a in &mut a, &b in &b, &c in &c, &d in &d) { - *a += b.exp() + c.exp() + d.exp(); + c.bench_function("add", |bench| { + bench.iter(|| { + azip!((a in &mut a, &b in &b_arr, &c in &c_arr, &d in &d) { + *a += b.exp() + c.exp() + d.exp(); + }); }); }); } -#[bench] -fn rayon_add(bench: &mut Bencher) +fn rayon_add(c: &mut Criterion) { set_threads(); let mut a = Array2::::zeros((ADDN, ADDN)); - let b = Array2::::zeros((ADDN, ADDN)); - let c = Array2::::zeros((ADDN, ADDN)); + let b_arr = Array2::::zeros((ADDN, ADDN)); + let c_arr = Array2::::zeros((ADDN, ADDN)); let d = Array2::::zeros((ADDN, ADDN)); - bench.iter(|| { - par_azip!((a in &mut a, b in &b, c in &c, d in &d) { - *a += b.exp() + c.exp() + d.exp(); + c.bench_function("rayon_add", |bench| { + bench.iter(|| { + par_azip!((a in &mut a, b in &b_arr, c in &c_arr, d in &d) { + *a += b.exp() + c.exp() + d.exp(); + }); }); }); } @@ -153,30 +156,54 @@ fn rayon_add(bench: &mut Bencher) const COLL_STRING_N: usize = 64; const COLL_F64_N: usize = 128; -#[bench] -fn vec_string_collect(bench: &mut test::Bencher) +fn vec_string_collect(c: &mut Criterion) { let v = vec![""; COLL_STRING_N * COLL_STRING_N]; - bench.iter(|| v.iter().map(|s| s.to_owned()).collect::>()); + c.bench_function("vec_string_collect", |b| { + b.iter(|| v.iter().map(|s| s.to_owned()).collect::>()); + }); } -#[bench] -fn array_string_collect(bench: &mut test::Bencher) +fn array_string_collect(c: &mut Criterion) { let v = Array::from_elem((COLL_STRING_N, COLL_STRING_N), ""); - bench.iter(|| Zip::from(&v).par_map_collect(|s| s.to_owned())); + c.bench_function("array_string_collect", |b| { + b.iter(|| Zip::from(&v).par_map_collect(|s| s.to_owned())); + }); } -#[bench] -fn vec_f64_collect(bench: &mut test::Bencher) +fn vec_f64_collect(c: &mut Criterion) { let v = vec![1.; COLL_F64_N * COLL_F64_N]; - bench.iter(|| v.iter().map(|s| s + 1.).collect::>()); + c.bench_function("vec_f64_collect", |b| { + b.iter(|| v.iter().map(|s| s + 1.).collect::>()); + }); } -#[bench] -fn array_f64_collect(bench: &mut test::Bencher) +fn array_f64_collect(c: &mut Criterion) { let v = Array::from_elem((COLL_F64_N, COLL_F64_N), 1.); - bench.iter(|| Zip::from(&v).par_map_collect(|s| s + 1.)); + c.bench_function("array_f64_collect", |b| { + b.iter(|| Zip::from(&v).par_map_collect(|s| s + 1.)); + }); } + +criterion_group!( + benches, + map_exp_regular, + rayon_exp_regular, + map_fastexp_regular, + rayon_fastexp_regular, + map_fastexp_cut, + rayon_fastexp_cut, + map_fastexp_by_axis, + rayon_fastexp_by_axis, + rayon_fastexp_zip, + add, + rayon_add, + vec_string_collect, + array_string_collect, + vec_f64_collect, + array_f64_collect +); +criterion_main!(benches); diff --git a/benches/reserve.rs b/benches/reserve.rs index 14ebf9f1..791bbefa 100644 --- a/benches/reserve.rs +++ b/benches/reserve.rs @@ -1,31 +1,32 @@ -#![feature(test)] - -extern crate test; -use test::Bencher; - +use criterion::{criterion_group, criterion_main, Criterion}; use ndarray::prelude::*; -#[bench] -fn push_reserve(bench: &mut Bencher) +fn push_reserve(c: &mut Criterion) { let ones: Array = array![1f32]; - bench.iter(|| { - let mut a: Array = array![]; - a.reserve(Axis(0), 100).unwrap(); - for _ in 0..100 { - a.append(Axis(0), ones.view()).unwrap(); - } + c.bench_function("push_reserve", |b| { + b.iter(|| { + let mut a: Array = array![]; + a.reserve(Axis(0), 100).unwrap(); + for _ in 0..100 { + a.append(Axis(0), ones.view()).unwrap(); + } + }); }); } -#[bench] -fn push_no_reserve(bench: &mut Bencher) +fn push_no_reserve(c: &mut Criterion) { let ones: Array = array![1f32]; - bench.iter(|| { - let mut a: Array = array![]; - for _ in 0..100 { - a.append(Axis(0), ones.view()).unwrap(); - } + c.bench_function("push_no_reserve", |b| { + b.iter(|| { + let mut a: Array = array![]; + for _ in 0..100 { + a.append(Axis(0), ones.view()).unwrap(); + } + }); }); } + +criterion_group!(benches, push_reserve, push_no_reserve); +criterion_main!(benches); diff --git a/benches/to_shape.rs b/benches/to_shape.rs index f056a985..fcf2d927 100644 --- a/benches/to_shape.rs +++ b/benches/to_shape.rs @@ -1,95 +1,118 @@ -#![feature(test)] - -extern crate test; -use test::Bencher; - +use criterion::{criterion_group, criterion_main, Criterion}; use ndarray::prelude::*; use ndarray::Order; -#[bench] -fn to_shape2_1(bench: &mut Bencher) +fn to_shape2_1(c: &mut Criterion) { let a = Array::::zeros((4, 5)); let view = a.view(); - bench.iter(|| view.to_shape(4 * 5).unwrap()); + c.bench_function("to_shape2_1", |b| { + b.iter(|| view.to_shape(4 * 5).unwrap()); + }); } -#[bench] -fn to_shape2_2_same(bench: &mut Bencher) +fn to_shape2_2_same(c: &mut Criterion) { let a = Array::::zeros((4, 5)); let view = a.view(); - bench.iter(|| view.to_shape((4, 5)).unwrap()); + c.bench_function("to_shape2_2_same", |b| { + b.iter(|| view.to_shape((4, 5)).unwrap()); + }); } -#[bench] -fn to_shape2_2_flip(bench: &mut Bencher) +fn to_shape2_2_flip(c: &mut Criterion) { let a = Array::::zeros((4, 5)); let view = a.view(); - bench.iter(|| view.to_shape((5, 4)).unwrap()); + c.bench_function("to_shape2_2_flip", |b| { + b.iter(|| view.to_shape((5, 4)).unwrap()); + }); } -#[bench] -fn to_shape2_3(bench: &mut Bencher) +fn to_shape2_3(c: &mut Criterion) { let a = Array::::zeros((4, 5)); let view = a.view(); - bench.iter(|| view.to_shape((2, 5, 2)).unwrap()); + c.bench_function("to_shape2_3", |b| { + b.iter(|| view.to_shape((2, 5, 2)).unwrap()); + }); } -#[bench] -fn to_shape3_1(bench: &mut Bencher) +fn to_shape3_1(c: &mut Criterion) { let a = Array::::zeros((3, 4, 5)); let view = a.view(); - bench.iter(|| view.to_shape(3 * 4 * 5).unwrap()); + c.bench_function("to_shape3_1", |b| { + b.iter(|| view.to_shape(3 * 4 * 5).unwrap()); + }); } -#[bench] -fn to_shape3_2_order(bench: &mut Bencher) +fn to_shape3_2_order(c: &mut Criterion) { let a = Array::::zeros((3, 4, 5)); let view = a.view(); - bench.iter(|| view.to_shape((12, 5)).unwrap()); + c.bench_function("to_shape3_2_order", |b| { + b.iter(|| view.to_shape((12, 5)).unwrap()); + }); } -#[bench] -fn to_shape3_2_outoforder(bench: &mut Bencher) +fn to_shape3_2_outoforder(c: &mut Criterion) { let a = Array::::zeros((3, 4, 5)); let view = a.view(); - bench.iter(|| view.to_shape((4, 15)).unwrap()); + c.bench_function("to_shape3_2_outoforder", |b| { + b.iter(|| view.to_shape((4, 15)).unwrap()); + }); } -#[bench] -fn to_shape3_3c(bench: &mut Bencher) +fn to_shape3_3c(c: &mut Criterion) { let a = Array::::zeros((3, 4, 5)); let view = a.view(); - bench.iter(|| view.to_shape((3, 4, 5)).unwrap()); + c.bench_function("to_shape3_3c", |b| { + b.iter(|| view.to_shape((3, 4, 5)).unwrap()); + }); } -#[bench] -fn to_shape3_3f(bench: &mut Bencher) +fn to_shape3_3f(c: &mut Criterion) { let a = Array::::zeros((3, 4, 5).f()); let view = a.view(); - bench.iter(|| view.to_shape(((3, 4, 5), Order::F)).unwrap()); + c.bench_function("to_shape3_3f", |b| { + b.iter(|| view.to_shape(((3, 4, 5), Order::F)).unwrap()); + }); } -#[bench] -fn to_shape3_4c(bench: &mut Bencher) +fn to_shape3_4c(c: &mut Criterion) { let a = Array::::zeros((3, 4, 5)); let view = a.view(); - bench.iter(|| view.to_shape(((2, 3, 2, 5), Order::C)).unwrap()); + c.bench_function("to_shape3_4c", |b| { + b.iter(|| view.to_shape(((2, 3, 2, 5), Order::C)).unwrap()); + }); } -#[bench] -fn to_shape3_4f(bench: &mut Bencher) +fn to_shape3_4f(c: &mut Criterion) { let a = Array::::zeros((3, 4, 5).f()); let view = a.view(); - bench.iter(|| view.to_shape(((2, 3, 2, 5), Order::F)).unwrap()); + c.bench_function("to_shape3_4f", |b| { + b.iter(|| view.to_shape(((2, 3, 2, 5), Order::F)).unwrap()); + }); } + +criterion_group!( + benches, + to_shape2_1, + to_shape2_2_same, + to_shape2_2_flip, + to_shape2_3, + to_shape3_1, + to_shape3_2_order, + to_shape3_2_outoforder, + to_shape3_3c, + to_shape3_3f, + to_shape3_4c, + to_shape3_4f +); +criterion_main!(benches); diff --git a/benches/zip.rs b/benches/zip.rs index 46149731..66246842 100644 --- a/benches/zip.rs +++ b/benches/zip.rs @@ -1,9 +1,7 @@ -#![feature(test)] -extern crate test; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; use ndarray::s; use ndarray::IntoNdProducer; use ndarray::{Array3, ShapeBuilder, Zip}; -use test::{black_box, Bencher}; pub fn zip_copy<'a, A, P, Q>(data: P, out: Q) where @@ -44,90 +42,95 @@ pub fn zip_indexed(data: &Array3, out: &mut Array3) // array size in benchmarks const SZ3: (usize, usize, usize) = (100, 110, 100); -#[bench] -fn zip_cc(b: &mut Bencher) +fn zip_cc(c: &mut Criterion) { let data: Array3 = Array3::zeros(SZ3); let mut out = Array3::zeros(data.dim()); - b.iter(|| zip_copy(&data, &mut out)); + c.bench_function("zip_cc", |b| b.iter(|| zip_copy(&data, &mut out))); } -#[bench] -fn zip_cf(b: &mut Bencher) +fn zip_cf(c: &mut Criterion) { let data: Array3 = Array3::zeros(SZ3); let mut out = Array3::zeros(data.dim().f()); - b.iter(|| zip_copy(&data, &mut out)); + c.bench_function("zip_cf", |b| b.iter(|| zip_copy(&data, &mut out))); } -#[bench] -fn zip_fc(b: &mut Bencher) +fn zip_fc(c: &mut Criterion) { let data: Array3 = Array3::zeros(SZ3.f()); let mut out = Array3::zeros(data.dim()); - b.iter(|| zip_copy(&data, &mut out)); + c.bench_function("zip_fc", |b| b.iter(|| zip_copy(&data, &mut out))); } -#[bench] -fn zip_ff(b: &mut Bencher) +fn zip_ff(c: &mut Criterion) { let data: Array3 = Array3::zeros(SZ3.f()); let mut out = Array3::zeros(data.dim().f()); - b.iter(|| zip_copy(&data, &mut out)); + c.bench_function("zip_ff", |b| b.iter(|| zip_copy(&data, &mut out))); } -#[bench] -fn zip_indexed_cc(b: &mut Bencher) +fn zip_indexed_cc(c: &mut Criterion) { let data: Array3 = Array3::zeros(SZ3); let mut out = Array3::zeros(data.dim()); - b.iter(|| zip_indexed(&data, &mut out)); + c.bench_function("zip_indexed_cc", |b| b.iter(|| zip_indexed(&data, &mut out))); } -#[bench] -fn zip_indexed_ff(b: &mut Bencher) +fn zip_indexed_ff(c: &mut Criterion) { let data: Array3 = Array3::zeros(SZ3.f()); let mut out = Array3::zeros(data.dim().f()); - b.iter(|| zip_indexed(&data, &mut out)); + c.bench_function("zip_indexed_ff", |b| b.iter(|| zip_indexed(&data, &mut out))); } -#[bench] -fn slice_zip_cc(b: &mut Bencher) +fn slice_zip_cc(c: &mut Criterion) { let data: Array3 = Array3::zeros(SZ3); let mut out = Array3::zeros(data.dim()); let data = data.slice(s![1.., 1.., 1..]); let mut out = out.slice_mut(s![1.., 1.., 1..]); - b.iter(|| zip_copy(&data, &mut out)); + c.bench_function("slice_zip_cc", |b| b.iter(|| zip_copy(&data, &mut out))); } -#[bench] -fn slice_zip_ff(b: &mut Bencher) +fn slice_zip_ff(c: &mut Criterion) { let data: Array3 = Array3::zeros(SZ3.f()); let mut out = Array3::zeros(data.dim().f()); let data = data.slice(s![1.., 1.., 1..]); let mut out = out.slice_mut(s![1.., 1.., 1..]); - b.iter(|| zip_copy(&data, &mut out)); + c.bench_function("slice_zip_ff", |b| b.iter(|| zip_copy(&data, &mut out))); } -#[bench] -fn slice_split_zip_cc(b: &mut Bencher) +fn slice_split_zip_cc(c: &mut Criterion) { let data: Array3 = Array3::zeros(SZ3); let mut out = Array3::zeros(data.dim()); let data = data.slice(s![1.., 1.., 1..]); let mut out = out.slice_mut(s![1.., 1.., 1..]); - b.iter(|| zip_copy_split(&data, &mut out)); + c.bench_function("slice_split_zip_cc", |b| b.iter(|| zip_copy_split(&data, &mut out))); } -#[bench] -fn slice_split_zip_ff(b: &mut Bencher) +fn slice_split_zip_ff(c: &mut Criterion) { let data: Array3 = Array3::zeros(SZ3.f()); let mut out = Array3::zeros(data.dim().f()); let data = data.slice(s![1.., 1.., 1..]); let mut out = out.slice_mut(s![1.., 1.., 1..]); - b.iter(|| zip_copy_split(&data, &mut out)); + c.bench_function("slice_split_zip_ff", |b| b.iter(|| zip_copy_split(&data, &mut out))); } + +criterion_group!( + benches, + zip_cc, + zip_cf, + zip_fc, + zip_ff, + zip_indexed_cc, + zip_indexed_ff, + slice_zip_cc, + slice_zip_ff, + slice_split_zip_cc, + slice_split_zip_ff +); +criterion_main!(benches); diff --git a/examples/life.rs b/examples/life.rs index a521f34c..c4ee3106 100644 --- a/examples/life.rs +++ b/examples/life.rs @@ -1,4 +1,13 @@ -#![allow(clippy::many_single_char_names, clippy::deref_addrof, clippy::unreadable_literal)] +// `s![1..-1, 1..-1]` / `s![0..-2, 0..-2]` — ndarray's `s!` macro uses +// Python-style negative indexing. Clippy can't see through the macro and +// reads `1..-1` as a plain (empty) Rust range; the actual semantics are +// correct. +#![allow( + clippy::many_single_char_names, + clippy::deref_addrof, + clippy::unreadable_literal, + clippy::reversed_empty_ranges +)] use ndarray::prelude::*; diff --git a/ndarray-rand/Cargo.toml b/ndarray-rand/Cargo.toml index b7169f30..31037644 100644 --- a/ndarray-rand/Cargo.toml +++ b/ndarray-rand/Cargo.toml @@ -31,6 +31,11 @@ quickcheck = { workspace = true, optional = true } [dev-dependencies] rand_isaac = "0.4.0" quickcheck = { workspace = true } +criterion = { version = "0.5", features = ["html_reports"] } + +[[bench]] +name = "bench" +harness = false [package.metadata.release] tag-name = "ndarray-rand-{{version}}" diff --git a/ndarray-rand/benches/bench.rs b/ndarray-rand/benches/bench.rs index 364eca9f..4d8e9370 100644 --- a/ndarray-rand/benches/bench.rs +++ b/ndarray-rand/benches/bench.rs @@ -1,31 +1,32 @@ -#![feature(test)] - -extern crate test; - +use criterion::{criterion_group, criterion_main, Criterion}; use ndarray::Array; use ndarray_rand::RandomExt; use rand_distr::Normal; use rand_distr::Uniform; -use test::Bencher; - -#[bench] -fn uniform_f32(b: &mut Bencher) +fn uniform_f32(c: &mut Criterion) { let m = 100; - b.iter(|| Array::random((m, m), Uniform::new(-1f32, 1.).unwrap())); + c.bench_function("uniform_f32", |b| { + b.iter(|| Array::random((m, m), Uniform::new(-1f32, 1.).unwrap())); + }); } -#[bench] -fn norm_f32(b: &mut Bencher) +fn norm_f32(c: &mut Criterion) { let m = 100; - b.iter(|| Array::random((m, m), Normal::new(0f32, 1.).unwrap())); + c.bench_function("norm_f32", |b| { + b.iter(|| Array::random((m, m), Normal::new(0f32, 1.).unwrap())); + }); } -#[bench] -fn norm_f64(b: &mut Bencher) +fn norm_f64(c: &mut Criterion) { let m = 100; - b.iter(|| Array::random((m, m), Normal::new(0f64, 1.).unwrap())); + c.bench_function("norm_f64", |b| { + b.iter(|| Array::random((m, m), Normal::new(0f64, 1.).unwrap())); + }); } + +criterion_group!(benches, uniform_f32, norm_f32, norm_f64); +criterion_main!(benches); diff --git a/tests/array.rs b/tests/array.rs index 391f88b9..5d5872eb 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -1,4 +1,8 @@ #![allow(non_snake_case)] +// `s![1..-1, ..]` etc. — ndarray's `s!` macro uses Python-style negative +// indexing. Clippy can't see through the macro and reads `1..-1` as a plain +// (empty) Rust range; the actual semantics are correct. +#![allow(clippy::reversed_empty_ranges)] #![allow( clippy::many_single_char_names, clippy::deref_addrof, clippy::unreadable_literal, clippy::float_cmp )] diff --git a/tests/assign.rs b/tests/assign.rs index 29a6b851..4c5aa502 100644 --- a/tests/assign.rs +++ b/tests/assign.rs @@ -1,3 +1,8 @@ +// `s![1..-1, ..;2]` — ndarray's `s!` macro uses Python-style negative +// indexing. Clippy can't see through the macro and reads `1..-1` as a +// plain (empty) Rust range; the actual semantics are correct. +#![allow(clippy::reversed_empty_ranges)] + use ndarray::prelude::*; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/oper.rs b/tests/oper.rs index a6d7054b..0a0d1b4b 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -1,4 +1,6 @@ #![allow(clippy::many_single_char_names, clippy::deref_addrof, clippy::unreadable_literal)] +use std::mem::MaybeUninit; + use ndarray::linalg::general_mat_mul; use ndarray::linalg::kron; use ndarray::prelude::*; @@ -297,16 +299,19 @@ where let ((m, k), (k2, n)) = (lhs.dim(), rhs.dim()); assert!(m.checked_mul(n).is_some()); assert_eq!(k, k2); - let mut res_elems = Vec::::with_capacity(m * n); - unsafe { - res_elems.set_len(m * n); - } + // SAFETY: We allocate `m * n` MaybeUninit slots, then write into every + // slot exactly once via the `for rr in &mut res_elems` loop below + // (each iteration writes `*rr = ...`). After all writes complete every + // slot is initialized, so it's safe to transmute the buffer to + // `Vec` via `assume_init`. + let mut res_elems: Vec> = Vec::with_capacity(m * n); + res_elems.resize_with(m * n, MaybeUninit::uninit); let mut i = 0; let mut j = 0; for rr in &mut res_elems { unsafe { - *rr = (0..k).fold(A::zero(), move |s, x| s + *lhs.uget((i, x)) * *rhs.uget((x, j))); + rr.write((0..k).fold(A::zero(), move |s, x| s + *lhs.uget((i, x)) * *rhs.uget((x, j)))); } j += 1; if j == n { @@ -314,6 +319,11 @@ where i += 1; } } + // SAFETY: every slot was initialized in the loop above. + let res_elems: Vec = unsafe { + let mut me = std::mem::ManuallyDrop::new(res_elems); + Vec::from_raw_parts(me.as_mut_ptr() as *mut A, me.len(), me.capacity()) + }; unsafe { ArrayBase::from_shape_vec_unchecked((m, n), res_elems) } } From 6e0ce888e8a980de60381f1dfeb6ecce86e09959 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 13 May 2026 06:46:43 +0000 Subject: [PATCH 2/2] fix(hpc): clear last 5 clippy errors in lib doctest scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to bench migration commit (cb5caad). Removes the 5 lib-level clippy errors that surfaced under `cargo clippy --lib --tests`: - src/hpc/quantized.rs:431 — test fixture array used 3.14 as an arbitrary roundtrip value; clippy::approx_constant flagged it as approximate PI. Changed to 2.5 (still arbitrary, no longer triggers the lint). - src/hpc/blackboard.rs:484-485 — `bb.alloc_f32("x", 3.14)` + matching get assertion. Same case: arbitrary slot value, not actually PI. (The f64 sibling test correctly uses `std::f64::consts::PI` keyed as "pi" — kept unchanged.) Changed both 3.14 occurrences to 2.5. - src/hpc/jitson/parser.rs:487 — JSON parsing test with input `{"flt": 3.14, ...}` and matching float assertion. Both the JSON literal and the assertion changed to 2.5 in lockstep. - src/hpc/renderer.rs:428 — `assert!(GLOBAL_RENDERER.tick_count() >= 0)` was always true (u64 ≥ 0). The function-doc comment says "First-touch: tick count is 0", so the intent was an equality assertion. Changed to `assert_eq!(..., 0)`. Verification: `cargo clippy --all-targets --features rayon --no-deps` returns 0 errors across lib + tests + examples + benches + lib doctests. Remaining: 253 lib warnings (mostly unused imports + manual_div_ceil / manual_is_multiple_of mechanical lints; cargo clippy --fix can apply 107 of them automatically — separate cleanup commit if wanted). --- src/hpc/blackboard.rs | 4 ++-- src/hpc/jitson/parser.rs | 4 ++-- src/hpc/quantized.rs | 2 +- src/hpc/renderer.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hpc/blackboard.rs b/src/hpc/blackboard.rs index e1f1ac2a..3dde6572 100644 --- a/src/hpc/blackboard.rs +++ b/src/hpc/blackboard.rs @@ -481,8 +481,8 @@ mod tests { #[test] fn test_alloc_get_f32() { let mut bb = Blackboard::new(); - bb.alloc_f32("x", 3.14); - assert_eq!(bb.get_f32("x"), Some(&3.14)); + bb.alloc_f32("x", 2.5); + assert_eq!(bb.get_f32("x"), Some(&2.5)); assert_eq!(bb.get_f32("y"), None); } diff --git a/src/hpc/jitson/parser.rs b/src/hpc/jitson/parser.rs index f9dc8e86..001b0e4d 100644 --- a/src/hpc/jitson/parser.rs +++ b/src/hpc/jitson/parser.rs @@ -481,10 +481,10 @@ mod tests { #[test] fn test_parse_negative_and_float() { - let input = r#"{"neg": -42, "flt": 3.14, "exp": 1e10}"#; + let input = r#"{"neg": -42, "flt": 2.5, "exp": 1e10}"#; let root = parse_json(input).unwrap(); assert!((root.get("neg").unwrap().as_f64().unwrap() - (-42.0)).abs() < 1e-10); - assert!((root.get("flt").unwrap().as_f64().unwrap() - 3.14).abs() < 1e-10); + assert!((root.get("flt").unwrap().as_f64().unwrap() - 2.5).abs() < 1e-10); assert!((root.get("exp").unwrap().as_f64().unwrap() - 1e10).abs() < 1.0); } diff --git a/src/hpc/quantized.rs b/src/hpc/quantized.rs index ffd228ca..84a9e8d9 100644 --- a/src/hpc/quantized.rs +++ b/src/hpc/quantized.rs @@ -428,7 +428,7 @@ mod tests { #[test] fn test_bf16_roundtrip() { - let values = [1.0f32, -1.0, 0.0, 3.14, 1000.0, 0.001]; + let values = [1.0f32, -1.0, 0.0, 2.5, 1000.0, 0.001]; for &v in &values { let bf = BF16::from_f32(v); let back = bf.to_f32(); diff --git a/src/hpc/renderer.rs b/src/hpc/renderer.rs index 242560ff..b7cab349 100644 --- a/src/hpc/renderer.rs +++ b/src/hpc/renderer.rs @@ -425,7 +425,7 @@ mod tests { let _ = &*GLOBAL_RENDERER; // First-touch: tick count is 0; capacity is at least 4096 // (could be greater if PREFERRED_F32_LANES > 16 at some future tier). - assert!(GLOBAL_RENDERER.tick_count() >= 0); + assert_eq!(GLOBAL_RENDERER.tick_count(), 0); let f = GLOBAL_RENDERER.read_front(); assert!(f.capacity >= 4096); }