Skip to main content

oxicuda_rocm/
error.rs

1//! Error types for the `oxicuda-rocm` backend.
2
3use oxicuda_backend::BackendError;
4
5/// Errors specific to the ROCm/HIP compute backend.
6#[derive(Debug, thiserror::Error)]
7pub enum RocmError {
8    /// ROCm/HIP is only supported on Linux.
9    #[error("ROCm/HIP requires Linux")]
10    UnsupportedPlatform,
11
12    /// The HIP runtime shared library was not found or failed to load.
13    #[error("HIP library not found: {0}")]
14    LibraryNotFound(String),
15
16    /// A HIP runtime API returned a non-zero error code.
17    #[error("HIP error code {0}: {1}")]
18    HipError(i32, String),
19
20    /// No AMD GPU was discovered on this system.
21    #[error("no AMD GPU found")]
22    NoSuitableDevice,
23
24    /// Device memory allocation failed due to insufficient resources.
25    #[error("out of device memory")]
26    OutOfMemory,
27
28    /// The backend has not been initialized yet.
29    #[error("not initialized")]
30    NotInitialized,
31
32    /// The requested operation is not yet supported by this backend.
33    #[error("unsupported: {0}")]
34    Unsupported(String),
35
36    /// An invalid argument was passed to an operation.
37    #[error("invalid argument: {0}")]
38    InvalidArgument(String),
39
40    /// A device-level error occurred.
41    #[error("device error: {0}")]
42    DeviceError(String),
43}
44
45/// Convenience result alias for ROCm operations.
46pub type RocmResult<T> = Result<T, RocmError>;
47
48impl From<RocmError> for BackendError {
49    fn from(e: RocmError) -> Self {
50        match e {
51            RocmError::UnsupportedPlatform => {
52                BackendError::DeviceError("ROCm/HIP requires Linux".into())
53            }
54            RocmError::LibraryNotFound(s) => {
55                BackendError::DeviceError(format!("HIP library not found: {s}"))
56            }
57            RocmError::HipError(code, msg) => {
58                BackendError::DeviceError(format!("hip({code}): {msg}"))
59            }
60            RocmError::NoSuitableDevice => BackendError::DeviceError("no AMD GPU found".into()),
61            RocmError::OutOfMemory => BackendError::OutOfMemory,
62            RocmError::NotInitialized => BackendError::NotInitialized,
63            RocmError::Unsupported(s) => BackendError::Unsupported(s),
64            RocmError::InvalidArgument(s) => BackendError::InvalidArgument(s),
65            RocmError::DeviceError(s) => BackendError::DeviceError(s),
66        }
67    }
68}
69
70// ─── Tests ───────────────────────────────────────────────────────────────────
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn rocm_error_display() {
78        assert_eq!(
79            RocmError::UnsupportedPlatform.to_string(),
80            "ROCm/HIP requires Linux"
81        );
82        assert_eq!(
83            RocmError::LibraryNotFound("libamdhip64.so".into()).to_string(),
84            "HIP library not found: libamdhip64.so"
85        );
86        assert_eq!(
87            RocmError::HipError(1, "invalid device".into()).to_string(),
88            "HIP error code 1: invalid device"
89        );
90        assert_eq!(RocmError::NoSuitableDevice.to_string(), "no AMD GPU found");
91        assert_eq!(RocmError::OutOfMemory.to_string(), "out of device memory");
92        assert_eq!(RocmError::NotInitialized.to_string(), "not initialized");
93        assert_eq!(
94            RocmError::Unsupported("gemm".into()).to_string(),
95            "unsupported: gemm"
96        );
97        assert_eq!(
98            RocmError::InvalidArgument("bad ptr".into()).to_string(),
99            "invalid argument: bad ptr"
100        );
101        assert_eq!(
102            RocmError::DeviceError("kernel launch failed".into()).to_string(),
103            "device error: kernel launch failed"
104        );
105    }
106
107    #[test]
108    fn backend_error_from_rocm_error() {
109        let e = BackendError::from(RocmError::OutOfMemory);
110        assert_eq!(e, BackendError::OutOfMemory);
111
112        let e = BackendError::from(RocmError::NotInitialized);
113        assert_eq!(e, BackendError::NotInitialized);
114
115        let e = BackendError::from(RocmError::Unsupported("foo".into()));
116        assert_eq!(e, BackendError::Unsupported("foo".into()));
117
118        let e = BackendError::from(RocmError::InvalidArgument("bar".into()));
119        assert_eq!(e, BackendError::InvalidArgument("bar".into()));
120
121        let e = BackendError::from(RocmError::UnsupportedPlatform);
122        assert!(matches!(e, BackendError::DeviceError(_)));
123
124        let e = BackendError::from(RocmError::LibraryNotFound("x".into()));
125        assert!(matches!(e, BackendError::DeviceError(_)));
126
127        let e = BackendError::from(RocmError::HipError(42, "something".into()));
128        assert!(matches!(e, BackendError::DeviceError(_)));
129
130        let e = BackendError::from(RocmError::NoSuitableDevice);
131        assert!(matches!(e, BackendError::DeviceError(_)));
132
133        let e = BackendError::from(RocmError::DeviceError("boom".into()));
134        assert!(matches!(e, BackendError::DeviceError(_)));
135    }
136}