use memra_engine::Engine;
use memra_gguf::{GgmlType, GgufFile};
use std::time::Instant;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = std::env::args().nth(1).expect("usage: mvq-msweep <gguf>");
let e = Engine::new(0)?;
let g = GgufFile::open(&path)?;
let tname = std::env::var("MSWEEP_TENSOR").unwrap_or_else(|_| "blk.0.ffn_down.weight".into());
let t = g
.find(&tname)
.or_else(|| g.find("blk.0.ffn_gate.weight"))
.expect("no ffn weight");
let in_f = t.ne[0] as usize;
let out_f = t.ne[1] as usize;
let raw = g.tensor_data(t);
let row_bytes = raw.len() / out_f;
let qtype = match t.ggml_type {
GgmlType::NVFP4 => memra_engine::QT_NVFP4,
GgmlType::Q8_0 => memra_engine::QT_Q8_0,
GgmlType::Q4_K => memra_engine::QT_Q4_K,
GgmlType::Q5_K => memra_engine::QT_Q5_K,
GgmlType::Q6_K => memra_engine::QT_Q6_K,
other => panic!("unsupported msweep dtype {other:?}"),
};
let copies: usize = std::env::var("MSWEEP_COPIES")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(1);
let rp = std::env::var("MSWEEP_RP").is_ok();
assert!(
!rp || qtype == memra_engine::QT_NVFP4,
"MSWEEP_RP is NVFP4-only"
);
let raw_owned: Vec<u8>;
let raw = if rp {
let nsb64 = in_f / 64;
assert_eq!(row_bytes, nsb64 * 36, "unexpected NVFP4 row_bytes");
let qplane = out_f * nsb64 * 32;
let mut rpb = vec![0u8; raw.len()];
for o in 0..out_f {
for s in 0..nsb64 {
let src = &raw[o * row_bytes + s * 36..o * row_bytes + s * 36 + 36];
rpb[qplane + o * nsb64 * 4 + s * 4..qplane + o * nsb64 * 4 + s * 4 + 4]
.copy_from_slice(&src[0..4]);
rpb[o * nsb64 * 32 + s * 32..o * nsb64 * 32 + s * 32 + 32]
.copy_from_slice(&src[4..36]);
}
}
let mut back = vec![0u8; raw.len()];
for o in 0..out_f {
for s in 0..nsb64 {
back[o * row_bytes + s * 36..o * row_bytes + s * 36 + 4].copy_from_slice(
&rpb[qplane + o * nsb64 * 4 + s * 4..qplane + o * nsb64 * 4 + s * 4 + 4],
);
back[o * row_bytes + s * 36 + 4..o * row_bytes + s * 36 + 36]
.copy_from_slice(&rpb[o * nsb64 * 32 + s * 32..o * nsb64 * 32 + s * 32 + 32]);
}
}
let rt_bad = raw.iter().zip(&back).filter(|(a, b)| a != b).count();
println!(
"repack roundtrip: {} mismatched bytes of {}",
rt_bad,
raw.len()
);
assert_eq!(rt_bad, 0, "repack roundtrip FAILED");
raw_owned = rpb;
&raw_owned[..]
} else {
raw
};
let wd_orig = if rp {
Some(e.htod_bytes(g.tensor_data(t))?)
} else {
None
};
let wds: Vec<_> = (0..copies)
.map(|_| e.htod_bytes(raw))
.collect::<Result<_, _>>()?;
let bv = std::env::var("MEMRA_MMVQ_BV").unwrap_or_else(|_| "auto".into());
println!(
"weight {tname} [{:?}] in_f={in_f} out_f={out_f} row_bytes={row_bytes} \
copies={copies} variant={bv}",
t.ggml_type
);
let iters = if copies > 1 { 800 } else { 2000 };
if std::env::var("MSWEEP_BATCHED_ONLY").is_err() {
println!("--- grid.y=m (current, no weight reuse) ---");
for m in [1usize, 2, 4, 8] {
let x: Vec<f32> = (0..m * in_f)
.map(|i| ((i % 17) as f32 - 8.0) * 0.1)
.collect();
let xd = e.htod(&x)?;
for _ in 0..50 {
let _ =
e.qmatvec_mmvq_raw(&wds[0], &xd, m, in_f, out_f, qtype, row_bytes, false)?;
}
e.stream().synchronize()?;
let t0 = Instant::now();
for i in 0..iters {
let _ = e.qmatvec_mmvq_raw(
&wds[i % copies],
&xd,
m,
in_f,
out_f,
qtype,
row_bytes,
false,
)?;
}
e.stream().synchronize()?;
let us = t0.elapsed().as_secs_f64() * 1e6 / iters as f64;
println!(" m={m}: {us:.2} us/call ({:.2} us/token)", us / m as f64);
}
}
println!("--- BATCHED weight-tile-resident (1 weight read serves m tokens) ---");
let mut cells = vec![(2usize, 2usize), (3, 4), (4, 4), (5, 8), (6, 8), (8, 8)];
if std::env::var("MSWEEP_M1").is_ok() {
cells.insert(0, (1, 2));
}
for (m, mcols) in cells {
let x: Vec<f32> = (0..m * in_f)
.map(|i| ((i % 17) as f32 - 8.0) * 0.1)
.collect();
let xd = e.htod(&x)?;
let wref = wd_orig.as_ref().unwrap_or(&wds[0]);
let r_ref =
e.dtoh(&e.qmatvec_mmvq_raw(wref, &xd, m, in_f, out_f, qtype, row_bytes, false)?)?;
let r_bat = e.dtoh(
&e.qmatvec_batched_raw(&wds[0], &xd, m, in_f, out_f, qtype, row_bytes, mcols, rp)?,
)?;
let bad = r_ref
.iter()
.zip(&r_bat)
.filter(|(a, b)| (*a - *b).abs() > 1e-3)
.count();
let bit = r_ref
.iter()
.zip(&r_bat)
.filter(|(a, b)| a.to_bits() != b.to_bits())
.count();
for _ in 0..50 {
let _ =
e.qmatvec_batched_raw(&wds[0], &xd, m, in_f, out_f, qtype, row_bytes, mcols, rp)?;
}
e.stream().synchronize()?;
let t0 = Instant::now();
for i in 0..iters {
let _ = e.qmatvec_batched_raw(
&wds[i % copies],
&xd,
m,
in_f,
out_f,
qtype,
row_bytes,
mcols,
rp,
)?;
}
e.stream().synchronize()?;
let us = t0.elapsed().as_secs_f64() * 1e6 / iters as f64;
println!(
" m={m} (b{mcols}): {us:.2} us/call ({:.2} us/token) bit-bad={bad} bit-exact-bad={bit}",
us / m as f64
);
}
Ok(())
}