1use oxicuda_driver::ffi::CUevent;
12use oxicuda_driver::loader::try_driver;
13
14use crate::error::{CudaRtError, CudaRtResult};
15use crate::stream::CudaStream;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
23pub struct EventFlags(pub u32);
24
25impl EventFlags {
26 pub const DEFAULT: Self = Self(0x0);
28 pub const DISABLE_TIMING: Self = Self(0x2);
30 pub const INTERPROCESS: Self = Self(0x4);
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
41pub struct CudaEvent(CUevent);
42
43impl CudaEvent {
44 #[must_use]
51 pub const unsafe fn from_raw(raw: CUevent) -> Self {
52 Self(raw)
53 }
54
55 #[must_use]
57 pub fn raw(self) -> CUevent {
58 self.0
59 }
60
61 #[must_use]
63 pub fn is_null(self) -> bool {
64 self.0.is_null()
65 }
66}
67
68pub fn event_create() -> CudaRtResult<CudaEvent> {
78 event_create_with_flags(EventFlags::DEFAULT)
79}
80
81pub fn event_create_with_flags(flags: EventFlags) -> CudaRtResult<CudaEvent> {
89 let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
90 let mut event = CUevent::default();
91 let rc = unsafe { (api.cu_event_create)(&raw mut event, flags.0) };
93 if rc != 0 {
94 return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::InvalidResourceHandle));
95 }
96 Ok(CudaEvent(event))
97}
98
99pub fn event_destroy(event: CudaEvent) -> CudaRtResult<()> {
107 if event.is_null() {
108 return Ok(());
109 }
110 let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
111 let rc = unsafe { (api.cu_event_destroy_v2)(event.raw()) };
113 if rc != 0 {
114 return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::InvalidResourceHandle));
115 }
116 Ok(())
117}
118
119pub fn event_record(event: CudaEvent, stream: CudaStream) -> CudaRtResult<()> {
129 let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
130 let rc = unsafe { (api.cu_event_record)(event.raw(), stream.raw()) };
132 if rc != 0 {
133 return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::InvalidResourceHandle));
134 }
135 Ok(())
136}
137
138pub fn event_record_with_flags(
146 event: CudaEvent,
147 stream: CudaStream,
148 flags: u32,
149) -> CudaRtResult<()> {
150 let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
151 let f = api
153 .cu_event_record_with_flags
154 .ok_or(CudaRtError::NotSupported)?;
155 let rc = unsafe { f(event.raw(), stream.raw(), flags) };
156 if rc != 0 {
157 return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::InvalidResourceHandle));
158 }
159 Ok(())
160}
161
162pub fn event_synchronize(event: CudaEvent) -> CudaRtResult<()> {
170 let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
171 let rc = unsafe { (api.cu_event_synchronize)(event.raw()) };
173 if rc != 0 {
174 return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::NotReady));
175 }
176 Ok(())
177}
178
179pub fn event_query(event: CudaEvent) -> CudaRtResult<bool> {
189 let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
190 let rc = unsafe { (api.cu_event_query)(event.raw()) };
192 match rc {
193 0 => Ok(true),
194 600 => Ok(false), other => Err(CudaRtError::from_code(other).unwrap_or(CudaRtError::Unknown)),
196 }
197}
198
199pub fn event_elapsed_time(start: CudaEvent, end: CudaEvent) -> CudaRtResult<f32> {
210 let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
211 let mut ms: f32 = 0.0;
212 let rc = unsafe { (api.cu_event_elapsed_time)(&raw mut ms, start.raw(), end.raw()) };
214 if rc != 0 {
215 return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::InvalidResourceHandle));
216 }
217 Ok(ms)
218}
219
220#[cfg(test)]
223mod tests {
224 use super::*;
225
226 #[test]
227 fn event_flags_values() {
228 assert_eq!(EventFlags::DEFAULT.0, 0x0);
229 assert_eq!(EventFlags::DISABLE_TIMING.0, 0x2);
230 assert_eq!(EventFlags::INTERPROCESS.0, 0x4);
231 }
232
233 #[test]
234 fn event_create_without_gpu_returns_error() {
235 let _ = event_create();
237 }
238
239 #[test]
240 fn event_destroy_null_is_noop() {
241 let ev = unsafe { CudaEvent::from_raw(CUevent::default()) };
243 let _ = event_destroy(ev); }
245}