GPUs: fan speed in % per card (nvidia-smi fan.speed, hwmon pwm1); 0% shows

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-11-14 17:09:10 -08:00
co-authored by Claude Opus 5.5
parent 95bb026b7f
commit afd4688358
5 changed files with 37 additions and 5 deletions
+2 -2
View File
@@ -624,7 +624,7 @@ function GPUBox({ g, values, tick, advance, now, cap }: { g: GPU; values: number
<span className="t-fact" title={g.req_mhz ? `${Math.round(g.req_mhz)} MHz requested${g.max_mhz ? `, ${Math.round(g.max_mhz)} MHz max` : ''}` : undefined}>{Math.round(g.mhz ?? 0)}{g.max_mhz ? ` / ${Math.round(g.max_mhz)}` : ''} MHz</span></div> : null}
{(g.power_w !== undefined && g.power_w > 0) || g.power_cap_w ? <div className="t-row t-sub"><span>Power</span><span className="spacer" />
<span className="t-fact">{(g.power_w ?? 0).toFixed(1)}{g.power_cap_w ? ` / ${Math.round(g.power_cap_w)}` : ''} W</span></div> : null}
{g.fan_rpm ? <div className="t-row t-sub"><span>Fan</span><span className="spacer" /><span className="t-fact">{g.fan_rpm} rpm</span></div> : null}
{g.fan_rpm || g.fan_pct !== undefined ? <div className="t-row t-sub"><span>Fan</span><span className="spacer" /><span className="t-fact">{[g.fan_pct !== undefined ? `${Math.round(g.fan_pct)}%` : '', g.fan_rpm ? `${g.fan_rpm} rpm` : ''].filter(Boolean).join(' · ')}</span></div> : null}
{g.mem_total ? <div className="t-row t-sub"><span>Mem</span><span className="t-pct">{Math.round(((g.mem_used ?? 0) / g.mem_total) * 100)}%</span><Meter pct={((g.mem_used ?? 0) / g.mem_total) * 100} grad="used" /><span className="t-amt">{bytes(g.mem_used ?? 0, 1)}</span></div>
: g.mem_used ? <div className="t-row t-sub"><span>Mem</span><span className="spacer" /><span className="t-fact" title="resident memory of the processes that have it open">{bytes(g.mem_used, 1)}</span></div> : null}
</div>
@@ -645,7 +645,7 @@ function GPUBox({ g, values, tick, advance, now, cap }: { g: GPU; values: number
// Nothing on this GPU can be read — no busy counter, engine, temperature, clock, power, memory,
// nor a process with it open: the Mac's Asahi, today. Its box would be a graph that can never
// draw beside a column of dashes, so it is one line instead. A client opening it brings the box back.
const unmeasured = (g: GPU) => !g.usage_src && !g.engines && !(g.temp && g.temp > 0) && !g.mhz && !g.max_mhz && !g.power_w && !g.power_cap_w && !g.fan_rpm && !g.mem_total && !g.mem_used && g.clients.length === 0
const unmeasured = (g: GPU) => !g.usage_src && !g.engines && !(g.temp && g.temp > 0) && !g.mhz && !g.max_mhz && !g.power_w && !g.power_cap_w && !g.fan_rpm && g.fan_pct === undefined && !g.mem_total && !g.mem_used && g.clients.length === 0
function GPULine({ g }: { g: GPU }) {
return (
<div className="t-row t-gpu-line">
+1 -1
View File
@@ -86,7 +86,7 @@ export interface GPUClient { pid: number; name: string; usage: number; engines?:
export interface GPU {
name: string; driver: string; bus?: string; integrated?: boolean
usage: number; usage_src?: 'idle' | 'busy' | 'clients'; engines?: Record<string, number>
temp?: number; temp_src?: 'gpu' | 'package'; power_w?: number; power_cap_w?: number; fan_rpm?: number
temp?: number; temp_src?: 'gpu' | 'package'; power_w?: number; power_cap_w?: number; fan_rpm?: number; fan_pct?: number
mhz?: number; req_mhz?: number; max_mhz?: number; mem_used?: number; mem_total?: number
clients: GPUClient[]; clients_ok: boolean; stalled?: boolean
}