#![allow(clippy::result_large_err)]
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use numrs2::prelude::*;
use scirs2_core::simd_ops::SimdUnifiedOps;
use std::hint::black_box;
fn bench_simd_vs_scalar_addition(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_vs_scalar_addition");
for size in [16, 64, 256, 1024, 4096, 16384, 65536].iter() {
group.bench_with_input(BenchmarkId::new("scalar_f64", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f64>(&[s]), rng.random::<f64>(&[s])) {
bencher.iter(|| {
let vec_a = a.to_vec();
let vec_b = b.to_vec();
let result: Vec<f64> = vec_a
.iter()
.zip(vec_b.iter())
.map(|(&x, &y)| x + y)
.collect();
black_box(result);
});
}
});
group.bench_with_input(BenchmarkId::new("simd_f64", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f64>(&[s]), rng.random::<f64>(&[s])) {
bencher.iter(|| {
let result = &a + &b;
black_box(result);
});
}
});
}
group.finish();
}
fn bench_simd_vs_scalar_multiplication(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_vs_scalar_multiplication");
for size in [16, 64, 256, 1024, 4096, 16384, 65536].iter() {
group.bench_with_input(BenchmarkId::new("scalar_f64", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f64>(&[s]), rng.random::<f64>(&[s])) {
bencher.iter(|| {
let vec_a = a.to_vec();
let vec_b = b.to_vec();
let result: Vec<f64> = vec_a
.iter()
.zip(vec_b.iter())
.map(|(&x, &y)| x * y)
.collect();
black_box(result);
});
}
});
group.bench_with_input(BenchmarkId::new("simd_f64", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f64>(&[s]), rng.random::<f64>(&[s])) {
bencher.iter(|| {
let result = &a * &b;
black_box(result);
});
}
});
}
group.finish();
}
fn bench_simd_vs_scalar_division(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_vs_scalar_division");
for size in [16, 64, 256, 1024, 4096, 16384, 65536].iter() {
group.bench_with_input(BenchmarkId::new("scalar_f64", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f64>(&[s]), rng.uniform::<f64>(0.1, 10.0, &[s])) {
bencher.iter(|| {
let vec_a = a.to_vec();
let vec_b = b.to_vec();
let result: Vec<f64> = vec_a
.iter()
.zip(vec_b.iter())
.map(|(&x, &y)| x / y)
.collect();
black_box(result);
});
}
});
group.bench_with_input(BenchmarkId::new("simd_f64", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f64>(&[s]), rng.uniform::<f64>(0.1, 10.0, &[s])) {
bencher.iter(|| {
let result = &a / &b;
black_box(result);
});
}
});
}
group.finish();
}
fn bench_simd_reductions(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_reductions");
for size in [16, 64, 256, 1024, 4096, 16384, 65536].iter() {
group.bench_with_input(BenchmarkId::new("scalar_sum", size), size, |bencher, &s| {
let rng = random::default_rng();
if let Ok(arr) = rng.random::<f64>(&[s]) {
bencher.iter(|| {
let vec = arr.to_vec();
let result: f64 = vec.iter().sum();
black_box(result);
});
}
});
group.bench_with_input(BenchmarkId::new("simd_sum", size), size, |bencher, &s| {
let rng = random::default_rng();
if let Ok(arr) = rng.random::<f64>(&[s]) {
bencher.iter(|| {
if let Ok(result) = sum(&arr, None, false) {
black_box(result);
}
});
}
});
group.bench_with_input(
BenchmarkId::new("scalar_product", size),
size,
|bencher, &s| {
let rng = random::default_rng();
if let Ok(arr) = rng.uniform::<f64>(0.99, 1.01, &[s]) {
bencher.iter(|| {
let vec = arr.to_vec();
let result: f64 = vec.iter().product();
black_box(result);
});
}
},
);
group.bench_with_input(
BenchmarkId::new("simd_product", size),
size,
|bencher, &s| {
let rng = random::default_rng();
if let Ok(arr) = rng.uniform::<f64>(0.99, 1.01, &[s]) {
bencher.iter(|| {
if let Ok(result) = prod(&arr, None, false, None) {
black_box(result);
}
});
}
},
);
}
group.finish();
}
fn bench_simd_threshold_analysis(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_threshold_analysis");
for size in [4, 8, 16, 32, 64, 128].iter() {
group.bench_with_input(BenchmarkId::new("scalar", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f64>(&[s]), rng.random::<f64>(&[s])) {
bencher.iter(|| {
let vec_a = a.to_vec();
let vec_b = b.to_vec();
let result: Vec<f64> = vec_a
.iter()
.zip(vec_b.iter())
.map(|(&x, &y)| x + y)
.collect();
black_box(result);
});
}
});
group.bench_with_input(BenchmarkId::new("simd", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f64>(&[s]), rng.random::<f64>(&[s])) {
bencher.iter(|| {
let result = &a + &b;
black_box(result);
});
}
});
}
group.finish();
}
fn bench_simd_data_types(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_data_types");
for size in [256, 1024, 4096, 16384].iter() {
group.bench_with_input(BenchmarkId::new("f32_add", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f32>(&[s]), rng.random::<f32>(&[s])) {
bencher.iter(|| {
let result = &a + &b;
black_box(result);
});
}
});
group.bench_with_input(BenchmarkId::new("f64_add", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f64>(&[s]), rng.random::<f64>(&[s])) {
bencher.iter(|| {
let result = &a + &b;
black_box(result);
});
}
});
group.bench_with_input(BenchmarkId::new("f32_mul", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f32>(&[s]), rng.random::<f32>(&[s])) {
bencher.iter(|| {
let result = &a * &b;
black_box(result);
});
}
});
group.bench_with_input(BenchmarkId::new("f64_mul", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f64>(&[s]), rng.random::<f64>(&[s])) {
bencher.iter(|| {
let result = &a * &b;
black_box(result);
});
}
});
}
group.finish();
}
fn bench_simd_math_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_math_operations");
for size in [256, 1024, 4096, 16384].iter() {
group.bench_with_input(BenchmarkId::new("scalar_exp", size), size, |bencher, &s| {
let rng = random::default_rng();
if let Ok(arr) = rng.uniform::<f64>(-2.0, 2.0, &[s]) {
bencher.iter(|| {
let vec = arr.to_vec();
let result: Vec<f64> = vec.iter().map(|&x| x.exp()).collect();
black_box(result);
});
}
});
group.bench_with_input(BenchmarkId::new("simd_exp", size), size, |bencher, &s| {
let rng = random::default_rng();
if let Ok(arr) = rng.uniform::<f64>(-2.0, 2.0, &[s]) {
bencher.iter(|| {
let result = exp(&arr);
black_box(result);
});
}
});
group.bench_with_input(
BenchmarkId::new("scalar_sqrt", size),
size,
|bencher, &s| {
let rng = random::default_rng();
if let Ok(arr) = rng.uniform::<f64>(0.1, 100.0, &[s]) {
bencher.iter(|| {
let vec = arr.to_vec();
let result: Vec<f64> = vec.iter().map(|&x| x.sqrt()).collect();
black_box(result);
});
}
},
);
group.bench_with_input(BenchmarkId::new("simd_sqrt", size), size, |bencher, &s| {
let rng = random::default_rng();
if let Ok(arr) = rng.uniform::<f64>(0.1, 100.0, &[s]) {
bencher.iter(|| {
let result = sqrt(&arr);
black_box(result);
});
}
});
}
group.finish();
}
fn bench_simd_alignment(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_alignment");
for size in [256, 1024, 4096].iter() {
group.bench_with_input(BenchmarkId::new("aligned", size), size, |bencher, &s| {
let rng = random::default_rng();
if let (Ok(a), Ok(b)) = (rng.random::<f64>(&[s]), rng.random::<f64>(&[s])) {
bencher.iter(|| {
let result = &a + &b;
black_box(result);
});
}
});
}
group.finish();
}
criterion_group!(
benches,
bench_simd_vs_scalar_addition,
bench_simd_vs_scalar_multiplication,
bench_simd_vs_scalar_division,
bench_simd_reductions,
bench_simd_threshold_analysis,
bench_simd_data_types,
bench_simd_math_operations,
bench_simd_alignment,
);
criterion_main!(benches);