fix: Fix hwinfo bugs (#5164)

* add libnvidia-ml.so.1 fallback for linux

* fix AMD memory usage on Linux

* add os_type. use std::env::consts::ARCH directly
This commit is contained in:
Thien Tran 2025-06-02 17:39:10 +08:00 committed by GitHub
parent ae6d343d19
commit 8509479dfb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 85 additions and 46 deletions

View File

@ -20,40 +20,58 @@ impl GpuInfo {
}
};
for card_idx in 0.. {
let device_path = format!("/sys/class/drm/card{}/device", card_idx);
if !Path::new(&device_path).exists() {
break;
}
let closure = || -> Result<GpuUsage, Box<dyn std::error::Error>> {
for subdir in fs::read_dir("/sys/class/drm")? {
let device_path = subdir?.path().join("device");
// Check if this is an AMD GPU by looking for amdgpu directory
if !Path::new(&format!("{}/driver/module/drivers/pci:amdgpu", device_path)).exists() {
continue;
}
// Check if this is an AMD GPU by looking for amdgpu directory
if !device_path
.join("driver/module/drivers/pci:amdgpu")
.exists()
{
continue;
}
// match device_id from Vulkan info
let this_device_id = fs::read_to_string(format!("{}/device", device_path))
.map(|s| u32::from_str_radix(s.trim(), 16).unwrap_or(0))
.unwrap_or(0);
if this_device_id != device_id {
continue;
}
// match device_id from Vulkan info
let this_device_id_str = fs::read_to_string(device_path.join("device"))?;
let this_device_id = u32::from_str_radix(
this_device_id_str
.strip_prefix("0x")
.unwrap_or(&this_device_id_str)
.trim(),
16,
)?;
if this_device_id != device_id {
continue;
}
let read_mem = |path: &str| -> u64 {
fs::read_to_string(path)
.map(|content| content.trim().parse::<u64>().unwrap_or(0))
.unwrap_or(0)
/ 1024
/ 1024 // Convert bytes to MiB
};
return GpuUsage {
uuid: self.uuid.clone(),
total_memory: read_mem(&format!("{}/mem_info_vram_total", device_path)),
used_memory: read_mem(&format!("{}/mem_info_vram_used", device_path)),
};
let read_mem = |path: &Path| -> u64 {
fs::read_to_string(path)
.map(|content| content.trim().parse::<u64>().unwrap_or(0))
.unwrap_or(0)
/ 1024
/ 1024 // Convert bytes to MiB
};
return Ok(GpuUsage {
uuid: self.uuid.clone(),
total_memory: read_mem(&device_path.join("mem_info_vram_total")),
used_memory: read_mem(&device_path.join("mem_info_vram_used")),
});
}
Err(format!("GPU not found").into())
};
match closure() {
Ok(usage) => usage,
Err(e) => {
log::error!(
"Failed to get memory usage for AMD GPU {:#x}: {}",
device_id,
e
);
self.get_usage_unsupported()
}
}
self.get_usage_unsupported()
}
#[cfg(target_os = "windows")]

View File

@ -28,21 +28,10 @@ impl CpuStaticInfo {
.unwrap_or("unknown")
.to_string();
// cortex only returns amd64, arm64, or Unsupported
// TODO: find how Jan uses this value, if we can use
// std::env::consts::ARCH directly
let arch = match std::env::consts::ARCH {
"x86" => "amd64",
"x86_64" => "amd64",
"arm" => "arm64",
"aarch64" => "arm64",
_ => "Unsupported",
};
CpuStaticInfo {
name,
core_count: System::physical_core_count().unwrap_or(0),
arch: arch.to_string(),
arch: std::env::consts::ARCH.to_string(),
extensions: CpuStaticInfo::get_extensions(),
}
}
@ -220,7 +209,8 @@ impl GpuInfo {
#[derive(serde::Serialize, Clone, Debug)]
pub struct SystemInfo {
cpu: CpuStaticInfo,
os: String,
os_type: String,
os_name: String,
total_memory: u64,
gpus: Vec<GpuInfo>,
}
@ -293,9 +283,21 @@ pub fn get_system_info<R: tauri::Runtime>(app: tauri::AppHandle<R>) -> SystemInf
}
}
let os_type = if cfg!(target_os = "windows") {
"windows"
} else if cfg!(target_os = "macos") {
"macos"
} else if cfg!(target_os = "linux") {
"linux"
} else {
"unknown"
};
let os_name = System::long_os_version().unwrap_or("Unknown".to_string());
SystemInfo {
cpu: CpuStaticInfo::new(),
os: System::long_os_version().unwrap_or("Unknown".to_string()),
os_type: os_type.to_string(),
os_name,
total_memory: system.total_memory() / 1024 / 1024, // bytes to MiB
gpus: gpu_map.into_values().collect(),
}

View File

@ -10,9 +10,28 @@ pub struct NvidiaInfo {
pub compute_capability: String,
}
// NvmlError doesn't implement Copy, so we have to store an Option in OnceLock
fn get_nvml() -> Option<&'static Nvml> {
NVML.get_or_init(|| Nvml::init().ok()).as_ref()
NVML.get_or_init(|| {
let result = Nvml::init().or_else(|e| {
// fallback
if cfg!(target_os = "linux") {
let lib_path = std::ffi::OsStr::new("libnvidia-ml.so.1");
Nvml::builder().lib_path(lib_path).init()
} else {
Err(e)
}
});
// NvmlError doesn't implement Copy, so we have to store an Option in OnceLock
match result {
Ok(nvml) => Some(nvml),
Err(e) => {
log::error!("Unable to initialize NVML: {}", e);
None
}
}
})
.as_ref()
}
impl GpuInfo {