#[cfg(feature = "nvidia")]
use crate::{ComputeCapability, CudaHost, CudaVersion, GpuInfo, Vendor};
#[cfg(feature = "nvidia")]
use nvml_wrapper::Nvml;
#[cfg(feature = "nvidia")]
use std::sync::OnceLock;
#[cfg(feature = "nvidia")]
static NVML: OnceLock<Nvml> = OnceLock::new();
#[cfg(feature = "nvidia")]
fn nvml() -> Option<&'static Nvml> {
if let Some(nvml) = NVML.get() {
return Some(nvml);
}
let nvml = Nvml::init().ok()?;
Some(NVML.get_or_init(|| nvml))
}
#[cfg(feature = "nvidia")]
pub(crate) fn detect() -> Vec<GpuInfo> {
let Some(nvml) = nvml() else {
return Vec::new();
};
let Ok(count) = nvml.device_count() else {
return Vec::new();
};
let mut gpus = Vec::new();
for index in 0..count {
let Ok(device) = nvml.device_by_index(index) else {
continue;
};
let Ok(memory) = device.memory_info() else {
continue;
};
gpus.push(GpuInfo {
name: device.name().unwrap_or_else(|_| "NVIDIA GPU".to_string()),
vendor: Vendor::Nvidia,
total_bytes: memory.total,
free_bytes: Some(memory.free),
used_bytes: Some(memory.used),
});
}
gpus
}
#[cfg(feature = "nvidia")]
pub(crate) fn cuda_host() -> Option<CudaHost> {
let nvml = nvml()?;
let capability = nvml
.device_by_index(0)
.ok()?
.cuda_compute_capability()
.ok()?;
let compute_capability = ComputeCapability {
major: u32::try_from(capability.major).ok()?,
minor: u32::try_from(capability.minor).ok()?,
};
let packed = nvml.sys_cuda_driver_version().ok()?;
if packed <= 0 {
return None;
}
let driver_version = CudaVersion {
major: u32::try_from(nvml_wrapper::cuda_driver_version_major(packed)).ok()?,
minor: u32::try_from(nvml_wrapper::cuda_driver_version_minor(packed)).ok()?,
};
Some(CudaHost {
compute_capability,
driver_version,
})
}
#[cfg(not(feature = "nvidia"))]
pub(crate) fn detect() -> Vec<crate::GpuInfo> {
Vec::new()
}
#[cfg(not(feature = "nvidia"))]
pub(crate) fn cuda_host() -> Option<crate::CudaHost> {
None
}