use thiserror::Error;
pub type Result<T> = std::result::Result<T, GpuError>;
#[derive(Error, Debug)]
pub enum GpuError {
#[error("PTX generation error: {0}")]
PtxGeneration(String),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Invalid parameter: {0}")]
InvalidParameter(String),
#[error("Invalid PTX version: {major}.{minor} (requires >= 7.0)")]
InvalidPtxVersion {
major: u32,
minor: u32,
},
#[error("Invalid compute capability: {0} (requires sm_70+)")]
InvalidTarget(String),
#[error("CUDA driver error: {0} (code: {1})")]
CudaDriver(String, i32),
#[error("GPU memory allocation failed: {0}")]
MemoryAllocation(String),
#[error("Kernel launch failed: {0}")]
KernelLaunch(String),
#[error("Invalid launch config: {0}")]
InvalidLaunchConfig(String),
#[error("Register allocation failed: {0}")]
RegisterAllocation(String),
#[error("Bank conflict detected in shared memory access")]
BankConflict,
#[error("CUDA device initialization failed: {0}")]
DeviceInit(String),
#[error("CUDA device {0} not found (available: {1})")]
DeviceNotFound(i32, usize),
#[error("CUDA module loading failed: {0}")]
ModuleLoad(String),
#[error("CUDA function '{0}' not found in module")]
FunctionNotFound(String),
#[error("CUDA stream creation failed: {0}")]
StreamCreate(String),
#[error("CUDA stream synchronization failed: {0}")]
StreamSync(String),
#[error("CUDA memory transfer failed: {0}")]
Transfer(String),
#[error("Out of GPU memory: requested {requested} bytes, available {available} bytes")]
OutOfMemory {
requested: usize,
available: usize,
},
#[error("CUDA not available: {0}")]
CudaNotAvailable(String),
#[error("Not supported: {0}")]
NotSupported(String),
#[error("CUDA graph creation failed: {0}")]
GraphCreate(String),
#[error("CUDA graph capture failed: {0}")]
GraphCapture(String),
#[error("CUDA graph instantiation failed: {0}")]
GraphInstantiate(String),
#[error("CUDA graph launch failed: {0}")]
GraphLaunch(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ptx_generation_error() {
let err = GpuError::PtxGeneration("invalid instruction".to_string());
assert!(err.to_string().contains("PTX generation error"));
assert!(err.to_string().contains("invalid instruction"));
}
#[test]
fn test_invalid_ptx_version() {
let err = GpuError::InvalidPtxVersion { major: 6, minor: 5 };
assert!(err.to_string().contains("6.5"));
assert!(err.to_string().contains("requires >= 7.0"));
}
#[test]
fn test_invalid_target() {
let err = GpuError::InvalidTarget("sm_50".to_string());
assert!(err.to_string().contains("sm_50"));
assert!(err.to_string().contains("requires sm_70+"));
}
#[test]
fn test_cuda_driver_error() {
let err = GpuError::CudaDriver("out of memory".to_string(), 2);
assert!(err.to_string().contains("out of memory"));
assert!(err.to_string().contains("code: 2"));
}
#[test]
fn test_memory_allocation_error() {
let err = GpuError::MemoryAllocation("insufficient device memory".to_string());
assert!(err.to_string().contains("allocation failed"));
}
#[test]
fn test_kernel_launch_error() {
let err = GpuError::KernelLaunch("invalid grid dimensions".to_string());
assert!(err.to_string().contains("launch failed"));
}
#[test]
fn test_error_debug() {
let err = GpuError::BankConflict;
let _ = format!("{:?}", err);
}
#[test]
fn test_error_display() {
let err = GpuError::PtxGeneration("test".to_string());
assert!(err.to_string().contains("test"));
}
#[test]
fn test_io_error() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let err: GpuError = io_err.into();
assert!(err.to_string().contains("I/O error"));
}
#[test]
fn test_invalid_parameter() {
let err = GpuError::InvalidParameter("bad value".to_string());
assert!(err.to_string().contains("Invalid parameter"));
assert!(err.to_string().contains("bad value"));
}
#[test]
fn test_device_init_error() {
let err = GpuError::DeviceInit("no CUDA driver".to_string());
assert!(err.to_string().contains("initialization failed"));
assert!(err.to_string().contains("no CUDA driver"));
}
#[test]
fn test_device_not_found_error() {
let err = GpuError::DeviceNotFound(5, 2);
assert!(err.to_string().contains("device 5"));
assert!(err.to_string().contains("available: 2"));
}
#[test]
fn test_module_load_error() {
let err = GpuError::ModuleLoad("invalid PTX".to_string());
assert!(err.to_string().contains("module loading failed"));
}
#[test]
fn test_function_not_found_error() {
let err = GpuError::FunctionNotFound("my_kernel".to_string());
assert!(err.to_string().contains("my_kernel"));
assert!(err.to_string().contains("not found"));
}
#[test]
fn test_stream_create_error() {
let err = GpuError::StreamCreate("resource exhausted".to_string());
assert!(err.to_string().contains("stream creation"));
}
#[test]
fn test_stream_sync_error() {
let err = GpuError::StreamSync("timeout".to_string());
assert!(err.to_string().contains("synchronization"));
}
#[test]
fn test_transfer_error() {
let err = GpuError::Transfer("DMA error".to_string());
assert!(err.to_string().contains("transfer failed"));
}
#[test]
fn test_out_of_memory_error() {
let err = GpuError::OutOfMemory { requested: 1_000_000_000, available: 500_000_000 };
assert!(err.to_string().contains("1000000000"));
assert!(err.to_string().contains("500000000"));
}
#[test]
fn test_cuda_not_available_error() {
let err = GpuError::CudaNotAvailable("no GPU detected".to_string());
assert!(err.to_string().contains("not available"));
}
#[test]
fn test_not_supported_error() {
let err = GpuError::NotSupported("CPU temperature monitoring".to_string());
assert!(err.to_string().contains("Not supported"));
assert!(err.to_string().contains("CPU temperature"));
}
}