Skip to main content

gpu_histop/
model.rs

1use std::time::Instant;
2
3#[derive(Debug, Clone)]
4pub struct GpuInfo {
5    pub id: usize,
6    pub backend_index: u32,
7    pub name: String,
8    pub uuid: Option<String>,
9}
10
11#[derive(Debug, Clone)]
12pub struct GpuSample {
13    pub gpu_id: usize,
14    pub at: Instant,
15    pub gpu_util_percent: Option<f64>,
16    pub mem_util_percent: Option<f64>,
17    pub vram_used_bytes: Option<u64>,
18    pub vram_total_bytes: Option<u64>,
19    pub power_watts: Option<f64>,
20    pub power_limit_watts: Option<f64>,
21    pub temperature_celsius: Option<f64>,
22    pub fan_percent: Option<f64>,
23    pub graphics_clock_mhz: Option<f64>,
24    pub memory_clock_mhz: Option<f64>,
25    pub compute_processes: Option<u32>,
26    pub processes: Vec<GpuProcess>,
27}
28
29impl GpuSample {
30    pub fn vram_used_percent(&self) -> Option<f64> {
31        let used = self.vram_used_bytes? as f64;
32        let total = self.vram_total_bytes? as f64;
33        (total > 0.0).then_some((used / total) * 100.0)
34    }
35}
36
37#[derive(Debug, Clone, Copy, Eq, PartialEq)]
38pub enum GpuProcessKind {
39    Compute,
40    Graphics,
41    Mps,
42}
43
44impl GpuProcessKind {
45    pub fn label(self) -> &'static str {
46        match self {
47            Self::Compute => "C",
48            Self::Graphics => "G",
49            Self::Mps => "MPS",
50        }
51    }
52}
53
54#[derive(Debug, Clone)]
55pub struct GpuProcess {
56    pub pid: u32,
57    pub user: Option<String>,
58    pub command: Option<String>,
59    pub kinds: Vec<GpuProcessKind>,
60    pub used_gpu_memory_bytes: Option<u64>,
61    pub gpu_instance_id: Option<u32>,
62    pub compute_instance_id: Option<u32>,
63}
64
65impl GpuProcess {
66    pub fn kind_label(&self) -> String {
67        self.kinds
68            .iter()
69            .map(|kind| kind.label())
70            .collect::<Vec<_>>()
71            .join("+")
72    }
73}
74
75#[derive(Debug, Clone, Copy, Eq, PartialEq)]
76pub enum MetricKind {
77    GpuUtil,
78    MemUtil,
79    VramUsed,
80    Power,
81    Temperature,
82    Fan,
83}
84
85impl MetricKind {
86    pub const ALL: [Self; 6] = [
87        Self::GpuUtil,
88        Self::MemUtil,
89        Self::VramUsed,
90        Self::Power,
91        Self::Temperature,
92        Self::Fan,
93    ];
94
95    pub fn title(self) -> &'static str {
96        match self {
97            Self::GpuUtil => "GPU",
98            Self::MemUtil => "MEM",
99            Self::VramUsed => "VRAM",
100            Self::Power => "POWER",
101            Self::Temperature => "TEMP",
102            Self::Fan => "FAN",
103        }
104    }
105
106    pub fn unit(self) -> &'static str {
107        match self {
108            Self::GpuUtil | Self::MemUtil | Self::VramUsed | Self::Fan => "%",
109            Self::Power => "W",
110            Self::Temperature => "C",
111        }
112    }
113
114    pub fn value(self, sample: &GpuSample) -> Option<f64> {
115        match self {
116            Self::GpuUtil => sample.gpu_util_percent,
117            Self::MemUtil => sample.mem_util_percent,
118            Self::VramUsed => sample.vram_used_percent(),
119            Self::Power => sample.power_watts,
120            Self::Temperature => sample.temperature_celsius,
121            Self::Fan => sample.fan_percent,
122        }
123    }
124
125    pub fn fixed_range(self, latest: Option<&GpuSample>) -> Option<(f64, f64)> {
126        match self {
127            Self::GpuUtil | Self::MemUtil | Self::VramUsed | Self::Fan => Some((0.0, 100.0)),
128            Self::Temperature => Some((0.0, 100.0)),
129            Self::Power => latest
130                .and_then(|sample| sample.power_limit_watts)
131                .map(|limit| (0.0, limit.max(1.0))),
132        }
133    }
134}