use memra_engine::Engine;
fn pr(i: usize) -> f32 {
let x = (i.wrapping_mul(2654435761) ^ 0x9E3779B9) as u32;
((x >> 8) as f32 / (1u32 << 24) as f32) * 8.0 - 4.0
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let e = Engine::new(0)?;
println!("GPU: {}", e.ctx().name()?);
let reps = 200usize;
for (name, in_f, n_pairs, act_kind) in [("q35-silu", 512usize, 16384usize, 0i32),
("g26-gelu", 704, 13888, 1)] {
let n = n_pairs * in_f;
let g: Vec<f32> = (0..n).map(|i| pr(i + 17)).collect();
let u: Vec<f32> = (0..n).map(|i| pr(i + 29)).collect();
let gd = e.htod(&g)?;
let ud = e.htod(&u)?;
let act = if act_kind == 0 { e.moe_pairs_silu_mul(&gd, &ud, n)? }
else { e.moe_pairs_gelu_mul(&gd, &ud, n)? };
let scr_ref = e.mmq_iq_quantize_act(&act, in_f, n_pairs)?;
let scr_f = e.mmq_iq_fused_act_quant(&gd, &ud, in_f, n_pairs, act_kind)?;
let b_ref: Vec<u8> = e.stream().clone_dtoh(&scr_ref)?;
let b_f: Vec<u8> = e.stream().clone_dtoh(&scr_f)?;
e.stream().synchronize()?;
let nbad = b_ref.iter().zip(&b_f).filter(|(a, b)| a != b).count();
for _ in 0..20 {
let a = if act_kind == 0 { e.moe_pairs_silu_mul(&gd, &ud, n)? }
else { e.moe_pairs_gelu_mul(&gd, &ud, n)? };
let _ = e.mmq_iq_quantize_act(&a, in_f, n_pairs)?;
}
e.stream().synchronize()?;
let t0 = std::time::Instant::now();
for _ in 0..reps {
let a = if act_kind == 0 { e.moe_pairs_silu_mul(&gd, &ud, n)? }
else { e.moe_pairs_gelu_mul(&gd, &ud, n)? };
let _ = e.mmq_iq_quantize_act(&a, in_f, n_pairs)?;
}
e.stream().synchronize()?;
let us_two = t0.elapsed().as_secs_f64() * 1e6 / reps as f64;
for _ in 0..20 { let _ = e.mmq_iq_fused_act_quant(&gd, &ud, in_f, n_pairs, act_kind)?; }
e.stream().synchronize()?;
let t1 = std::time::Instant::now();
for _ in 0..reps { let _ = e.mmq_iq_fused_act_quant(&gd, &ud, in_f, n_pairs, act_kind)?; }
e.stream().synchronize()?;
let us_fused = t1.elapsed().as_secs_f64() * 1e6 / reps as f64;
let scratch = b_ref.len() as f64;
let two_bytes = (4 * n) as f64 * 4.0 + scratch;
let fused_bytes = (2 * n) as f64 * 4.0 + scratch;
println!("{name} [{n_pairs}x{in_f}] byte_mismatch={nbad}: two-pass {us_two:.1} us \
({:.0} GB/s) | fused {us_fused:.1} us ({:.0} GB/s) | {:.2}x epilogue, \
{:.1} us saved/layer-call",
two_bytes / us_two / 1e3, fused_bytes / us_fused / 1e3,
us_two / us_fused, us_two - us_fused);
}
Ok(())
}