Skip to content

[Backend] Redesign HardwareMonitorUpdate event payload for multi-GPU #1298

@shm11C3

Description

@shm11C3

Parent: #1296
Depends on: #1297

Problem

HardwareMonitorUpdate has flat, single-GPU fields:

pub struct HardwareMonitorUpdate {
    pub gpu_usage: Option<f32>,
    pub gpu_name: Option<String>,
    pub gpu_temperature: Option<f32>,
    pub gpu_source: Option<String>,
    pub gpu_dedicated_memory_usage_kb: Option<f32>,
    pub gpu_cooler_level: Option<u32>,
    // ...
}

emit_hardware_update() in system_monitor.rs picks only gpu_samples.first(), discarding all other GPUs even though sample_gpu() already returns a Vec<GpuSample> with per-GPU data.

Proposed Changes

1. Add GpuMonitorData struct (models/hardware.rs)

#[derive(Debug, Clone, serde::Serialize, specta::Type)]
#[serde(rename_all = "camelCase")]
pub struct GpuMonitorData {
    pub gpu_id: String,
    pub gpu_name: String,
    pub gpu_usage: Option<f32>,
    pub gpu_temperature: Option<f32>,
    pub gpu_source: String,
    pub gpu_dedicated_memory_usage_kb: Option<f32>,
    pub gpu_cooler_level: Option<u32>,
}

2. Replace flat GPU fields in HardwareMonitorUpdate

pub struct HardwareMonitorUpdate {
    pub cpu_usage: f32,
    pub memory_usage: f32,
    pub gpus: Vec<GpuMonitorData>,    // replaces 6 flat fields
    pub processors_usage: Vec<f32>,
}

3. Rewrite emit_hardware_update() (system_monitor.rs)

  • Iterate over all gpu_samples instead of picking .first()
  • Build Vec<GpuMonitorData> from the full slice
  • Apply temperature unit conversion per GPU
  • Remove GpuCapabilities struct (the Option fields communicate availability implicitly)

4. Add gpu_id to GpuSample (monitoring_service.rs)

Add a gpu_id: String field to GpuSample. Convention:

  • Windows: "pci:{bus}:{device}.{function}" (from ADL BDF)
  • Linux: "pci:{bus}:{device}.{function}" (from sysfs symlink)
  • macOS: derived from GPU name (typically single GPU on Apple Silicon)

Update update_gpu_histories() to key on gpu_id instead of name for reliability.

5. Database migration

Add optional gpu_id column to GPU_DATA_ARCHIVE:

ALTER TABLE GPU_DATA_ARCHIVE ADD COLUMN gpu_id TEXT;

Existing rows retain NULL for gpu_id. New rows populate both fields. Frontend queries by gpu_name continue to work.

6. Clean up dead code

  • Remove HardwareMonitorState.gpu_history (VecDeque<f32>) — never populated by sample_gpu(), always returns empty
  • Fix get_gpu_usage_history command to read from gpu_usage_histories keyed by GPU

Affected Files

  • src-tauri/src/models/hardware.rs — new GpuMonitorData, redesign HardwareMonitorUpdate, remove dead gpu_history
  • src-tauri/src/workers/system_monitor.rs — rewrite emit_hardware_update(), remove GpuCapabilities
  • src-tauri/src/services/monitoring_service.rs — add gpu_id to GpuSample, update update_gpu_histories()
  • src-tauri/src/commands/hardware.rs — fix get_gpu_usage_history to read from per-GPU histories
  • src-tauri/src/infrastructure/database/migration.rs — add migration for gpu_id column
  • src-tauri/src/infrastructure/database/gpu_archive.rs — bind gpu_id on insert

Note

This is a breaking change to the event payload shape. bindings.ts will regenerate via tauri-specta, producing TypeScript compile errors in the frontend that guide the required frontend updates (#TBD).

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions