1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use cuda::cudaError_enum as DeviceError;
use std::path::PathBuf;

pub type Result<T> = ::std::result::Result<T, AccelError>;

#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, Hash)]
pub enum AccelError {
    /// Raw errors originates from CUDA Device APIs
    #[error("CUDA Device API Error: {api_name}, {error:?}")]
    CUDAError {
        api_name: String,
        error: DeviceError,
    },

    // This is not an error potentially, but it should be a bug if not captured by accel
    #[error("Async operations issues previously have not completed yet")]
    AsyncOperationNotReady,

    /// Error for user device code assertion
    #[error("Assertion in device code has failed")]
    DeviceAssertionFailed,

    #[error("No device found for given ID")]
    DeviceNotFound { id: usize, count: usize },

    #[error("File not found: {path:?}")]
    FileNotFound { path: PathBuf },
}

/// Convert return code of CUDA Driver/Runtime API into Result
pub(crate) fn check(error: DeviceError, api_name: &str) -> Result<()> {
    match error {
        DeviceError::CUDA_SUCCESS => Ok(()),
        DeviceError::CUDA_ERROR_ASSERT => Err(AccelError::DeviceAssertionFailed),
        DeviceError::CUDA_ERROR_NOT_READY => Err(AccelError::AsyncOperationNotReady),
        _ => Err(AccelError::CUDAError {
            api_name: api_name.into(),
            error,
        }),
    }
}

#[macro_export]
macro_rules! ffi_call {
    ($ffi:path $(,$args:expr)*) => {
        {
            $crate::error::check($ffi($($args),*), stringify!($ffi))
        }
    };
}

#[macro_export]
macro_rules! ffi_new {
    ($ffi:path $(,$args:expr)*) => {
        {
            let mut value = ::std::mem::MaybeUninit::uninit();
            $crate::error::check($ffi(value.as_mut_ptr(), $($args),*), stringify!($ffi)).map(|_| value.assume_init())
        }
    };
}

#[macro_export]
macro_rules! contexted_call {
    ($ctx:expr, $ffi:path $(,$args:expr)*) => {
        {
            let _g = $crate::Contexted::guard_context($ctx);
            $crate::ffi_call!($ffi $(,$args)*)
        }
    };
}

#[macro_export]
macro_rules! contexted_new {
    ($ctx:expr, $ffi:path $(,$args:expr)*) => {
        {
            let _g = $crate::Contexted::guard_context($ctx);
            $crate::ffi_new!($ffi $(,$args)*)
        }
    };
}