#![allow(deprecated)]
use std::{
ffi::{CStr, NulError},
fmt::{self, Display, Formatter},
};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use singe_core::impl_enum_conversion;
use singe_cuda::error::Error as CudaError;
use singe_cupti_sys as sys;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("cuda error: {0}")]
Cuda(#[from] CudaError),
#[error("cupti error ({code}): {message}")]
Cupti { code: Status, message: String },
#[error("string contains interior nul byte")]
InteriorNul,
#[error("unexpected null handle")]
NullHandle,
#[error("{name} is out of range")]
OutOfRange { name: String },
#[error("unexpected length for {name}: expected {expected}, got {actual}")]
LengthMismatch {
name: String,
expected: usize,
actual: usize,
},
#[error("invalid attribute: {name}")]
InvalidAttribute { name: String },
#[error("{name} lock poisoned")]
LockPoisoned { name: String },
}
pub type Result<T> = std::result::Result<T, Error>;
#[allow(deprecated)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum Status {
Success = sys::CUptiResult::CUPTI_SUCCESS as _,
InvalidParameter = sys::CUptiResult::CUPTI_ERROR_INVALID_PARAMETER as _,
InvalidDevice = sys::CUptiResult::CUPTI_ERROR_INVALID_DEVICE as _,
InvalidContext = sys::CUptiResult::CUPTI_ERROR_INVALID_CONTEXT as _,
InvalidEventDomainId = sys::CUptiResult::CUPTI_ERROR_INVALID_EVENT_DOMAIN_ID as _,
InvalidEventId = sys::CUptiResult::CUPTI_ERROR_INVALID_EVENT_ID as _,
InvalidEventName = sys::CUptiResult::CUPTI_ERROR_INVALID_EVENT_NAME as _,
InvalidOperation = sys::CUptiResult::CUPTI_ERROR_INVALID_OPERATION as _,
OutOfMemory = sys::CUptiResult::CUPTI_ERROR_OUT_OF_MEMORY as _,
Hardware = sys::CUptiResult::CUPTI_ERROR_HARDWARE as _,
ParameterSizeNotSufficient = sys::CUptiResult::CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT as _,
ApiNotImplemented = sys::CUptiResult::CUPTI_ERROR_API_NOT_IMPLEMENTED as _,
MaxLimitReached = sys::CUptiResult::CUPTI_ERROR_MAX_LIMIT_REACHED as _,
NotReady = sys::CUptiResult::CUPTI_ERROR_NOT_READY as _,
NotCompatible = sys::CUptiResult::CUPTI_ERROR_NOT_COMPATIBLE as _,
NotInitialized = sys::CUptiResult::CUPTI_ERROR_NOT_INITIALIZED as _,
InvalidMetricId = sys::CUptiResult::CUPTI_ERROR_INVALID_METRIC_ID as _,
InvalidMetricName = sys::CUptiResult::CUPTI_ERROR_INVALID_METRIC_NAME as _,
QueueEmpty = sys::CUptiResult::CUPTI_ERROR_QUEUE_EMPTY as _,
InvalidHandle = sys::CUptiResult::CUPTI_ERROR_INVALID_HANDLE as _,
InvalidStream = sys::CUptiResult::CUPTI_ERROR_INVALID_STREAM as _,
InvalidKind = sys::CUptiResult::CUPTI_ERROR_INVALID_KIND as _,
InvalidEventValue = sys::CUptiResult::CUPTI_ERROR_INVALID_EVENT_VALUE as _,
Disabled = sys::CUptiResult::CUPTI_ERROR_DISABLED as _,
InvalidModule = sys::CUptiResult::CUPTI_ERROR_INVALID_MODULE as _,
InvalidMetricValue = sys::CUptiResult::CUPTI_ERROR_INVALID_METRIC_VALUE as _,
HardwareBusy = sys::CUptiResult::CUPTI_ERROR_HARDWARE_BUSY as _,
NotSupported = sys::CUptiResult::CUPTI_ERROR_NOT_SUPPORTED as _,
UmProfilingNotSupported = sys::CUptiResult::CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED as _,
UmProfilingNotSupportedOnDevice =
sys::CUptiResult::CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED_ON_DEVICE as _,
UmProfilingNotSupportedOnNonP2pDevices =
sys::CUptiResult::CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED_ON_NON_P2P_DEVICES as _,
UmProfilingNotSupportedWithMps =
sys::CUptiResult::CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED_WITH_MPS as _,
CdpTracingNotSupported = sys::CUptiResult::CUPTI_ERROR_CDP_TRACING_NOT_SUPPORTED as _,
VirtualizedDeviceNotSupported =
sys::CUptiResult::CUPTI_ERROR_VIRTUALIZED_DEVICE_NOT_SUPPORTED as _,
CudaCompilerNotCompatible = sys::CUptiResult::CUPTI_ERROR_CUDA_COMPILER_NOT_COMPATIBLE as _,
InsufficientPrivileges = sys::CUptiResult::CUPTI_ERROR_INSUFFICIENT_PRIVILEGES as _,
OldProfilerApiInitialized = sys::CUptiResult::CUPTI_ERROR_OLD_PROFILER_API_INITIALIZED as _,
OpenAccUndefinedRoutine = sys::CUptiResult::CUPTI_ERROR_OPENACC_UNDEFINED_ROUTINE as _,
#[allow(deprecated)]
LegacyProfilerNotSupported = sys::CUptiResult::CUPTI_ERROR_LEGACY_PROFILER_NOT_SUPPORTED as _,
MultipleSubscribersNotSupported =
sys::CUptiResult::CUPTI_ERROR_MULTIPLE_SUBSCRIBERS_NOT_SUPPORTED as _,
VirtualizedDeviceInsufficientPrivileges =
sys::CUptiResult::CUPTI_ERROR_VIRTUALIZED_DEVICE_INSUFFICIENT_PRIVILEGES as _,
ConfidentialComputingNotSupported =
sys::CUptiResult::CUPTI_ERROR_CONFIDENTIAL_COMPUTING_NOT_SUPPORTED as _,
CmpDeviceNotSupported = sys::CUptiResult::CUPTI_ERROR_CMP_DEVICE_NOT_SUPPORTED as _,
MigDeviceNotSupported = sys::CUptiResult::CUPTI_ERROR_MIG_DEVICE_NOT_SUPPORTED as _,
SliDeviceNotSupported = sys::CUptiResult::CUPTI_ERROR_SLI_DEVICE_NOT_SUPPORTED as _,
WslDeviceNotSupported = sys::CUptiResult::CUPTI_ERROR_WSL_DEVICE_NOT_SUPPORTED as _,
InvalidChipName = sys::CUptiResult::CUPTI_ERROR_INVALID_CHIP_NAME as _,
HesTraceNotSupportedOnMps = sys::CUptiResult::CUPTI_ERROR_HES_TRACE_NOT_SUPPORTED_ON_MPS as _,
Unknown = sys::CUptiResult::CUPTI_ERROR_UNKNOWN as _,
ForceInt = sys::CUptiResult::CUPTI_ERROR_FORCE_INT as _,
}
impl_enum_conversion!(sys::CUptiResult, Status);
impl Status {
pub fn description(self) -> String {
self.to_string()
.trim_start_matches("CUPTI_ERROR_")
.trim_start_matches("CUPTI_")
.replace('_', " ")
.to_ascii_lowercase()
}
}
impl Display for Status {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Success => write!(f, "CUPTI_SUCCESS"),
Self::InvalidParameter => write!(f, "CUPTI_ERROR_INVALID_PARAMETER"),
Self::InvalidDevice => write!(f, "CUPTI_ERROR_INVALID_DEVICE"),
Self::InvalidContext => write!(f, "CUPTI_ERROR_INVALID_CONTEXT"),
Self::InvalidEventDomainId => write!(f, "CUPTI_ERROR_INVALID_EVENT_DOMAIN_ID"),
Self::InvalidEventId => write!(f, "CUPTI_ERROR_INVALID_EVENT_ID"),
Self::InvalidEventName => write!(f, "CUPTI_ERROR_INVALID_EVENT_NAME"),
Self::InvalidOperation => write!(f, "CUPTI_ERROR_INVALID_OPERATION"),
Self::OutOfMemory => write!(f, "CUPTI_ERROR_OUT_OF_MEMORY"),
Self::Hardware => write!(f, "CUPTI_ERROR_HARDWARE"),
Self::ParameterSizeNotSufficient => {
write!(f, "CUPTI_ERROR_PARAMETER_SIZE_NOT_SUFFICIENT")
}
Self::ApiNotImplemented => write!(f, "CUPTI_ERROR_API_NOT_IMPLEMENTED"),
Self::MaxLimitReached => write!(f, "CUPTI_ERROR_MAX_LIMIT_REACHED"),
Self::NotReady => write!(f, "CUPTI_ERROR_NOT_READY"),
Self::NotCompatible => write!(f, "CUPTI_ERROR_NOT_COMPATIBLE"),
Self::NotInitialized => write!(f, "CUPTI_ERROR_NOT_INITIALIZED"),
Self::InvalidMetricId => write!(f, "CUPTI_ERROR_INVALID_METRIC_ID"),
Self::InvalidMetricName => write!(f, "CUPTI_ERROR_INVALID_METRIC_NAME"),
Self::QueueEmpty => write!(f, "CUPTI_ERROR_QUEUE_EMPTY"),
Self::InvalidHandle => write!(f, "CUPTI_ERROR_INVALID_HANDLE"),
Self::InvalidStream => write!(f, "CUPTI_ERROR_INVALID_STREAM"),
Self::InvalidKind => write!(f, "CUPTI_ERROR_INVALID_KIND"),
Self::InvalidEventValue => write!(f, "CUPTI_ERROR_INVALID_EVENT_VALUE"),
Self::Disabled => write!(f, "CUPTI_ERROR_DISABLED"),
Self::InvalidModule => write!(f, "CUPTI_ERROR_INVALID_MODULE"),
Self::InvalidMetricValue => write!(f, "CUPTI_ERROR_INVALID_METRIC_VALUE"),
Self::HardwareBusy => write!(f, "CUPTI_ERROR_HARDWARE_BUSY"),
Self::NotSupported => write!(f, "CUPTI_ERROR_NOT_SUPPORTED"),
Self::UmProfilingNotSupported => write!(f, "CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED"),
Self::UmProfilingNotSupportedOnDevice => {
write!(f, "CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED_ON_DEVICE")
}
Self::UmProfilingNotSupportedOnNonP2pDevices => {
write!(
f,
"CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED_ON_NON_P2P_DEVICES"
)
}
Self::UmProfilingNotSupportedWithMps => {
write!(f, "CUPTI_ERROR_UM_PROFILING_NOT_SUPPORTED_WITH_MPS")
}
Self::CdpTracingNotSupported => write!(f, "CUPTI_ERROR_CDP_TRACING_NOT_SUPPORTED"),
Self::VirtualizedDeviceNotSupported => {
write!(f, "CUPTI_ERROR_VIRTUALIZED_DEVICE_NOT_SUPPORTED")
}
Self::CudaCompilerNotCompatible => {
write!(f, "CUPTI_ERROR_CUDA_COMPILER_NOT_COMPATIBLE")
}
Self::InsufficientPrivileges => write!(f, "CUPTI_ERROR_INSUFFICIENT_PRIVILEGES"),
Self::OldProfilerApiInitialized => {
write!(f, "CUPTI_ERROR_OLD_PROFILER_API_INITIALIZED")
}
Self::OpenAccUndefinedRoutine => write!(f, "CUPTI_ERROR_OPENACC_UNDEFINED_ROUTINE"),
Self::LegacyProfilerNotSupported => {
write!(f, "CUPTI_ERROR_LEGACY_PROFILER_NOT_SUPPORTED")
}
Self::MultipleSubscribersNotSupported => {
write!(f, "CUPTI_ERROR_MULTIPLE_SUBSCRIBERS_NOT_SUPPORTED")
}
Self::VirtualizedDeviceInsufficientPrivileges => {
write!(f, "CUPTI_ERROR_VIRTUALIZED_DEVICE_INSUFFICIENT_PRIVILEGES")
}
Self::ConfidentialComputingNotSupported => {
write!(f, "CUPTI_ERROR_CONFIDENTIAL_COMPUTING_NOT_SUPPORTED")
}
Self::CmpDeviceNotSupported => write!(f, "CUPTI_ERROR_CMP_DEVICE_NOT_SUPPORTED"),
Self::MigDeviceNotSupported => write!(f, "CUPTI_ERROR_MIG_DEVICE_NOT_SUPPORTED"),
Self::SliDeviceNotSupported => write!(f, "CUPTI_ERROR_SLI_DEVICE_NOT_SUPPORTED"),
Self::WslDeviceNotSupported => write!(f, "CUPTI_ERROR_WSL_DEVICE_NOT_SUPPORTED"),
Self::InvalidChipName => write!(f, "CUPTI_ERROR_INVALID_CHIP_NAME"),
Self::HesTraceNotSupportedOnMps => {
write!(f, "CUPTI_ERROR_HES_TRACE_NOT_SUPPORTED_ON_MPS")
}
Self::Unknown => write!(f, "CUPTI_ERROR_UNKNOWN"),
Self::ForceInt => write!(f, "CUPTI_ERROR_FORCE_INT"),
}
}
}
impl From<sys::CUptiResult> for Error {
fn from(code: sys::CUptiResult) -> Self {
debug_assert_ne!(code, sys::CUptiResult::CUPTI_SUCCESS);
let status = Status::try_from(code as u32).unwrap_or(Status::Unknown);
let message = unsafe {
let mut message_ptr = std::ptr::null();
let error_result = sys::cuptiGetErrorMessage(code, &mut message_ptr);
if error_result == sys::CUptiResult::CUPTI_SUCCESS && !message_ptr.is_null() {
CStr::from_ptr(message_ptr).to_string_lossy().into_owned()
} else {
format!("cupti error code {:?}", code)
}
};
Self::Cupti {
code: status,
message,
}
}
}
impl From<Status> for Error {
fn from(status: Status) -> Self {
sys::CUptiResult::from(status).into()
}
}
pub fn result_string(status: Status) -> Result<String> {
let mut message = std::ptr::null();
unsafe {
crate::try_ffi!(sys::cuptiGetResultString(status.into(), &mut message))?;
if message.is_null() {
return Err(Error::NullHandle);
}
Ok(CStr::from_ptr(message).to_string_lossy().into_owned())
}
}
pub fn error_message(status: Status) -> Result<String> {
let mut message = std::ptr::null();
unsafe {
crate::try_ffi!(sys::cuptiGetErrorMessage(status.into(), &mut message))?;
if message.is_null() {
return Err(Error::NullHandle);
}
Ok(CStr::from_ptr(message).to_string_lossy().into_owned())
}
}
impl From<NulError> for Error {
fn from(_: NulError) -> Self {
Self::InteriorNul
}
}
#[macro_export]
macro_rules! try_ffi {
($expr:expr) => {{
let status = { $expr };
if status != singe_cupti_sys::CUptiResult::CUPTI_SUCCESS {
Err($crate::error::Error::from(status))
} else {
Ok(())
}
}};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn result_string_and_error_message_are_available() -> Result<()> {
let result_string = result_string(Status::Success)?;
let error_message = error_message(Status::InvalidParameter)?;
assert!(result_string.contains("CUPTI_SUCCESS"));
assert!(!error_message.is_empty());
Ok(())
}
}