Skip to main content

gpu_histop/backend/
mod.rs

1mod amdgpu;
2mod apple;
3mod nvidia_smi;
4mod nvml;
5
6use anyhow::{Result, anyhow, bail};
7
8use crate::config::BackendChoice;
9use crate::model::{GpuInfo, GpuSample};
10
11pub trait GpuBackend: Send {
12    fn label(&self) -> &str;
13    fn devices(&self) -> &[GpuInfo];
14    fn sample(&mut self) -> Result<Vec<GpuSample>>;
15}
16
17pub fn create_backend(kind: BackendChoice) -> Result<Box<dyn GpuBackend>> {
18    match kind {
19        BackendChoice::Auto => create_auto_backend(),
20        BackendChoice::Nvml => Ok(Box::new(nvml::NvmlBackend::new()?)),
21        BackendChoice::NvidiaSmi => Ok(Box::new(nvidia_smi::NvidiaSmiBackend::new()?)),
22        BackendChoice::Amdgpu => Ok(Box::new(amdgpu::AmdGpuBackend::new()?)),
23        BackendChoice::Apple => Ok(Box::new(apple::AppleBackend::new()?)),
24    }
25}
26
27fn create_auto_backend() -> Result<Box<dyn GpuBackend>> {
28    if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
29        return apple::AppleBackend::new()
30            .map(|backend| Box::new(backend) as Box<dyn GpuBackend>)
31            .map_err(|error| {
32                anyhow!("no real GPU metrics backend is available on Apple Silicon: {error:#}")
33            });
34    }
35
36    let mut errors = Vec::new();
37
38    match nvml::NvmlBackend::new() {
39        Ok(backend) => return Ok(Box::new(backend)),
40        Err(error) => errors.push(format!("NVML: {error:#}")),
41    }
42
43    match nvidia_smi::NvidiaSmiBackend::new() {
44        Ok(backend) => return Ok(Box::new(backend)),
45        Err(error) => errors.push(format!("nvidia-smi: {error:#}")),
46    }
47
48    match amdgpu::AmdGpuBackend::new() {
49        Ok(backend) => return Ok(Box::new(backend)),
50        Err(error) => errors.push(format!("AMDGPU sysfs: {error:#}")),
51    }
52
53    match apple::AppleBackend::new() {
54        Ok(backend) => return Ok(Box::new(backend)),
55        Err(error) => errors.push(format!("Apple Silicon: {error:#}")),
56    }
57
58    Err(anyhow!(
59        "no real GPU metrics backend is available; tried {}",
60        errors.join("; ")
61    ))
62}
63
64fn require_devices(devices: &[GpuInfo], backend: &str) -> Result<()> {
65    if devices.is_empty() {
66        bail!("{backend} reported no GPUs");
67    }
68    Ok(())
69}