Skip to main content

shared_bench/
shared_bench.rs

1//! Warm end-to-end latency for a real NPU passthrough pipeline.
2//! Usage: shared_bench <passthrough.xclbin> <instructions.bin> <bytes>
3use hrx::{
4    Result,
5    benchmark::percentile,
6    execution::{Access, BindingContract, KernelContract, MemoryPlacement, Runtime},
7};
8use std::time::Instant;
9fn main() -> Result<()> {
10    let args: Vec<_> = std::env::args().collect();
11    if args.len() != 4 {
12        return Err(hrx::Error::Message(
13            "usage: shared_bench <passthrough.xclbin> <instructions.bin> <bytes>".into(),
14        ));
15    }
16    let bytes = args[3]
17        .parse::<usize>()
18        .map_err(|e| hrx::Error::Message(e.to_string()))?;
19    let runtime = Runtime::new()?;
20    let program = unsafe { runtime.npu(0)?.load_program(&args[1]) }?;
21    let binding = |bytes, access| BindingContract {
22        bytes,
23        access,
24        alignment: 4,
25        layout: "passthrough".into(),
26    };
27    let kernel = unsafe {
28        program.kernel(
29            &std::fs::read(&args[2])?,
30            KernelContract {
31                bindings: vec![
32                    binding(bytes, Access::Read),
33                    binding(4096, Access::Read),
34                    binding(bytes, Access::Write),
35                ],
36                constants: vec![],
37            },
38        )
39    }?;
40    let a = runtime.allocate(bytes, MemoryPlacement::Shared(program.clone()))?;
41    let b = runtime.allocate(4096, MemoryPlacement::Shared(program.clone()))?;
42    let c = runtime.allocate(bytes, MemoryPlacement::Shared(program.clone()))?;
43    let mut graph = runtime.graph();
44    graph.fill(a.view(), 0x35)?;
45    graph.npu(&kernel, &[a.view(), b.view(), c.view()])?;
46    let graph = graph.prepare()?;
47    for _ in 0..5 {
48        graph.submit()?.wait()?;
49    }
50    let mut samples = Vec::new();
51    for _ in 0..100 {
52        let start = Instant::now();
53        graph.submit()?.wait()?;
54        samples.push(start.elapsed().as_secs_f64());
55    }
56    if c.map_read()?.iter().any(|&b| b != 0x35) {
57        return Err(hrx::Error::Message("incorrect benchmark output".into()));
58    }
59    samples.sort_by(f64::total_cmp);
60    println!(
61        "bytes={bytes} p50_us={:.2} p95_us={:.2}",
62        percentile(&samples, 50) * 1e6,
63        percentile(&samples, 95) * 1e6
64    );
65    Ok(())
66}