use memra_engine::Engine;
use memra_engine::mmq_ffi::*;
use cudarc::driver::{DevicePtr, DevicePtrMut};
use std::time::Instant;
fn pr(i: usize) -> f32 { ((i.wrapping_mul(40503) % 1000) as f32) / 1000.0 - 0.5 }
fn hb(i: usize) -> u8 { ((i.wrapping_mul(2654435761u32 as usize)) >> 13) as u8 }
fn synth_q4_0(in_f: usize, out_f: usize) -> Vec<u8> {
let nblk = in_f / 32 * out_f;
let mut raw = vec![0u8; nblk * 18];
for (bi, b) in raw.chunks_mut(18).enumerate() {
b[0] = 0x00; b[1] = 0x2C; for k in 0..16 { b[2 + k] = hb(bi * 17 + k); }
}
raw
}
fn median(v: &mut [f64]) -> f64 {
v.sort_by(|a, b| a.partial_cmp(b).unwrap());
v[v.len() / 2]
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let gguf = std::env::args().nth(1);
let reps: usize = std::env::args().nth(2).and_then(|v| v.parse().ok()).unwrap_or(30);
let sessions: usize = std::env::args().nth(3).and_then(|v| v.parse().ok()).unwrap_or(3);
unsafe { std::env::set_var("MEMRA_MMQ_SK_FORM", "sk"); }
let e = Engine::new(0)?;
println!("GPU: {} reps={reps} sessions={sessions}", e.ctx().name()?);
let clc_avail = unsafe { memra_mmq_q4_0_set_clc(-1) } == 1;
if !clc_avail {
println!("CLC kernel not compiled in (pre-SM100 build) — nothing to measure.");
return Ok(());
}
let nsm = 82usize;
let mut shapes: Vec<(String, usize, usize, usize, Option<Vec<u8>>)> = Vec::new();
for (lbl, inf, outf) in [("q9-qkv", 4096usize, 8192usize),
("q9-gateup", 4096, 12288),
("q9-down", 12288, 4096),
("q9-attngate", 4096, 4096)] {
for t in [512usize, 1736] {
shapes.push((format!("{lbl}"), inf, outf, t, None));
}
}
shapes.push(("wavequant-84t".into(), 4096, 10752, 128, None)); shapes.push(("wavequant-336t".into(), 4096, 10752, 512, None)); shapes.push(("wavequant-168t".into(), 4096, 10752, 256, None)); shapes.push(("subwave-32t".into(), 4096, 4096, 128, None)); shapes.push(("subwave-64t".into(), 4096, 8192, 128, None)); if let Some(p) = &gguf {
use memra_gguf::{GgufFile, GgmlType};
let g = GgufFile::open(p)?;
for tname in ["blk.0.attn_q.weight", "blk.0.ffn_gate.weight", "blk.0.ffn_down.weight"] {
if let Some(t) = g.find(tname).filter(|t| t.ggml_type == GgmlType::Q4_0) {
let inf = t.ne[0] as usize; let outf = t.ne[1] as usize;
let raw = g.tensor_data(t).to_vec();
for t in [512usize, 1736] {
shapes.push((format!("g12-{}", tname.trim_start_matches("blk.0.").trim_end_matches(".weight")),
inf, outf, t, Some(raw.clone())));
}
}
}
}
println!("{:<16} {:>6} {:>6} {:>5} {:>6} {:>6} {:>8} | {:>9} {:>9} {:>9} | {:>8} {:>8} | bits",
"shape", "in_f", "out_f", "T", "tiles", "waves", "waveeff",
"static_us", "clc_us", "sk_us", "clc", "sk");
for (lbl, in_f, out_f, t, real) in shapes {
let raw = real.unwrap_or_else(|| synth_q4_0(in_f, out_f));
let wd = e.htod_bytes(&raw)?;
let x: Vec<f32> = (0..t * in_f).map(|i| pr(i + 29) * 0.1).collect();
let xd = e.htod(&x)?;
let act_bytes = unsafe { memra_mmq_q4_0_act_bytes(in_f as i32, t as i32) };
let mut scratch = e.htod_bytes(&vec![0u8; act_bytes])?;
let fixup_bytes = unsafe { memra_mmq_q4_0_fixup_bytes() };
let mut fixup = e.htod_bytes(&vec![0u8; fixup_bytes])?;
let mut y = e.zeros(t * out_f)?;
let stream = e.stream();
let cu = stream.cu_stream() as *mut core::ffi::c_void;
let (x_p, _gx) = xd.device_ptr(&stream);
{
let (s_p, _gs) = scratch.device_ptr_mut(&stream);
let rc = unsafe { memra_mmq_q4_0_quant_act(x_p as *const f32,
s_p as *mut core::ffi::c_void, in_f as i32, t as i32, cu) };
assert_eq!(rc, 0, "quant_act rc={rc}");
}
let (w_p, _gw) = wd.device_ptr(&stream);
let (s_p, _gs) = scratch.device_ptr(&stream);
let gemm = |arm: i32, y: &mut cudarc::driver::CudaSlice<f32>,
fixup: &mut cudarc::driver::CudaSlice<u8>| -> i32 {
let stream = e.stream();
let (y_p, _gy) = y.device_ptr_mut(&stream);
if arm == 2 {
unsafe { memra_mmq_q4_0_set_clc(0) };
let (f_p, _gf) = fixup.device_ptr_mut(&stream);
unsafe { memra_mmq_q4_0_gemm_sk(w_p as *const core::ffi::c_void,
s_p as *const core::ffi::c_void, y_p as *mut f32,
f_p as *mut core::ffi::c_void,
in_f as i32, out_f as i32, t as i32, cu, 0) }
} else {
unsafe { memra_mmq_q4_0_set_clc(arm) };
unsafe { memra_mmq_q4_0_gemm(w_p as *const core::ffi::c_void,
s_p as *const core::ffi::c_void, y_p as *mut f32,
in_f as i32, out_f as i32, t as i32, cu, 0) }
}
};
assert_eq!(gemm(0, &mut y, &mut fixup), 0);
stream.synchronize()?;
let y_static = e.dtoh(&y)?;
assert_eq!(gemm(1, &mut y, &mut fixup), 0);
stream.synchronize()?;
let y_clc = e.dtoh(&y)?;
let nbad = y_static.iter().zip(y_clc.iter())
.filter(|(a, b)| a.to_bits() != b.to_bits()).count();
for arm in [0i32, 1, 2] {
for _ in 0..10 { assert_eq!(gemm(arm, &mut y, &mut fixup), 0); }
}
stream.synchronize()?;
let mut med = [Vec::new(), Vec::new(), Vec::new()];
for _s in 0..sessions {
for arm in [0i32, 1, 2] {
stream.synchronize()?;
let t0 = Instant::now();
for _ in 0..reps { assert_eq!(gemm(arm, &mut y, &mut fixup), 0); }
stream.synchronize()?;
let us = t0.elapsed().as_secs_f64() * 1e6 / reps as f64;
med[arm as usize].push(us);
}
}
unsafe { memra_mmq_q4_0_set_clc(-1) };
let ms = median(&mut med[0]);
let mc = median(&mut med[1]);
let mk = median(&mut med[2]);
let nty = out_f.div_ceil(128); let ntx = t.div_ceil(128);
let tiles = nty * ntx;
let waves = tiles as f64 / nsm as f64;
let waveeff = tiles as f64 / (tiles.div_ceil(nsm) * nsm) as f64;
println!("{:<16} {:>6} {:>6} {:>5} {:>6} {:>6.2} {:>7.1}% | {:>9.1} {:>9.1} {:>9.1} | {:>7.3}x {:>7.3}x | {}",
lbl, in_f, out_f, t, tiles, waves, waveeff * 100.0, ms, mc, mk, ms / mc, ms / mk,
if nbad == 0 { "IDENTICAL".to_string() } else { format!("MISMATCH {nbad}") });
println!("JSONL {{\"lane\":\"clc-mmq\",\"shape\":\"{lbl}\",\"in_f\":{in_f},\"out_f\":{out_f},\"T\":{t},\"tiles\":{tiles},\"waves\":{waves:.3},\"wave_eff\":{waveeff:.4},\"static_us\":{ms:.2},\"clc_us\":{mc:.2},\"sk_us\":{mk:.2},\"clc_ratio\":{:.4},\"sk_ratio\":{:.4},\"bit_identical\":{},\"reps\":{reps},\"sessions\":{sessions},\"n_static\":{:?},\"n_clc\":{:?},\"n_sk\":{:?}}}",
ms / mc, ms / mk, nbad == 0,
med[0].iter().map(|v| (v * 100.0).round() / 100.0).collect::<Vec<_>>(),
med[1].iter().map(|v| (v * 100.0).round() / 100.0).collect::<Vec<_>>(),
med[2].iter().map(|v| (v * 100.0).round() / 100.0).collect::<Vec<_>>());
}
Ok(())
}