use fuel_quantized::{BlockQ4_0, BlockQ4K, BlockQ8_0, GgmlType, matmul};
use std::time::Instant;
const REPEATS: usize = 9;
const ARM: &str = "ARM_PLACEHOLDER";
fn fill(len: usize, seed: u32) -> Vec<f32> {
(0..len as u32)
.map(|i| {
let x = i
.wrapping_mul(2654435761)
.wrapping_add(seed.wrapping_mul(40503))
>> 8;
(x % 2001) as f32 / 1000.0 - 1.0
})
.collect()
}
fn median(mut v: Vec<f64>) -> (f64, f64, f64) {
v.sort_by(|a, b| a.total_cmp(b));
(v[0], v[v.len() / 2], v[v.len() - 1])
}
fn run<T: GgmlType>(label: &str, (m, k, n): (usize, usize, usize)) {
let w = fill(n * k, 7);
let x = fill(m * k, 11);
let blk = T::BLCK_SIZE;
let mut blocks = vec![T::zeros(); n * k / blk];
T::from_float(&w, &mut blocks);
let mut deq = vec![0f32; n * k];
T::to_float(&blocks, &mut deq);
let mut got = vec![0f32; m * n];
for _ in 0..3 {
matmul((m, k, n), &x, &blocks, &mut got).expect("matmul");
}
let mut ms = Vec::with_capacity(REPEATS);
for _ in 0..REPEATS {
let t = Instant::now();
matmul((m, k, n), &x, &blocks, &mut got).expect("matmul");
ms.push(t.elapsed().as_secs_f64() * 1e3);
}
let (lo, med, hi) = median(ms);
let mut worst = 0f64;
for r in 0..m {
let refs: Vec<f64> = (0..n)
.map(|c| {
(0..k)
.map(|i| f64::from(x[r * k + i]) * f64::from(deq[c * k + i]))
.sum()
})
.collect();
let rms = (refs.iter().map(|v| v * v).sum::<f64>() / n as f64)
.sqrt()
.max(1e-12);
for (c, rv) in refs.iter().enumerate() {
worst = worst.max((f64::from(got[r * n + c]) - rv).abs() / rms);
}
}
println!(
"{ARM:<22} {label:<6} m={m:<2} k={k} n={n:<5} min {lo:>8.2} med {med:>8.2} max {hi:>8.2} ms max|err|/rms {worst:.2e}"
);
}
fn main() {
println!(
"# repeats={REPEATS}; milliseconds per matmul call; agreement vs the f64 dequantized reference"
);
for shape in [
(1usize, 4096usize, 4096usize),
(8, 4096, 4096),
(1, 4096, 11008),
] {
run::<BlockQ4_0>("Q4_0", shape);
run::<BlockQ8_0>("Q8_0", shape);
run::<BlockQ4K>("Q4_K", shape);
}
}