use crate::harness::{BENCH_GUARD, fill, measure};
use gemmkit::{Activation, Bias, MatMut, MatRef, Parallelism, gemm, gemm_fused};
const MAX_FUSED_RATIO: f64 = 2.0;
const SHAPES: &[(usize, usize, usize)] = &[(512, 512, 512), (1024, 64, 1024), (4096, 128, 64)];
fn bench(par: Parallelism, tag: &str) {
for &(m, k, n) in SHAPES {
let a = fill(m * k, 1);
let b = fill(k * n, 2);
let bias = fill(m, 3);
let mut c = vec![0.0f32; m * n];
let plain = measure(m, k, n, || {
gemm(
1.0,
MatRef::new(&a, m, k, 1, m as isize),
MatRef::new(&b, k, n, 1, k as isize),
0.0,
MatMut::new(&mut c, m, n, 1, m as isize),
par,
);
});
let fused = measure(m, k, n, || {
gemm_fused(
1.0,
MatRef::new(&a, m, k, 1, m as isize),
MatRef::new(&b, k, n, 1, k as isize),
0.0,
MatMut::new(&mut c, m, n, 1, m as isize),
Some(Bias::PerRow(&bias)),
Some(Activation::Relu),
par,
);
});
let ratio = plain.median / fused.median;
println!(
"{tag} {m:>5}x{k:<5}x{n:<5} plain {:8.1} GF/s (spread {:4.1}%) \
fused {:8.1} GF/s (spread {:4.1}%) ratio x{ratio:.2}",
plain.median,
plain.spread_pct(),
fused.median,
fused.spread_pct(),
);
assert!(
ratio < MAX_FUSED_RATIO,
"{tag} {m}x{k}x{n}: fused/plain time ratio x{ratio:.2} exceeds \
x{MAX_FUSED_RATIO:.2}; the epilogue is degrading the kernel, not just the \
store (see the module comment)"
);
}
}
#[test]
#[ignore = "benchmark"]
fn perf_fused_overhead_serial() {
let _g = BENCH_GUARD.lock();
bench(Parallelism::Serial, "ser");
}
#[test]
#[ignore = "benchmark"]
fn perf_fused_overhead_parallel() {
let _g = BENCH_GUARD.lock();
bench(Parallelism::Rayon(0), "par");
}