use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId, Throughput};
use std::time::Duration;
use rand::prelude::*;
use micro_core::types::{RootVector, RootSpace, CartanMatrix};
fn bench_simd_dot_product(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_dot_product");
group.sample_size(1000);
group.measurement_time(Duration::from_secs(3));
let mut rng = thread_rng();
let v1 = RootVector::from_array(core::array::from_fn(|_| rng.gen_range(-1.0..1.0)));
let v2 = RootVector::from_array(core::array::from_fn(|_| rng.gen_range(-1.0..1.0)));
group.throughput(Throughput::Elements(32));
#[cfg(feature = "simd")]
group.bench_function("simd_dot", |b| {
b.iter(|| {
black_box(v1.dot(black_box(&v2)))
});
});
group.bench_function("scalar_dot", |b| {
b.iter(|| {
let result = v1.data.iter()
.zip(v2.data.iter())
.map(|(a, b)| a * b)
.sum::<f32>();
black_box(result)
});
});
group.finish();
}
fn bench_simd_vector_ops(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_vector_ops");
group.sample_size(1000);
let mut rng = thread_rng();
let mut v1 = RootVector::from_array(core::array::from_fn(|_| rng.gen_range(-1.0..1.0)));
let v2 = RootVector::from_array(core::array::from_fn(|_| rng.gen_range(-1.0..1.0)));
let scalar = rng.gen_range(0.1..2.0);
group.throughput(Throughput::Elements(32));
group.bench_function("simd_add", |b| {
b.iter(|| {
let mut v = v1;
v.add_assign(black_box(&v2));
black_box(v)
});
});
group.bench_function("simd_scale", |b| {
b.iter(|| {
let mut v = v1;
v.scale(black_box(scalar));
black_box(v)
});
});
group.bench_function("scalar_add", |b| {
b.iter(|| {
let mut result = v1;
for i in 0..32 {
result.data[i] += v2.data[i];
}
black_box(result)
});
});
group.bench_function("scalar_scale", |b| {
b.iter(|| {
let mut result = v1;
for i in 0..32 {
result.data[i] *= scalar;
}
black_box(result)
});
});
group.finish();
}
fn bench_simd_matrix_ops(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_matrix_ops");
group.sample_size(100);
group.measurement_time(Duration::from_secs(5));
let root_space = RootSpace::new();
let mut rng = thread_rng();
for input_size in [768, 1024, 2048, 4096].iter() {
let input: Vec<f32> = (0..*input_size)
.map(|_| rng.gen_range(-1.0..1.0))
.collect();
group.throughput(Throughput::Elements(*input_size as u64));
#[cfg(feature = "simd")]
group.bench_with_input(
BenchmarkId::new("simd_projection", input_size),
input_size,
|b, _| {
b.iter(|| {
root_space.project_simd(black_box(&input))
});
},
);
group.bench_with_input(
BenchmarkId::new("regular_projection", input_size),
input_size,
|b, _| {
b.iter(|| {
root_space.project(black_box(&input))
});
},
);
}
group.finish();
}
fn bench_simd_cartan_matrix(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_cartan_matrix");
group.sample_size(100);
let mut rng = thread_rng();
let matrix1 = CartanMatrix {
data: core::array::from_fn(|_| core::array::from_fn(|_| rng.gen_range(-1.0..1.0)))
};
let matrix2 = CartanMatrix {
data: core::array::from_fn(|_| core::array::from_fn(|_| rng.gen_range(-1.0..1.0)))
};
group.throughput(Throughput::Elements(32 * 32));
group.bench_function("simd_frobenius", |b| {
b.iter(|| {
matrix1.frobenius_distance(black_box(&matrix2))
});
});
group.bench_function("scalar_frobenius", |b| {
b.iter(|| {
let mut sum = 0.0f32;
for i in 0..32 {
for j in 0..32 {
let diff = matrix1.data[i][j] - matrix2.data[i][j];
sum += diff * diff;
}
}
black_box(sum.sqrt())
});
});
group.finish();
}
fn bench_simd_memory_throughput(c: &mut Criterion) {
let mut group = c.benchmark_group("simd_memory_throughput");
group.sample_size(1000);
let mut rng = thread_rng();
let data: Vec<RootVector> = (0..1000)
.map(|_| RootVector::from_array(core::array::from_fn(|_| rng.gen_range(-1.0..1.0))))
.collect();
group.throughput(Throughput::Elements(1000 * 32));
group.bench_function("simd_batch_dot", |b| {
b.iter(|| {
let mut sum = 0.0f32;
for i in 0..data.len() - 1 {
sum += data[i].dot(&data[i + 1]);
}
black_box(sum)
});
});
group.bench_function("simd_batch_add", |b| {
b.iter(|| {
let mut result = data[0];
for i in 1..100 {
result.add_assign(&data[i]);
}
black_box(result)
});
});
group.finish();
}
#[cfg(target_arch = "wasm32")]
fn bench_wasm_simd_comparison(c: &mut Criterion) {
let mut group = c.benchmark_group("wasm_simd_comparison");
group.sample_size(500);
let mut rng = thread_rng();
let v1 = RootVector::from_array(core::array::from_fn(|_| rng.gen_range(-1.0..1.0)));
let v2 = RootVector::from_array(core::array::from_fn(|_| rng.gen_range(-1.0..1.0)));
group.throughput(Throughput::Elements(32));
#[cfg(feature = "simd-wasm")]
group.bench_function("wasm_simd_dot", |b| {
b.iter(|| {
black_box(v1.dot(black_box(&v2)))
});
});
group.bench_function("wasm_scalar_dot", |b| {
b.iter(|| {
let result = v1.data.iter()
.zip(v2.data.iter())
.map(|(a, b)| a * b)
.sum::<f32>();
black_box(result)
});
});
group.finish();
}
fn bench_performance_regression(c: &mut Criterion) {
let mut group = c.benchmark_group("performance_regression");
group.sample_size(1000);
group.significance_level(0.02);
let mut rng = thread_rng();
let vectors: Vec<_> = (0..100)
.map(|_| RootVector::from_array(core::array::from_fn(|_| rng.gen_range(-1.0..1.0))))
.collect();
group.bench_function("intensive_simd_operations", |b| {
b.iter(|| {
let mut accumulator = vectors[0];
for i in 1..vectors.len() {
let dot = accumulator.dot(&vectors[i]);
accumulator.scale(dot * 0.01);
accumulator.add_assign(&vectors[i % 10]);
}
black_box(accumulator)
});
});
group.bench_function("intensive_scalar_operations", |b| {
b.iter(|| {
let mut accumulator = vectors[0];
for i in 1..vectors.len() {
let mut dot = 0.0f32;
for j in 0..32 {
dot += accumulator.data[j] * vectors[i].data[j];
}
for j in 0..32 {
accumulator.data[j] *= dot * 0.01;
}
for j in 0..32 {
accumulator.data[j] += vectors[i % 10].data[j];
}
}
black_box(accumulator)
});
});
group.finish();
}
criterion_group!(
simd_benches,
bench_simd_dot_product,
bench_simd_vector_ops,
bench_simd_matrix_ops,
bench_simd_cartan_matrix,
bench_simd_memory_throughput,
bench_performance_regression
);
#[cfg(target_arch = "wasm32")]
criterion_group!(
wasm_benches,
bench_wasm_simd_comparison
);
#[cfg(not(target_arch = "wasm32"))]
criterion_main!(simd_benches);
#[cfg(target_arch = "wasm32")]
criterion_main!(simd_benches, wasm_benches);