Skip to main content

baracuda_runtime/
event.rs

1//! Runtime-API events.
2
3use std::sync::Arc;
4
5use baracuda_cuda_sys::runtime::{cudaEvent_t, runtime, types::cudaEventFlags};
6
7use crate::error::{check, Result};
8use crate::stream::Stream;
9
10/// A CUDA event (Runtime API).
11#[derive(Clone)]
12pub struct Event {
13    inner: Arc<EventInner>,
14}
15
16struct EventInner {
17    handle: cudaEvent_t,
18}
19
20unsafe impl Send for EventInner {}
21unsafe impl Sync for EventInner {}
22
23impl core::fmt::Debug for EventInner {
24    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
25        f.debug_struct("Event")
26            .field("handle", &self.handle)
27            .finish_non_exhaustive()
28    }
29}
30
31impl core::fmt::Debug for Event {
32    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
33        self.inner.fmt(f)
34    }
35}
36
37impl Event {
38    /// Create an event with default flags (timing enabled, spinning wait).
39    pub fn new() -> Result<Self> {
40        Self::with_flags(cudaEventFlags::DEFAULT)
41    }
42
43    /// Create an event optimized for synchronization (no timing data).
44    pub fn no_timing() -> Result<Self> {
45        Self::with_flags(cudaEventFlags::DISABLE_TIMING)
46    }
47
48    /// Create an event with raw flags (see [`cudaEventFlags`]).
49    pub fn with_flags(flags: u32) -> Result<Self> {
50        let r = runtime()?;
51        let cu = r.cuda_event_create_with_flags()?;
52        let mut event: cudaEvent_t = core::ptr::null_mut();
53        check(unsafe { cu(&mut event, flags) })?;
54        Ok(Self {
55            inner: Arc::new(EventInner { handle: event }),
56        })
57    }
58
59    /// Record this event on the given stream.
60    pub fn record(&self, stream: &Stream) -> Result<()> {
61        let r = runtime()?;
62        let cu = r.cuda_event_record()?;
63        check(unsafe { cu(self.inner.handle, stream.as_raw()) })
64    }
65
66    /// Block the calling host thread until the event has completed.
67    pub fn synchronize(&self) -> Result<()> {
68        let r = runtime()?;
69        let cu = r.cuda_event_synchronize()?;
70        check(unsafe { cu(self.inner.handle) })
71    }
72
73    /// `Ok(true)` if the event has completed.
74    pub fn is_complete(&self) -> Result<bool> {
75        use baracuda_cuda_sys::runtime::cudaError_t;
76        let r = runtime()?;
77        let cu = r.cuda_event_query()?;
78        match unsafe { cu(self.inner.handle) } {
79            cudaError_t::Success => Ok(true),
80            cudaError_t::NotReady => Ok(false),
81            other => Err(crate::error::Error::Status { status: other }),
82        }
83    }
84
85    /// Milliseconds of device work between `start` and `end`. Both must have
86    /// been created with timing enabled.
87    pub fn elapsed_time_ms(start: &Event, end: &Event) -> Result<f32> {
88        let r = runtime()?;
89        let cu = r.cuda_event_elapsed_time()?;
90        let mut ms: f32 = 0.0;
91        check(unsafe { cu(&mut ms, start.inner.handle, end.inner.handle) })?;
92        Ok(ms)
93    }
94
95    /// Raw `cudaEvent_t`. Use with care.
96    #[inline]
97    pub fn as_raw(&self) -> cudaEvent_t {
98        self.inner.handle
99    }
100}
101
102impl Drop for EventInner {
103    fn drop(&mut self) {
104        if let Ok(r) = runtime() {
105            if let Ok(cu) = r.cuda_event_destroy() {
106                let _ = unsafe { cu(self.handle) };
107            }
108        }
109    }
110}