use oxicuda_driver::ffi::CUevent;
use oxicuda_driver::loader::try_driver;
use crate::error::{CudaRtError, CudaRtResult};
use crate::stream::CudaStream;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct EventFlags(pub u32);
impl EventFlags {
pub const DEFAULT: Self = Self(0x0);
pub const DISABLE_TIMING: Self = Self(0x2);
pub const INTERPROCESS: Self = Self(0x4);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CudaEvent(CUevent);
impl CudaEvent {
#[must_use]
pub const unsafe fn from_raw(raw: CUevent) -> Self {
Self(raw)
}
#[must_use]
pub fn raw(self) -> CUevent {
self.0
}
#[must_use]
pub fn is_null(self) -> bool {
self.0.is_null()
}
}
pub fn event_create() -> CudaRtResult<CudaEvent> {
event_create_with_flags(EventFlags::DEFAULT)
}
pub fn event_create_with_flags(flags: EventFlags) -> CudaRtResult<CudaEvent> {
let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
let mut event = CUevent::default();
let rc = unsafe { (api.cu_event_create)(&raw mut event, flags.0) };
if rc != 0 {
return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::InvalidResourceHandle));
}
Ok(CudaEvent(event))
}
pub fn event_destroy(event: CudaEvent) -> CudaRtResult<()> {
if event.is_null() {
return Ok(());
}
let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
let rc = unsafe { (api.cu_event_destroy_v2)(event.raw()) };
if rc != 0 {
return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::InvalidResourceHandle));
}
Ok(())
}
pub fn event_record(event: CudaEvent, stream: CudaStream) -> CudaRtResult<()> {
let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
let rc = unsafe { (api.cu_event_record)(event.raw(), stream.raw()) };
if rc != 0 {
return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::InvalidResourceHandle));
}
Ok(())
}
pub fn event_record_with_flags(
event: CudaEvent,
stream: CudaStream,
flags: u32,
) -> CudaRtResult<()> {
let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
let f = api
.cu_event_record_with_flags
.ok_or(CudaRtError::NotSupported)?;
let rc = unsafe { f(event.raw(), stream.raw(), flags) };
if rc != 0 {
return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::InvalidResourceHandle));
}
Ok(())
}
pub fn event_synchronize(event: CudaEvent) -> CudaRtResult<()> {
let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
let rc = unsafe { (api.cu_event_synchronize)(event.raw()) };
if rc != 0 {
return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::NotReady));
}
Ok(())
}
pub fn event_query(event: CudaEvent) -> CudaRtResult<bool> {
let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
let rc = unsafe { (api.cu_event_query)(event.raw()) };
match rc {
0 => Ok(true),
600 => Ok(false), other => Err(CudaRtError::from_code(other).unwrap_or(CudaRtError::Unknown)),
}
}
pub fn event_elapsed_time(start: CudaEvent, end: CudaEvent) -> CudaRtResult<f32> {
let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
let mut ms: f32 = 0.0;
let rc = unsafe { (api.cu_event_elapsed_time)(&raw mut ms, start.raw(), end.raw()) };
if rc != 0 {
return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::InvalidResourceHandle));
}
Ok(ms)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn event_flags_values() {
assert_eq!(EventFlags::DEFAULT.0, 0x0);
assert_eq!(EventFlags::DISABLE_TIMING.0, 0x2);
assert_eq!(EventFlags::INTERPROCESS.0, 0x4);
}
#[test]
fn event_create_without_gpu_returns_error() {
let _ = event_create();
}
#[test]
fn event_destroy_null_is_noop() {
let ev = unsafe { CudaEvent::from_raw(CUevent::default()) };
let _ = event_destroy(ev); }
}