codec/gpu/types.rs
1//! Core GPU type definitions: `GpuDevice`, `GpuVendor`, `GpuUtilization`.
2
3#[derive(Debug, Clone)]
4pub struct GpuDevice {
5 pub vendor: GpuVendor,
6 pub name: String,
7 /// Global device index across ALL vendors (0-based, in `detect_gpus()`
8 /// order) — what the user addresses via `--decode-gpu N` / the GPU policy.
9 pub index: u32,
10 /// Index of this device WITHIN its own vendor's set (0-based). On a
11 /// single-vendor host this equals `index`; on a mixed host (e.g. NVIDIA +
12 /// AMD iGPU) they differ. The per-vendor hardware decoder/encoder uses THIS
13 /// to pick the physical adapter (CUDA ordinal, QSV/AMF adapter), since those
14 /// SDKs enumerate only their own vendor's devices.
15 pub vendor_index: u32,
16 /// Architecture / generation label, e.g. "Blackwell" (RTX 5060),
17 /// "Ada Lovelace" (RTX 4000-series), "Ampere" (RTX 3000), "Alchemist DG2"
18 /// (Arc A-series), "Battlemage BMG" (Arc B-series), "RDNA3" (RX 7000).
19 /// Phase 2 (2026-05-07) inventory page surface — derived from the PCI
20 /// device id at detect time so the inventory aggregations don't have
21 /// to re-derive it. "Unknown" when the device id falls outside the
22 /// per-vendor known-id table; preserved verbatim to the admin UI so
23 /// operators can spot fleet rows that need a label update.
24 pub generation: String,
25 /// Lowercase `vendor:device` PCI tuple, e.g. `"0x10de:0x2d05"`. Stable
26 /// identifier across driver / kernel versions. Empty string when the
27 /// platform path doesn't expose a device id (NVIDIA via CUDA on
28 /// Windows: cuda doesn't surface PCI; the field stays empty rather
29 /// than synthesise something misleading).
30 pub pci_id: String,
31 /// Total VRAM in MiB. NVIDIA via NVML `memory_info().total`; Intel via
32 /// `/sys/class/drm/cardN/device/mem_info_vram_total` when present;
33 /// AMD same. 0 when the platform path can't read it — admin UI shows
34 /// "—" for that case rather than "0 MiB".
35 pub vram_mib: u64,
36 /// Vendor-reported serial number of the physical card. NVIDIA via
37 /// NVML `Device::serial()` (returns the manufacturer's serial sticker
38 /// for cards that have one — datacenter Tesla / A10G / consumer Pro
39 /// cards expose it; consumer GeForce typically doesn't). Intel /
40 /// AMD: try `/sys/class/drm/cardN/device/serial[_number]` paths;
41 /// usually `None`. Stable identifier for warranty tracking + the
42 /// `transcoder_gpus` asset table — when present, the same card
43 /// across host moves dedups to a single row.
44 pub serial: Option<String>,
45 /// PCI host slot address, e.g. `"04:00.0"`. Used as the dedupe
46 /// fallback when `serial` is absent — assumes the card stays in
47 /// the same slot of the same host (the dev-box reality).
48 /// Empty when the platform path doesn't expose it.
49 pub host_pci_address: String,
50 /// Vendor portion of the PCI tuple as a standalone hex string,
51 /// e.g. `"0x10de"`. Already implicit in `pci_id` but exposed
52 /// separately so the SQL inventory query can index on it
53 /// without parsing.
54 pub vendor_id_hex: String,
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum GpuVendor {
59 Nvidia,
60 Amd,
61 Intel,
62}
63
64/// Per-GPU live utilisation snapshot. Read on every load tick (5 s
65/// cadence) by the Phase 2 (2026-05-07) `worker_load` reporter and
66/// folded into the `WsGpuLeaseEntry` for the wire. NVIDIA values come
67/// from NVML; Intel values come from sysfs `gt_cur_freq_mhz` /
68/// `gt_max_freq_mhz` for a coarse "busy" proxy + `mem_info_vram_*`
69/// for memory; AMD is currently a no-op (returns all zeros) — radeontop
70/// / `amdsmi` integration is the proper fix and is deferred per the
71/// brief's "Phase 1 stand-in for Intel; AMD skipped" guidance.
72#[derive(Debug, Clone, Default)]
73pub struct GpuUtilization {
74 /// 0..=100 compute / overall GPU busy.
75 pub util_percent: u8,
76 /// 0..=100 NVENC ASIC busy (encoder pipeline).
77 pub encoder_percent: u8,
78 /// 0..=100 NVDEC ASIC busy (decoder pipeline).
79 pub decoder_percent: u8,
80 /// VRAM in use (MiB).
81 pub mem_used_mib: u32,
82 /// VRAM total (MiB) — duplicated from the static device record so
83 /// the wire entry is self-contained for the FE bar render.
84 pub mem_total_mib: u32,
85 /// Core temperature in °C; `None` when the platform path doesn't
86 /// expose it.
87 pub temperature_c: Option<u8>,
88}