use std::time::Instant;
#[derive(Debug, Clone)]
pub struct GpuInfo {
pub id: usize,
pub backend_index: u32,
pub name: String,
pub uuid: Option<String>,
}
#[derive(Debug, Clone)]
pub struct GpuSample {
pub gpu_id: usize,
pub at: Instant,
pub gpu_util_percent: Option<f64>,
pub mem_util_percent: Option<f64>,
pub vram_used_bytes: Option<u64>,
pub vram_total_bytes: Option<u64>,
pub power_watts: Option<f64>,
pub power_limit_watts: Option<f64>,
pub temperature_celsius: Option<f64>,
pub fan_percent: Option<f64>,
pub graphics_clock_mhz: Option<f64>,
pub memory_clock_mhz: Option<f64>,
pub compute_processes: Option<u32>,
pub processes: Vec<GpuProcess>,
}
impl GpuSample {
pub fn vram_used_percent(&self) -> Option<f64> {
let used = self.vram_used_bytes? as f64;
let total = self.vram_total_bytes? as f64;
(total > 0.0).then_some((used / total) * 100.0)
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum GpuProcessKind {
Compute,
Graphics,
Mps,
}
impl GpuProcessKind {
pub fn label(self) -> &'static str {
match self {
Self::Compute => "C",
Self::Graphics => "G",
Self::Mps => "MPS",
}
}
}
#[derive(Debug, Clone)]
pub struct GpuProcess {
pub pid: u32,
pub user: Option<String>,
pub command: Option<String>,
pub kinds: Vec<GpuProcessKind>,
pub used_gpu_memory_bytes: Option<u64>,
pub gpu_instance_id: Option<u32>,
pub compute_instance_id: Option<u32>,
}
impl GpuProcess {
pub fn kind_label(&self) -> String {
self.kinds
.iter()
.map(|kind| kind.label())
.collect::<Vec<_>>()
.join("+")
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum MetricKind {
GpuUtil,
MemUtil,
VramUsed,
Power,
Temperature,
Fan,
}
impl MetricKind {
pub const ALL: [Self; 6] = [
Self::GpuUtil,
Self::MemUtil,
Self::VramUsed,
Self::Power,
Self::Temperature,
Self::Fan,
];
pub fn title(self) -> &'static str {
match self {
Self::GpuUtil => "GPU",
Self::MemUtil => "MEM",
Self::VramUsed => "VRAM",
Self::Power => "POWER",
Self::Temperature => "TEMP",
Self::Fan => "FAN",
}
}
pub fn unit(self) -> &'static str {
match self {
Self::GpuUtil | Self::MemUtil | Self::VramUsed | Self::Fan => "%",
Self::Power => "W",
Self::Temperature => "C",
}
}
pub fn value(self, sample: &GpuSample) -> Option<f64> {
match self {
Self::GpuUtil => sample.gpu_util_percent,
Self::MemUtil => sample.mem_util_percent,
Self::VramUsed => sample.vram_used_percent(),
Self::Power => sample.power_watts,
Self::Temperature => sample.temperature_celsius,
Self::Fan => sample.fan_percent,
}
}
pub fn fixed_range(self, latest: Option<&GpuSample>) -> Option<(f64, f64)> {
match self {
Self::GpuUtil | Self::MemUtil | Self::VramUsed | Self::Fan => Some((0.0, 100.0)),
Self::Temperature => Some((0.0, 100.0)),
Self::Power => latest
.and_then(|sample| sample.power_limit_watts)
.map(|limit| (0.0, limit.max(1.0))),
}
}
}