use std::io::Write;
use rlx_driver::Device;
use rlx_ir::{DType, Graph, Op, Shape, Tick};
use rlx_runtime::{CompiledGraph, Session};
fn fft_graph(batch: usize, n: usize) -> Graph {
let mut g = Graph::new("wgpu_multirow");
let len = batch * n * 2;
let mut bytes = Vec::with_capacity(len * 4);
for i in 0..len {
bytes.extend_from_slice(&((i as f32 * 0.013).sin()).to_le_bytes());
}
let x = g.add_node(
Op::Constant { data: bytes },
vec![],
Shape::new(&[batch, n * 2], DType::F32),
);
let y = g.fft(x, false);
g.set_outputs(vec![y]);
g
}
fn set_var(key: &str, on: bool) {
unsafe {
std::env::set_var(key, if on { "1" } else { "0" });
}
}
fn main() {
set_var("RLX_FFT_FAST", true);
let empty: &[(&str, &[f32])] = &[];
let median = |c: &mut CompiledGraph| -> u64 {
for _ in 0..5 {
let _ = c.run(empty);
}
let mut s = Vec::with_capacity(25);
for _ in 0..25 {
let t0 = Tick::now();
let _ = c.run(empty);
s.push(Tick::now().elapsed_ns(t0));
}
s.sort_unstable();
s[s.len() / 2]
};
println!("wgpu small-n FFT: 1-row-per-wg (old) vs multi-row packing (new), single forward FFT");
println!(
" {:>5} {:>6} {:>11} {:>11} {:>8}",
"n", "batch", "old µs", "new µs", "new/old"
);
let _ = std::io::stdout().flush();
for &n in &[8usize, 32, 128, 256, 512, 1024] {
for &batch in &[16usize, 64, 256, 512, 1024] {
let mut c = Session::new(Device::Gpu).compile(fft_graph(batch, n));
set_var("RLX_FFT_MULTIROW", false);
let old = median(&mut c);
set_var("RLX_FFT_MULTIROW", true);
let new = median(&mut c);
let per = |t: u64| t as f64 / 1000.0;
println!(
" {n:>5} {batch:>6} {:>9.1}µs {:>9.1}µs {:>7.2}×",
per(old),
per(new),
old as f64 / new.max(1) as f64,
);
let _ = std::io::stdout().flush();
}
println!();
}
}