use std::num::NonZeroU32;
use cudarc::driver::CudaContext;
use cudarc::driver::sys::CUdevice_attribute;
use crate::{ComputeCapability, Error};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeviceAttributes {
capability: ComputeCapability,
multiprocessors: NonZeroU32,
l2_bytes: u32,
shared_optin_bytes: u32,
name: Box<str>,
}
impl DeviceAttributes {
pub(crate) fn query(context: &CudaContext) -> Result<Self, Error> {
let (major, minor) = context.compute_capability()?;
let capability = ComputeCapability::new(
u32::try_from(major).unwrap_or(0),
u32::try_from(minor).unwrap_or(0),
);
context.bind_to_thread()?;
let attribute = |attribute| -> Result<u32, Error> {
Ok(u32::try_from(context.attribute(attribute)?).unwrap_or(0))
};
let multiprocessors = NonZeroU32::new(attribute(
CUdevice_attribute::CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT,
)?)
.ok_or_else(|| Error::Unsupported {
context: "device attributes",
reason: "the driver reports no streaming multiprocessors".to_owned(),
})?;
Ok(Self {
capability,
multiprocessors,
l2_bytes: attribute(CUdevice_attribute::CU_DEVICE_ATTRIBUTE_L2_CACHE_SIZE)?,
shared_optin_bytes: attribute(
CUdevice_attribute::CU_DEVICE_ATTRIBUTE_MAX_SHARED_MEMORY_PER_BLOCK_OPTIN,
)?,
name: context.name()?.into_boxed_str(),
})
}
pub const fn capability(&self) -> ComputeCapability {
self.capability
}
pub const fn multiprocessors(&self) -> NonZeroU32 {
self.multiprocessors
}
pub const fn l2_bytes(&self) -> u32 {
self.l2_bytes
}
pub const fn shared_optin_bytes(&self) -> u32 {
self.shared_optin_bytes
}
pub fn name(&self) -> &str {
&self.name
}
}
#[cfg(feature = "test-support")]
#[derive(Debug, Clone)]
pub struct DeviceAttributesBuilder(DeviceAttributes);
#[cfg(feature = "test-support")]
impl DeviceAttributesBuilder {
pub fn new(capability: ComputeCapability) -> Self {
Self(DeviceAttributes {
capability,
multiprocessors: NonZeroU32::MIN,
l2_bytes: 4 << 20,
shared_optin_bytes: 99 << 10,
name: "test device".into(),
})
}
pub fn multiprocessors(mut self, count: u32) -> Self {
self.0.multiprocessors = NonZeroU32::new(count).expect("a device has SMs");
self
}
pub fn shared_optin_bytes(mut self, bytes: u32) -> Self {
self.0.shared_optin_bytes = bytes;
self
}
pub fn name(mut self, name: &str) -> Self {
self.0.name = name.into();
self
}
pub fn build(self) -> DeviceAttributes {
self.0
}
}