use std::time::{Duration, Instant};
use himada_dispatch::{
adapt::AdaptiveEngine, kernels, AddF32Kernel, ArgmaxF32Kernel, ArgmaxKernel, BinaryOpKernel,
ClampF32Kernel, ClampKernel, Dispatch, DotF32Kernel, DotKernel, KernelInfo, MatMulBiasReluKernel,
MatMulF32Kernel, MatMulKernel, MemchrKernel, NegateF32Kernel, ReduceKernel, ReduceSumF32Kernel,
SoftmaxKernel, UnaryOpF32Kernel,
};
use himada_macros::{himada_adapt, himada_optimize};
const N: usize = 10_000_000;
const ITERS: usize = 10;
fn pure_dot(a: &[f64], b: &[f64]) -> f64 {
let mut sum = 0.0;
for i in 0..a.len().min(b.len()) { sum += a[i] * b[i]; }
sum
}
fn pure_euclidean(a: &[f64], b: &[f64]) -> f64 {
let mut sum = 0.0;
for i in 0..a.len().min(b.len()) { let d = a[i] - b[i]; sum += d * d; }
sum.sqrt()
}
fn pure_cosine(a: &[f64], b: &[f64]) -> f64 {
let mut dot = 0.0; let mut na = 0.0; let mut nb = 0.0;
for i in 0..a.len().min(b.len()) {
dot += a[i] * b[i]; na += a[i] * a[i]; nb += b[i] * b[i];
}
dot / (na.sqrt() * nb.sqrt())
}
fn pure_hadamard(a: &[f64], b: &[f64], c: &mut [f64]) {
for i in 0..a.len().min(b.len()).min(c.len()) { c[i] = a[i] * b[i]; }
}
fn pure_add(a: &[f64], b: &[f64], c: &mut [f64]) {
for i in 0..a.len().min(b.len()).min(c.len()) { c[i] = a[i] + b[i]; }
}
fn pure_sub(a: &[f64], b: &[f64], c: &mut [f64]) {
for i in 0..a.len().min(b.len()).min(c.len()) { c[i] = a[i] - b[i]; }
}
fn pure_mul(a: &[f64], b: &[f64], c: &mut [f64]) {
for i in 0..a.len().min(b.len()).min(c.len()) { c[i] = a[i] * b[i]; }
}
fn pure_negate(a: &[f64], c: &mut [f64]) {
for i in 0..a.len().min(c.len()) { c[i] = -a[i]; }
}
fn pure_clamp(a: &[f64], lo: f64, hi: f64, c: &mut [f64]) {
for i in 0..a.len().min(c.len()) { c[i] = a[i].clamp(lo, hi); }
}
fn pure_reduce_sum(a: &[f64]) -> f64 {
let mut s = 0.0; for &v in a { s += v; } s
}
fn pure_reduce_max(a: &[f64]) -> f64 {
let mut m = f64::NEG_INFINITY; for &v in a { if v > m { m = v; } } m
}
fn pure_abs_max(a: &[f64]) -> f64 {
let mut m = 0.0; for &v in a { let av = v.abs(); if av > m { m = av; } } m
}
fn pure_argmax(a: &[f64]) -> usize {
let mut idx = 0; let mut max = f64::NEG_INFINITY;
for (i, &v) in a.iter().enumerate() { if v > max { max = v; idx = i; } }
idx
}
fn pure_softmax(input: &[f64], output: &mut [f64]) {
let max = input.iter().copied().fold(f64::NEG_INFINITY, f64::max);
let mut sum = 0.0;
for i in 0..input.len() { let e = (input[i] - max).exp(); output[i] = e; sum += e; }
let inv = 1.0 / sum;
for v in output.iter_mut() { *v *= inv; }
}
fn pure_memchr(byte: u8, data: &[u8]) -> Option<usize> { data.iter().position(|&b| b == byte) }
fn pure_matmul(a: &[f64], b: &[f64], c: &mut [f64], n: usize) {
for i in 0..n { for k in 0..n { let aik = a[i * n + k]; for j in 0..n { c[i * n + j] += aik * b[k * n + j]; } } }
}
fn pure_matmul_bias_relu(a: &[f64], w: &[f64], bias: &[f64], c: &mut [f64], m: usize, k: usize, n: usize) {
for i in 0..m {
for j in 0..n {
let mut sum = 0.0;
for t in 0..k { sum += a[i * k + t] * w[t * n + j]; }
sum += bias[j];
c[i * n + j] = if sum > 0.0 { sum } else { 0.0 };
}
}
}
fn pure_dot_f32(a: &[f32], b: &[f32]) -> f32 {
let mut sum = 0.0; for i in 0..a.len().min(b.len()) { sum += a[i] * b[i]; } sum
}
fn pure_reduce_sum_f32(a: &[f32]) -> f32 {
let mut s = 0.0; for &v in a { s += v; } s
}
fn pure_reduce_max_f32(a: &[f32]) -> f32 {
let mut m = f32::NEG_INFINITY; for &v in a { if v > m { m = v; } } m
}
fn pure_abs_max_f32(a: &[f32]) -> f32 {
let mut m = 0.0; for &v in a { let av = v.abs(); if av > m { m = av; } } m
}
fn pure_negate_f32(a: &[f32], c: &mut [f32]) {
for i in 0..a.len().min(c.len()) { c[i] = -a[i]; }
}
fn pure_clamp_f32(a: &[f32], lo: f32, hi: f32, c: &mut [f32]) {
for i in 0..a.len().min(c.len()) { c[i] = a[i].clamp(lo, hi); }
}
fn pure_cosine_f32(a: &[f32], b: &[f32]) -> f32 {
let mut dot = 0.0; let mut na = 0.0; let mut nb = 0.0;
for i in 0..a.len().min(b.len()) {
dot += a[i] * b[i]; na += a[i] * a[i]; nb += b[i] * b[i];
}
dot / (na.sqrt() * nb.sqrt())
}
fn pure_argmax_f32(a: &[f32]) -> usize {
let mut idx = 0;
let mut max = f32::NEG_INFINITY;
for (i, &v) in a.iter().enumerate() {
if v > max { max = v; idx = i; }
}
idx
}
fn pure_euclidean_f32(a: &[f32], b: &[f32]) -> f32 {
let mut sum = 0.0;
for i in 0..a.len().min(b.len()) { let d = a[i] - b[i]; sum += d * d; }
sum.sqrt()
}
fn pure_add_f32(a: &[f32], b: &[f32], c: &mut [f32]) {
for i in 0..a.len().min(b.len()).min(c.len()) { c[i] = a[i] + b[i]; }
}
fn pure_sub_f32(a: &[f32], b: &[f32], c: &mut [f32]) {
for i in 0..a.len().min(b.len()).min(c.len()) { c[i] = a[i] - b[i]; }
}
fn pure_mul_f32(a: &[f32], b: &[f32], c: &mut [f32]) {
for i in 0..a.len().min(b.len()).min(c.len()) { c[i] = a[i] * b[i]; }
}
fn pure_softmax_f32(input: &[f32], output: &mut [f32]) {
let max = input.iter().copied().fold(f32::NEG_INFINITY, f32::max);
let n = input.len().min(output.len());
let mut sum = 0.0;
for i in 0..n {
let e = (input[i] - max).exp();
output[i] = e;
sum += e;
}
for i in 0..n {
output[i] /= sum;
}
}
fn pure_matmul_f32(a: &[f32], b: &[f32], c: &mut [f32], n: usize) {
for i in 0..n {
for j in 0..n {
let mut sum = 0.0;
for k in 0..n {
sum += a[i * n + k] * b[k * n + j];
}
c[i * n + j] = sum;
}
}
}
fn bench_all_f64() {
let n = N;
let a: Vec<f64> = (0..n).map(|i| (i % 100) as f64).collect();
let b: Vec<f64> = (0..n).map(|i| (i % 200 + 50) as f64).collect();
let mut tmp = vec![0.0; n];
let mut out = vec![0.0; n];
println!("╔══════════════════════════════════════════════════════════════╗");
println!("║ f64 Operations (n = {}) ║", n);
println!("╚══════════════════════════════════════════════════════════════╝\n");
let mut d = Dispatch::<DotKernel>::new("dot", vec![
KernelInfo { name: "scalar", func: kernels::dot_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::dot_sse, is_supported: kernels::dot_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::dot_avx2, is_supported: kernels::dot_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::dot_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::dot_f64_sve, is_supported: kernels::dot_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let flops = 2.0 * n as f64 / 1e9;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a, &b)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_dot(&a, &b)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" dot_product himada ({:<8}) {:>8.3} ms {:>5.2} GFLOP/s {:>5.2}x", kn, h*1000.0, flops/h, p/h);
let mut d = Dispatch::<DotKernel>::new("euclidean", vec![
KernelInfo { name: "scalar", func: kernels::euclidean_distance_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::euclidean_distance_f64_sse, is_supported: kernels::euclidean_distance_f64_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::euclidean_distance_f64_avx2, is_supported: kernels::euclidean_distance_f64_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::euclidean_distance_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::euclidean_distance_f64_sve, is_supported: kernels::euclidean_distance_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a, &b)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_euclidean(&a, &b)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" euclidean_distance himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<DotKernel>::new("cosine", vec![
KernelInfo { name: "scalar", func: kernels::cosine_similarity_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::cosine_similarity_f64_sse, is_supported: kernels::cosine_similarity_f64_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::cosine_similarity_f64_avx2, is_supported: kernels::cosine_similarity_f64_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::cosine_similarity_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::cosine_similarity_f64_sve, is_supported: kernels::cosine_similarity_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a, &b)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_cosine(&a, &b)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" cosine_similarity himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<ReduceKernel>::new("reduce_sum", vec![
KernelInfo { name: "scalar", func: kernels::reduce_sum_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::reduce_sum_sse, is_supported: kernels::reduce_sum_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::reduce_sum_avx2, is_supported: kernels::reduce_sum_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::reduce_sum_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::reduce_sum_f64_sve, is_supported: kernels::reduce_sum_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_reduce_sum(&a)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" reduce_sum himada ({:<8}) {:>8.3} ms {:>5.2} GFLOP/s {:>5.2}x", kn, h*1000.0, flops/h, p/h);
let mut d = Dispatch::<ReduceKernel>::new("reduce_max", vec![
KernelInfo { name: "scalar", func: kernels::reduce_max_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::reduce_max_sse, is_supported: kernels::reduce_max_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::reduce_max_avx2, is_supported: kernels::reduce_max_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::reduce_max_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::reduce_max_f64_sve, is_supported: kernels::reduce_max_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_reduce_max(&a)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" reduce_max himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<ReduceKernel>::new("abs_max", vec![
KernelInfo { name: "scalar", func: kernels::abs_max_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::abs_max_f64_sse, is_supported: kernels::abs_max_f64_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::abs_max_f64_avx2, is_supported: kernels::abs_max_f64_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::abs_max_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::abs_max_f64_sve, is_supported: kernels::abs_max_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_abs_max(&a)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" abs_max himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<ArgmaxKernel>::new("argmax", vec![
KernelInfo { name: "scalar", func: kernels::argmax_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::argmax_f64_sse, is_supported: kernels::argmax_f64_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::argmax_f64_avx2, is_supported: kernels::argmax_f64_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::argmax_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::argmax_f64_sve, is_supported: kernels::argmax_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_argmax(&a)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" argmax himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<SoftmaxKernel>::new("softmax", vec![
KernelInfo { name: "scalar", func: kernels::softmax_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::softmax_sse, is_supported: kernels::softmax_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::softmax_avx2, is_supported: kernels::softmax_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::softmax_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::softmax_f64_sve, is_supported: kernels::softmax_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
out.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { out.fill(0.0); d.compute(&a, &mut out); std::hint::black_box(&out[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
out.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { out.fill(0.0); pure_softmax(&a, &mut out); std::hint::black_box(&out[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" softmax himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<BinaryOpKernel>::new("hadamard", vec![
KernelInfo { name: "scalar", func: kernels::hadamard_product_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::hadamard_product_f64_sse, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::hadamard_product_f64_avx2, is_supported: |_| true, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::hadamard_product_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::hadamard_product_f64_sve, is_supported: kernels::hadamard_product_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); d.compute(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); pure_hadamard(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" hadamard_product himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<BinaryOpKernel>::new("add", vec![
KernelInfo { name: "scalar", func: kernels::add_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::hadamard_product_f64_sse, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::hadamard_product_f64_avx2, is_supported: |_| true, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::hadamard_product_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::hadamard_product_f64_sve, is_supported: kernels::hadamard_product_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); d.compute(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); pure_add(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" add himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<BinaryOpKernel>::new("sub", vec![
KernelInfo { name: "scalar", func: kernels::sub_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::hadamard_product_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::hadamard_product_f64_sve, is_supported: kernels::hadamard_product_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); d.compute(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); pure_sub(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" sub himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<BinaryOpKernel>::new("mul", vec![
KernelInfo { name: "scalar", func: kernels::mul_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::hadamard_product_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::hadamard_product_f64_sve, is_supported: kernels::hadamard_product_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); d.compute(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); pure_mul(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" mul himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<SoftmaxKernel>::new("negate", vec![
KernelInfo { name: "scalar", func: kernels::negate_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::negate_f64_sse, is_supported: kernels::negate_f64_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::negate_f64_avx2, is_supported: kernels::negate_f64_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::negate_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::negate_f64_sve, is_supported: kernels::negate_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); d.compute(&a, &mut tmp); std::hint::black_box(&tmp[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); pure_negate(&a, &mut tmp); std::hint::black_box(&tmp[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" negate himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<ClampKernel>::new("clamp", vec![
KernelInfo { name: "scalar", func: kernels::clamp_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::clamp_f64_sse, is_supported: kernels::clamp_f64_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::clamp_f64_avx2, is_supported: kernels::clamp_f64_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::clamp_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::clamp_f64_sve, is_supported: kernels::clamp_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); d.compute(&a, -20.0, 20.0, &mut tmp); std::hint::black_box(&tmp[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); pure_clamp(&a, -20.0, 20.0, &mut tmp); std::hint::black_box(&tmp[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" clamp himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
const M: usize = 512;
let am: Vec<f64> = (0..M * M).map(|i| (i % 5) as f64).collect();
let bm: Vec<f64> = (0..M * M).map(|i| (i % 7) as f64).collect();
let mut cm = vec![0.0; M * M];
let mut d = Dispatch::<MatMulKernel>::new("matmul", vec![
KernelInfo { name: "scalar", func: kernels::matmul_scalar, is_supported: |_| true, thermal_priority: 1 },
KernelInfo { name: "tiled", func: kernels::matmul_tiled, is_supported: |_| true, thermal_priority: 1 },
KernelInfo { name: "cache_tiled", func: kernels::matmul_cache_tiled, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::matmul_sse, is_supported: kernels::matmul_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::matmul_avx2, is_supported: kernels::matmul_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::matmul_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::matmul_f64_sve, is_supported: kernels::matmul_f64_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let mflops = 2.0 * M as f64 * M as f64 * M as f64;
cm.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { cm.fill(0.0); d.compute(&am, &bm, &mut cm, M); std::hint::black_box(&cm[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
cm.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { cm.fill(0.0); pure_matmul(&am, &bm, &mut cm, M); std::hint::black_box(&cm[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" matmul ({}x{}) himada ({:<8}) {:>8.3} ms {:>5.2} GFLOP/s {:>5.2}x", M, M, kn, h*1000.0, mflops/h/1e9, p/h);
const MN: usize = 10_000_000;
let data: Vec<u8> = (0..MN).map(|i| (i % 251) as u8).collect();
let mut d = Dispatch::<MemchrKernel>::new("memchr", vec![
KernelInfo { name: "scalar", func: kernels::memchr_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::memchr_sse, is_supported: kernels::memchr_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::memchr_avx2, is_supported: kernels::memchr_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::memchr_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::memchr_sve, is_supported: kernels::memchr_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(255u8, &data)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_memchr(255u8, &data)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" memchr himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d_fused = Dispatch::<DotKernel>::new("fused_dot_clamp_reduce", vec![
KernelInfo { name: "scalar", func: kernels::dot_clamp_reduce_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::dot_clamp_reduce_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::dot_clamp_reduce_sse, is_supported: kernels::dot_clamp_reduce_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::dot_clamp_reduce_avx2, is_supported: kernels::dot_clamp_reduce_avx2_supported, thermal_priority: 3 },
]);
d_fused.select().ok();
let fused_kn = d_fused.selected_name().to_string();
let mut d_sep_dot = Dispatch::<DotKernel>::new("dot", vec![
KernelInfo { name: "scalar", func: kernels::dot_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::dot_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::dot_f64_sve, is_supported: kernels::dot_f64_sve_supported, thermal_priority: 3 },
]);
let mut d_sep_clamp = Dispatch::<ClampKernel>::new("clamp", vec![
KernelInfo { name: "scalar", func: kernels::clamp_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::clamp_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::clamp_f64_sve, is_supported: kernels::clamp_f64_sve_supported, thermal_priority: 3 },
]);
let mut d_sep_sum = Dispatch::<ReduceKernel>::new("reduce_sum", vec![
KernelInfo { name: "scalar", func: kernels::reduce_sum_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::reduce_sum_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::reduce_sum_f64_sve, is_supported: kernels::reduce_sum_f64_sve_supported, thermal_priority: 3 },
]);
d_sep_dot.select().ok();
d_sep_clamp.select().ok();
d_sep_sum.select().ok();
let start = Instant::now();
for _ in 0..ITERS {
std::hint::black_box(d_fused.compute(&a, &b));
}
let fused_h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS {
let dot_r = d_sep_dot.compute(&a, &b);
for v in tmp.iter_mut() { *v = dot_r; }
d_sep_clamp.compute(&tmp, 0.0, 1.0, &mut out);
std::hint::black_box(d_sep_sum.compute(&out));
}
let separate_h = start.elapsed().as_secs_f64() / ITERS as f64;
let fused_speedup = separate_h / fused_h;
println!(" fused_dot_clamp_reduce himada ({:<8}) {:>8.3} ms separate: {:>8.3} ms speedup: {:>5.2}x",
fused_kn, fused_h * 1000.0, separate_h * 1000.0, fused_speedup);
println!();
const MBR_M: usize = 64;
const MBR_K: usize = 64;
const MBR_N: usize = 64;
let mbr_a: Vec<f64> = (0..MBR_M * MBR_K).map(|i| (i % 5) as f64).collect();
let mbr_w: Vec<f64> = (0..MBR_K * MBR_N).map(|i| (i % 7) as f64).collect();
let mbr_bias: Vec<f64> = (0..MBR_N).map(|i| (i % 3) as f64).collect();
let mut mbr_c = vec![0.0f64; MBR_M * MBR_N];
let mut d_mbr = Dispatch::<MatMulBiasReluKernel>::new("matmul_bias_relu", vec![
KernelInfo { name: "scalar", func: kernels::matmul_bias_relu_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::matmul_bias_relu_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::matmul_bias_relu_sse, is_supported: kernels::matmul_bias_relu_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::matmul_bias_relu_avx2, is_supported: kernels::matmul_bias_relu_avx2_supported, thermal_priority: 3 },
]);
d_mbr.select().ok();
let mbr_kn = d_mbr.selected_name().to_string();
let mbr_iters = 5.max(ITERS / 4);
mbr_c.fill(0.0);
let start = Instant::now();
for _ in 0..mbr_iters { mbr_c.fill(0.0); d_mbr.compute(&mbr_a, &mbr_w, &mbr_bias, &mut mbr_c, MBR_M, MBR_K, MBR_N); std::hint::black_box(&mbr_c[0]); }
let mbr_h = start.elapsed().as_secs_f64() / mbr_iters as f64;
mbr_c.fill(0.0);
let start = Instant::now();
for _ in 0..mbr_iters { mbr_c.fill(0.0); pure_matmul_bias_relu(&mbr_a, &mbr_w, &mbr_bias, &mut mbr_c, MBR_M, MBR_K, MBR_N); std::hint::black_box(&mbr_c[0]); }
let mbr_p = start.elapsed().as_secs_f64() / mbr_iters as f64;
println!(" matmul_bias_relu himada ({:<8}) {:>8.3} ms {:>5.2}x", mbr_kn, mbr_h*1000.0, mbr_p/mbr_h);
println!();
}
fn bench_all_f32() {
let n = N / 2;
let a: Vec<f32> = (0..n).map(|i| (i % 100) as f32).collect();
let b: Vec<f32> = (0..n).map(|i| (i % 200 + 50) as f32).collect();
let mut tmp = vec![0.0; n];
println!("╔══════════════════════════════════════════════════════════════╗");
println!("║ f32 Operations (n = {}) ║", n);
println!("╚══════════════════════════════════════════════════════════════╝\n");
let mut d = Dispatch::<DotF32Kernel>::new("dot_f32", vec![
KernelInfo { name: "scalar", func: kernels::dot_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::dot_f32_sse, is_supported: kernels::dot_f32_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::dot_f32_avx2, is_supported: kernels::dot_f32_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::dot_f32_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::dot_f32_sve, is_supported: kernels::dot_f32_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let flops = 2.0 * n as f64 / 1e9;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a, &b)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_dot_f32(&a, &b)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" dot_product himada ({:<8}) {:>8.3} ms {:>5.2} GFLOP/s {:>5.2}x", kn, h*1000.0, flops/h, p/h);
let mut d = Dispatch::<ReduceSumF32Kernel>::new("reduce_sum_f32", vec![
KernelInfo { name: "scalar", func: kernels::reduce_sum_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::reduce_sum_f32_sse, is_supported: kernels::reduce_sum_f32_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::reduce_sum_f32_avx2, is_supported: kernels::reduce_sum_f32_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::reduce_sum_f32_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::reduce_sum_f32_sve, is_supported: kernels::reduce_sum_f32_sve_supported, thermal_priority: 3 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_reduce_sum_f32(&a)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" reduce_sum himada ({:<8}) {:>8.3} ms {:>5.2} GFLOP/s {:>5.2}x", kn, h*1000.0, flops/h, p/h);
let mut d = Dispatch::<ReduceSumF32Kernel>::new("reduce_max_f32", vec![
KernelInfo { name: "scalar", func: kernels::reduce_max_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::reduce_max_f32_sse, is_supported: kernels::reduce_max_f32_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::reduce_max_f32_avx2, is_supported: kernels::reduce_max_f32_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::reduce_max_f32_neon, is_supported: |_| true, thermal_priority: 2 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_reduce_max_f32(&a)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" reduce_max himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<ReduceSumF32Kernel>::new("abs_max_f32", vec![
KernelInfo { name: "scalar", func: kernels::abs_max_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::abs_max_f32_sse, is_supported: kernels::abs_max_f32_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::abs_max_f32_avx2, is_supported: kernels::abs_max_f32_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::abs_max_f32_neon, is_supported: |_| true, thermal_priority: 2 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_abs_max_f32(&a)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" abs_max himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<ArgmaxF32Kernel>::new("argmax_f32", vec![
KernelInfo { name: "scalar", func: kernels::argmax_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::argmax_f32_sse, is_supported: kernels::argmax_f32_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::argmax_f32_avx2, is_supported: kernels::argmax_f32_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::argmax_f32_neon, is_supported: |_| true, thermal_priority: 2 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_argmax_f32(&a)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" argmax himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<AddF32Kernel>::new("add_f32", vec![
KernelInfo { name: "scalar", func: kernels::add_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::add_f32_sse, is_supported: kernels::add_f32_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::add_f32_avx2, is_supported: kernels::add_f32_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::add_f32_neon, is_supported: |_| true, thermal_priority: 2 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); d.compute(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); pure_add_f32(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" add himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<AddF32Kernel>::new("sub_f32", vec![
KernelInfo { name: "scalar", func: kernels::sub_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); d.compute(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); pure_sub_f32(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" sub himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<AddF32Kernel>::new("mul_f32", vec![
KernelInfo { name: "scalar", func: kernels::mul_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); d.compute(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); pure_mul_f32(&a, &b, &mut tmp); std::hint::black_box(&tmp[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" mul himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<NegateF32Kernel>::new("negate_f32", vec![
KernelInfo { name: "scalar", func: kernels::negate_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::negate_f32_neon, is_supported: |_| true, thermal_priority: 2 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); d.compute(&a, &mut tmp); std::hint::black_box(&tmp[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); pure_negate_f32(&a, &mut tmp); std::hint::black_box(&tmp[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" negate himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<ClampF32Kernel>::new("clamp_f32", vec![
KernelInfo { name: "scalar", func: kernels::clamp_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::clamp_f32_sse, is_supported: kernels::clamp_f32_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::clamp_f32_avx2, is_supported: kernels::clamp_f32_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::clamp_f32_neon, is_supported: |_| true, thermal_priority: 2 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); d.compute(&a, -20.0f32, 20.0f32, &mut tmp); std::hint::black_box(&tmp[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp.fill(0.0); pure_clamp_f32(&a, -20.0, 20.0, &mut tmp); std::hint::black_box(&tmp[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" clamp himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<DotF32Kernel>::new("euclidean_f32", vec![
KernelInfo { name: "scalar", func: kernels::euclidean_distance_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::euclidean_distance_f32_neon, is_supported: |_| true, thermal_priority: 2 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a, &b)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_euclidean_f32(&a, &b)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" euclidean_distance himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
println!();
let mut d = Dispatch::<DotF32Kernel>::new("cosine_similarity_f32", vec![
KernelInfo { name: "scalar", func: kernels::cosine_similarity_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::cosine_similarity_f32_sse, is_supported: kernels::cosine_similarity_f32_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::cosine_similarity_f32_avx2, is_supported: kernels::cosine_similarity_f32_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::cosine_similarity_f32_neon, is_supported: |_| true, thermal_priority: 2 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(d.compute(&a, &b)); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
let start = Instant::now();
for _ in 0..ITERS { std::hint::black_box(pure_cosine_f32(&a, &b)); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" cosine_similarity himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
let mut d = Dispatch::<UnaryOpF32Kernel>::new("softmax_f32", vec![
KernelInfo { name: "scalar", func: kernels::softmax_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::softmax_f32_sse, is_supported: kernels::softmax_f32_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::softmax_f32_avx2, is_supported: kernels::softmax_f32_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::softmax_f32_neon, is_supported: |_| true, thermal_priority: 2 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let mut tmp2 = vec![0.0f32; N];
let start = Instant::now();
for _ in 0..ITERS { tmp2.fill(0.0); d.compute(&a, &mut tmp2); std::hint::black_box(&tmp2[0]); }
let h = start.elapsed().as_secs_f64() / ITERS as f64;
tmp2.fill(0.0);
let start = Instant::now();
for _ in 0..ITERS { tmp2.fill(0.0); pure_softmax_f32(&a, &mut tmp2); std::hint::black_box(&tmp2[0]); }
let p = start.elapsed().as_secs_f64() / ITERS as f64;
println!(" softmax himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
const MN: usize = 256;
let m_a: Vec<f32> = (0..MN * MN).map(|i| (i % 5) as f32).collect();
let m_b: Vec<f32> = (0..MN * MN).map(|i| (i % 7) as f32).collect();
let mut m_c = vec![0.0f32; MN * MN];
let mut d = Dispatch::<MatMulF32Kernel>::new("matmul_f32", vec![
KernelInfo { name: "scalar", func: kernels::matmul_f32_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::matmul_f32_sse, is_supported: kernels::matmul_f32_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::matmul_f32_avx2, is_supported: kernels::matmul_f32_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::matmul_f32_neon, is_supported: |_| true, thermal_priority: 2 },
]);
d.select().ok();
let kn = d.selected_name().to_string();
let iters_small = 2.min(ITERS);
let start = Instant::now();
for _ in 0..iters_small { m_c.fill(0.0); d.compute(&m_a, &m_b, &mut m_c, MN); std::hint::black_box(&m_c[0]); }
let h = start.elapsed().as_secs_f64() / iters_small as f64;
m_c.fill(0.0);
let start = Instant::now();
for _ in 0..iters_small { m_c.fill(0.0); pure_matmul_f32(&m_a, &m_b, &mut m_c, MN); std::hint::black_box(&m_c[0]); }
let p = start.elapsed().as_secs_f64() / iters_small as f64;
println!(" matmul himada ({:<8}) {:>8.3} ms {:>5.2}x", kn, h*1000.0, p/h);
println!();
}
fn bench_pipeline() {
println!("╔══════════════════════════════════════════════════════════════╗");
println!("║ Composite Pipeline: ML Inference Simulation ║");
println!("╚══════════════════════════════════════════════════════════════╝\n");
let n = N;
let w1: Vec<f64> = (0..n).map(|i| (i % 7) as f64).collect();
let w2: Vec<f64> = (0..n).map(|i| ((i + 3) % 11) as f64).collect();
let x: Vec<f64> = (0..n).map(|i| (i % 5) as f64).collect();
let bias: Vec<f64> = vec![0.5; n];
let mut z1 = vec![0.0; n];
let mut a1 = vec![0.0; n];
let mut z2 = vec![0.0; n];
let mut out = vec![0.0; n];
let mut tmp = vec![0.0; n];
let mut d_dot = Dispatch::<DotKernel>::new("dot", vec![
KernelInfo { name: "scalar", func: kernels::dot_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::dot_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::dot_f64_sve, is_supported: kernels::dot_f64_sve_supported, thermal_priority: 3 },
]);
let mut d_add = Dispatch::<BinaryOpKernel>::new("add", vec![
KernelInfo { name: "scalar", func: kernels::add_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::hadamard_product_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::hadamard_product_f64_sve, is_supported: kernels::hadamard_product_f64_sve_supported, thermal_priority: 3 },
]);
let mut d_clamp = Dispatch::<ClampKernel>::new("clamp", vec![
KernelInfo { name: "scalar", func: kernels::clamp_f64_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::clamp_f64_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::clamp_f64_sve, is_supported: kernels::clamp_f64_sve_supported, thermal_priority: 3 },
]);
let mut d_softmax = Dispatch::<SoftmaxKernel>::new("softmax", vec![
KernelInfo { name: "scalar", func: kernels::softmax_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::softmax_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::softmax_f64_sve, is_supported: kernels::softmax_f64_sve_supported, thermal_priority: 3 },
]);
let mut d_sum = Dispatch::<ReduceKernel>::new("reduce_sum", vec![
KernelInfo { name: "scalar", func: kernels::reduce_sum_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::reduce_sum_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::reduce_sum_f64_sve, is_supported: kernels::reduce_sum_f64_sve_supported, thermal_priority: 3 },
]);
d_dot.select().ok();
d_add.select().ok();
d_clamp.select().ok();
d_softmax.select().ok();
d_sum.select().ok();
println!("Pipeline: dot(x,w1) → add(bias) → clamp(0,1) → dot(a1,w2) → add(bias) → softmax → reduce_sum\n");
println!("Selected kernels:");
println!(" dot → {}", d_dot.selected_name());
println!(" add → {}", d_add.selected_name());
println!(" clamp → {}", d_clamp.selected_name());
println!(" softmax → {}", d_softmax.selected_name());
println!(" reduce_sum → {}\n", d_sum.selected_name());
let start = Instant::now();
for _ in 0..ITERS {
let dot1 = d_dot.compute(&x, &w1);
for v in z1.iter_mut() { *v = dot1; }
d_add.compute(&z1, &bias, &mut tmp);
z1.copy_from_slice(&tmp);
d_clamp.compute(&z1, 0.0, 1.0, &mut a1);
let dot2 = d_dot.compute(&a1, &w2);
for v in z2.iter_mut() { *v = dot2; }
d_add.compute(&z2, &bias, &mut tmp);
z2.copy_from_slice(&tmp);
out.fill(0.0);
d_softmax.compute(&z2, &mut out);
std::hint::black_box(d_sum.compute(&out));
}
let himada_secs = start.elapsed().as_secs_f64() / ITERS as f64;
fn pure_pipeline(x: &[f64], w1: &[f64], w2: &[f64], bias: &[f64]) -> f64 {
let dot1 = pure_dot(x, w1);
let z1: Vec<f64> = x.iter().map(|_| dot1).zip(bias).map(|(z, b)| (z + b).clamp(0.0, 1.0)).collect();
let dot2 = pure_dot(&z1, w2);
let z2: Vec<f64> = z1.iter().map(|_| dot2).zip(bias).map(|(z, b)| z + b).collect();
let mut out = vec![0.0; z2.len()];
pure_softmax(&z2, &mut out);
pure_reduce_sum(&out)
}
std::hint::black_box(pure_pipeline(&x, &w1, &w2, &bias));
let start = Instant::now();
for _ in 0..ITERS {
std::hint::black_box(pure_pipeline(&x, &w1, &w2, &bias));
}
let pure_secs = start.elapsed().as_secs_f64() / ITERS as f64;
let speedup = pure_secs / himada_secs;
println!("Pipeline results:");
println!(" himada pipeline: {:>8.3} ms", himada_secs * 1000.0);
println!(" Pure Rust: {:>8.3} ms", pure_secs * 1000.0);
println!("──────────────────────────────");
println!(" Pipeline speedup: {:>6.2}x", speedup);
println!();
println!("Per-operation breakdown (himada only):");
let mut total = 0.0;
let t = |name: &str, secs: f64| {
println!(" {:<20} {:>8.3} ms", name, secs * 1000.0);
secs
};
total += t("dot(x,w1)", {
let s = Instant::now(); for _ in 0..ITERS { std::hint::black_box(d_dot.compute(&x, &w1)); } s.elapsed().as_secs_f64() / ITERS as f64
});
total += t("add(bias)", {
let s = Instant::now(); for _ in 0..ITERS { d_add.compute(&z1, &bias, &mut tmp); std::hint::black_box(&tmp[0]); } s.elapsed().as_secs_f64() / ITERS as f64
});
total += t("clamp(0,1)", {
let s = Instant::now(); for _ in 0..ITERS { d_clamp.compute(&z1, 0.0, 1.0, &mut a1); std::hint::black_box(&a1[0]); } s.elapsed().as_secs_f64() / ITERS as f64
});
total += t("dot(a1,w2)", {
let s = Instant::now(); for _ in 0..ITERS { std::hint::black_box(d_dot.compute(&a1, &w2)); } s.elapsed().as_secs_f64() / ITERS as f64
});
total += t("softmax(z2)", {
let s = Instant::now(); for _ in 0..ITERS { out.fill(0.0); d_softmax.compute(&z2, &mut out); std::hint::black_box(&out[0]); } s.elapsed().as_secs_f64() / ITERS as f64
});
total += t("reduce_sum(out)", {
let s = Instant::now(); for _ in 0..ITERS { std::hint::black_box(d_sum.compute(&out)); } s.elapsed().as_secs_f64() / ITERS as f64
});
println!(" ─────────────────────");
println!(" {:<20} {:>8.3} ms", "total (sum)", total * 1000.0);
}
#[allow(dead_code)]
fn bench_dot() { bench_all_f64(); }
#[allow(dead_code)]
fn bench_reduce_sum() { bench_all_f64(); }
#[allow(dead_code)]
fn bench_reduce_max() { bench_all_f64(); }
#[allow(dead_code)]
fn bench_softmax() { bench_all_f64(); }
#[allow(dead_code)]
fn bench_memchr() { bench_all_f64(); }
#[allow(dead_code)]
fn bench_matmul() { bench_all_f64(); }
fn run_adaptation_demo() {
println!("=== Himada Adaptive Engine Demo ===\n");
let dispatch = Dispatch::<DotKernel>::new(
"dot_product",
vec![
KernelInfo { name: "scalar", func: kernels::dot_scalar, is_supported: |_| true, thermal_priority: 1 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "SSE", func: kernels::dot_sse, is_supported: kernels::dot_sse_supported, thermal_priority: 2 },
#[cfg(target_arch = "x86_64")] KernelInfo { name: "AVX2", func: kernels::dot_avx2, is_supported: kernels::dot_avx2_supported, thermal_priority: 3 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "NEON", func: kernels::dot_neon, is_supported: |_| true, thermal_priority: 2 },
#[cfg(target_arch = "aarch64")] KernelInfo { name: "SVE", func: kernels::dot_f64_sve, is_supported: kernels::dot_f64_sve_supported, thermal_priority: 3 },
],
);
let mut engine = AdaptiveEngine::new(dispatch, Duration::from_secs(10));
println!("Starting background adaptation (re-benchmarks every 10s)...");
engine.start();
let n = 10_000_000;
let a: Vec<f64> = vec![1.0; n];
let b: Vec<f64> = vec![2.0; n];
for i in 0..3 {
let start = Instant::now();
let result = engine.compute(&a, &b);
let elapsed = start.elapsed();
println!("[{}] result={} kernel={} time={:.3}ms", i + 1, result, engine.selected_name(), elapsed.as_secs_f64() * 1000.0);
std::thread::sleep(Duration::from_secs(12));
}
println!("\nStopping adaptation...");
engine.stop();
println!("Adaptation history saved to ~/.himada/adapt.json");
}
#[himada_optimize]
fn dot_optimized(a: &[f64], b: &[f64]) -> f64 {
a.iter().zip(b).map(|(x, y)| x * y).sum()
}
fn run_macro_optimize_demo() {
println!("=== #[himada_optimize] Macro Demo ===\n");
let n = 10_000_000;
let a: Vec<f64> = vec![1.0; n];
let b: Vec<f64> = vec![2.0; n];
let start = Instant::now();
let result = dot_optimized(&a, &b);
let elapsed = start.elapsed();
println!("dot_optimized: result={} time={:.3}ms", result, elapsed.as_secs_f64() * 1000.0);
}
#[himada_adapt]
fn dot_adaptive(a: &[f64], b: &[f64]) -> f64 {
a.iter().zip(b).map(|(x, y)| x * y).sum()
}
fn run_macro_adapt_demo() {
println!("=== #[himada_adapt] Macro Demo ===\n");
let n = 10_000_000;
let a: Vec<f64> = vec![1.0; n];
let b: Vec<f64> = vec![2.0; n];
for i in 0..3 {
let start = Instant::now();
let result = dot_adaptive(&a, &b);
let elapsed = start.elapsed();
println!("[{}] result={} time={:.3}ms", i + 1, result, elapsed.as_secs_f64() * 1000.0);
std::thread::sleep(Duration::from_secs(2));
}
}
#[cfg(feature = "ext-bench")]
fn bench_dot_vs_rayon() { bench_all_f64(); }
#[cfg(feature = "ext-bench")]
fn bench_dot_vs_wide() { bench_all_f64(); }
#[cfg(feature = "ext-bench")]
fn bench_matmul_vs_nalgebra() { bench_all_f64(); }
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() > 1 {
match args[1].as_str() {
"--adapt" => return run_adaptation_demo(),
"--macro-optimize" => return run_macro_optimize_demo(),
"--macro-adapt" => return run_macro_adapt_demo(),
"--bench-all" | "--bench-dot" | "--bench-matmul" | "--bench-reduce-sum"
| "--bench-reduce-max" | "--bench-softmax" | "--bench-memchr" => {
bench_all_f64();
bench_all_f32();
bench_pipeline();
return;
}
"--bench-all-f64" => { bench_all_f64(); return; }
"--bench-all-f32" => { bench_all_f32(); return; }
"--bench-pipeline" => { bench_pipeline(); return; }
#[cfg(feature = "ext-bench")]
"--bench-vs-rayon" | "--bench-vs-nalgebra" | "--bench-vs-wide" => {
bench_all_f64();
bench_all_f32();
bench_pipeline();
return;
}
_ => {}
}
}
println!("=== Himada Dispatch Benchmark Suite ===\n");
println!("Usage: cargo run --release -- <flag>\n");
println!("Single benchmarks:");
println!(" --bench-all all f64 + f32 + pipeline");
println!(" --bench-all-f64 all f64 operations");
println!(" --bench-all-f32 all f32 operations");
println!(" --bench-pipeline composite ML pipeline");
#[cfg(feature = "ext-bench")]
println!(" --bench-vs-* (via ext-bench feature)");
println!();
println!("Other: --adapt, --macro-optimize, --macro-adapt");
}