use crate::Device;
use burn_backend::{Backend, BackendGraph};
use burn_dispatch::Dispatch;
pub struct Graph<T, F> {
device: Device,
output: T,
closure: F,
hardware: Option<BackendGraph<Dispatch>>,
}
pub fn capture<T, F>(device: &Device, mut closure: F) -> Graph<T, F>
where
F: FnMut() -> T,
{
let dispatch = device.as_dispatch();
const WARMUP_ITERS: usize = 3;
let _ = Dispatch::graph_prepare(dispatch);
for _ in 0..WARMUP_ITERS {
let out = closure();
let _ = Dispatch::sync(dispatch);
drop(out);
}
let (hardware, output) = match Dispatch::graph_start_capture(dispatch) {
Ok(()) => {
let output = closure();
(Dispatch::graph_stop_capture(dispatch).ok(), output)
}
Err(_) => (None, closure()),
};
Graph {
device: device.clone(),
output,
closure,
hardware,
}
}
impl<T, F> Graph<T, F>
where
F: FnMut() -> T,
{
pub unsafe fn replay(&mut self) -> &T {
match &self.hardware {
Some(graph) => {
unsafe { Dispatch::graph_replay(self.device.as_dispatch(), graph) }
.expect("graph replay should succeed");
}
None => {
self.output = (self.closure)();
}
}
&self.output
}
pub fn output(&self) -> &T {
&self.output
}
pub fn is_hardware(&self) -> bool {
self.hardware.is_some()
}
}