use crate::{Device, ExecutionError};
use burn_backend::{Backend, BackendGraph};
use burn_dispatch::Dispatch;
pub struct Graph<T, F> {
device: Device,
output: T,
closure: F,
hardware: Result<BackendGraph<Dispatch>, ExecutionError>,
}
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), output)
}
Err(error) => (Err(error), 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 {
Ok(graph) => {
unsafe { Dispatch::graph_replay(self.device.as_dispatch(), graph) }
.expect("graph replay should succeed");
}
Err(_) => {
self.output = (self.closure)();
}
}
&self.output
}
pub fn output(&self) -> &T {
&self.output
}
pub fn is_hardware(&self) -> bool {
self.hardware.is_ok()
}
pub fn capture_error(&self) -> Option<&ExecutionError> {
self.hardware.as_ref().err()
}
}