Update ui to show DGX spark gpu usage correctly

This commit is contained in:
Jaret Burkett committed 2026-09-24 17:55:11 -06:00
1 parent 60ca869b38
commit 5aa3d0c9a8
3 files changed
+34 -4

No files matched your search

+1 -1
View File
@@ -61,7 +61,7 @@ export default function GPUWidget({ gpu }: GPUWidgetProps) {
</div>
<div className="flex items-center space-x-2 mb-1 mt-3">
<HardDrive className="w-4 h-4 text-blue-600 dark:text-blue-400" />
<p className="text-xs text-gray-400">Memory</p>
<p className="text-xs text-gray-400">{gpu.memory.shared ? 'Shared Memory' : 'Memory'}</p>
<span className="text-xs text-gray-300 ml-auto">
{((gpu.memory.used / gpu.memory.total) * 100).toFixed(1)}%
</span>
+31 -3
View File
@@ -35,6 +35,13 @@ const NV_BATCH_FLUSH_MS = 100;
// Temperature refresh is decoupled from the tick (see refreshCpuTemp)
const CPU_TEMP_REFRESH_MS = 5000;
// Power limits for GPUs whose driver reports none (nvidia-smi gives [N/A]).
// GB10 (DGX Spark) is a unified SoC with no settable GPU limit; 140 W is
// NVIDIA's rated TDP for the GB10 superchip.
const KNOWN_POWER_LIMITS_W: Record<string, number> = {
'NVIDIA GB10': 140,
};
function parseGpuLine(line: string): GpuInfo | null {
const [
index,
@@ -69,7 +76,7 @@ function parseGpuLine(line: string): GpuInfo | null {
},
power: {
draw: parseFloat(powerDraw),
limit: parseFloat(powerLimit),
limit: isNaN(parseFloat(powerLimit)) ? (KNOWN_POWER_LIMITS_W[name] ?? NaN) : parseFloat(powerLimit),
},
clocks: {
graphics: parseInt(clockGraphics),
@@ -81,6 +88,23 @@ function parseGpuLine(line: string): GpuInfo | null {
};
}
/**
* Unified-memory GPUs (GB10 / DGX Spark) have no dedicated VRAM, so
* nvidia-smi reports memory as [N/A]. Report the system RAM pool they share
* instead, like the Mac path does for Apple silicon.
*/
function withSharedMemory(gpu: GPUApiResponse, cpu: CpuInfo | null): GPUApiResponse {
if (!cpu || !gpu.gpus.some(g => isNaN(g.memory.total))) return gpu;
const total = Math.round(cpu.totalMemory);
const free = Math.round(cpu.availableMemory);
return {
...gpu,
gpus: gpu.gpus.map(g =>
isNaN(g.memory.total) ? { ...g, memory: { total, free, used: total - free, shared: true } } : g,
),
};
}
// Serialized once per tick and shared, so N subscribers don't stringify N times
type Subscriber = (sample: MonitorSample, serialized: string) => void;
@@ -138,7 +162,7 @@ class SystemMonitor {
return {
t: Date.now(),
cpu: this.latestCpu,
gpu: this.latestGpu,
gpu: withSharedMemory(this.latestGpu, this.latestCpu),
history: [...this.history],
};
}
@@ -175,7 +199,11 @@ class SystemMonitor {
console.error('Monitor: GPU sample failed:', error);
}
const sample: MonitorSample = { t, cpu: this.latestCpu, gpu: this.latestGpu };
const sample: MonitorSample = {
t,
cpu: this.latestCpu,
gpu: withSharedMemory(this.latestGpu, this.latestCpu),
};
this.history.push(historyPointFromSample(sample));
if (this.history.length > MONITOR_HISTORY_LENGTH) {
this.history.splice(0, this.history.length - MONITOR_HISTORY_LENGTH);
+2
View File
@@ -11,6 +11,8 @@ export interface GpuMemory {
total: number;
free: number;
used: number;
// unified memory (e.g. GB10): figures are the system RAM pool the GPU shares
shared?: boolean;
}
export interface GpuPower {