use cudarc::driver::CudaGraph;
use cudarc::driver::sys::{CUgraphInstantiate_flags, CUstreamCaptureMode};
use super::super::{CudaError, CudaRuntime};
pub(super) struct CapturedGraph(CudaGraph);
impl std::fmt::Debug for CapturedGraph {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("CapturedGraph")
}
}
impl CapturedGraph {
pub(super) fn capture(
runtime: &CudaRuntime,
enqueue: impl FnOnce() -> Result<(), CudaError>,
) -> Result<Self, CudaError> {
let stream = runtime.stream();
stream.synchronize()?;
let _tracking = EventTrackingPause::new(runtime);
stream.begin_capture(CUstreamCaptureMode::CU_STREAM_CAPTURE_MODE_THREAD_LOCAL)?;
let enqueued = enqueue();
let graph = stream.end_capture(CUgraphInstantiate_flags(0));
enqueued?;
let graph = graph?.ok_or(CudaError::BufferLength {
context: "segmentation CUDA graph nodes",
expected: 1,
actual: 0,
})?;
Ok(Self(graph))
}
pub(super) fn launch(&self) -> Result<(), CudaError> {
self.0.launch()?;
Ok(())
}
}
struct EventTrackingPause<'a> {
runtime: &'a CudaRuntime,
was_tracking: bool,
}
impl<'a> EventTrackingPause<'a> {
fn new(runtime: &'a CudaRuntime) -> Self {
let context = runtime.context();
let was_tracking = context.is_event_tracking();
unsafe { context.disable_event_tracking() };
Self {
runtime,
was_tracking,
}
}
}
impl Drop for EventTrackingPause<'_> {
fn drop(&mut self) {
if self.was_tracking {
unsafe { self.runtime.context().enable_event_tracking() };
}
}
}