use crate::model::GpuInfo;
use std::process::Command;
pub fn collect_gpu_info() -> Vec<GpuInfo> {
if let Some(nvidia_gpus) = collect_nvidia_gpus()
&& !nvidia_gpus.is_empty()
{
tracing::debug!("Found {} NVIDIA GPU(s) via NVML", nvidia_gpus.len());
return nvidia_gpus;
}
tracing::debug!("NVML not available, falling back to WMIC");
collect_gpus_via_wmic()
}
#[allow(clippy::cast_precision_loss)]
fn collect_nvidia_gpus() -> Option<Vec<GpuInfo>> {
use nvml_wrapper::Nvml;
let Ok(nvml) = Nvml::init() else {
return None;
};
let Ok(device_count) = nvml.device_count() else {
return None;
};
let mut gpus = Vec::new();
for i in 0..device_count {
match nvml.device_by_index(i) {
Ok(device) => {
let model = device
.name()
.unwrap_or_else(|_| "Unknown NVIDIA GPU".to_owned());
let memory_info = device.memory_info().ok();
let total_memory_mb = memory_info
.as_ref()
.map(|m| m.total as f64 / 1024.0 / 1024.0);
let used_memory_mb = memory_info
.as_ref()
.map(|m| m.used as f64 / 1024.0 / 1024.0);
let cores = None;
gpus.push(GpuInfo {
model,
cores,
total_memory_mb,
used_memory_mb,
});
tracing::debug!(
"NVIDIA GPU {}: {} (Memory: {:.0} MB / {:.0} MB)",
i,
gpus.last()?.model,
used_memory_mb.unwrap_or(0.0),
total_memory_mb.unwrap_or(0.0)
);
}
Err(e) => {
tracing::warn!("Failed to get NVML device handle for GPU #{}: {}", i, e);
}
}
}
Some(gpus)
}
#[allow(clippy::cast_precision_loss)]
fn collect_gpus_via_wmic() -> Vec<GpuInfo> {
let output = Command::new("wmic")
.args([
"path",
"win32_VideoController",
"get",
"name,AdapterRAM",
"/format:csv",
])
.output();
if let Ok(output) = output
&& output.status.success()
{
let output_str = String::from_utf8_lossy(&output.stdout);
let mut gpus = Vec::new();
for line in output_str.lines().skip(1) {
let parts: Vec<&str> = line.split(',').collect();
if parts.len() >= 3 {
let name = parts[1].trim();
if !name.is_empty() {
let mut gpu = GpuInfo {
model: name.to_owned(),
cores: None,
total_memory_mb: None,
used_memory_mb: None,
};
if let Ok(ram_bytes) = parts[2].trim().parse::<u64>()
&& ram_bytes > 0
{
gpu.total_memory_mb = Some(ram_bytes as f64 / (1024.0 * 1024.0));
}
gpus.push(gpu);
}
}
}
if !gpus.is_empty() {
tracing::debug!("Found {} GPU(s) via WMIC", gpus.len());
}
return gpus;
}
Vec::new()
}