fix(sat): fan check uses hottest GPU load + IPMI-hang-proof polling
- GPU load switches from bee-gpu-burn (compute burn, ~88% TDP) to dcgmproftester -t 1004 / targeted_power via resolveBenchmarkPowerLoadCommand — the same engine Power/Thermal Fit uses and the hottest sustained NVIDIA load we have, so fans are actually pushed toward their ceiling. - Sample loop is now IPMI-hang-proof: every ipmitool read is time-boxed in an abandonable goroutine, and the poll interval backs off geometrically (1s→30s) when reads are slow, tightening again on recovery. A plateau is only trusted while telemetry is healthy; degraded runs ride out to MaxLoadSec. Summary gains fan_samples / telemetry_degraded. Drops the per-second nvidia-smi+power+cpu-temp sampling from the hot loop. - Dead code removed: FanStressRow, GPUStressMetric, sampleFanStressRow, sampleGPUStressMetrics, WriteFanStressCSV/WriteFanSensorsCSV, analyzeMaxTemp, sampleSystemPowerResolved. Topology fan tiles: - size encodes the fan's ceiling RPM (its class), not current speed; coloured fill rising from the bottom encodes live duty cycle (current / ceiling), shown only when the ceiling was measured. - glyph spin rate now maps absolute RPM into a human-perceptible band (fanSpinPeriodSec: 2.2s/turn at <=1000 RPM, 0.35s at >=13000). - the "N fans · N OK · tile size ∝ …" caption line is gone. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019VHG21rgTUiR1G3qFHTVmN
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
bb2a501a28
commit
8cb250f3f4
@@ -202,8 +202,9 @@ func TestTopoPageRendersCoolingFansAsFlexRow(t *testing.T) {
|
||||
if !strings.Contains(body, "FAN1 · 4200 RPM") || !strings.Contains(body, "FAN2 · 15000 RPM") {
|
||||
t.Fatalf("topo page missing per-fan RPM tooltips: %s", body)
|
||||
}
|
||||
if !strings.Contains(body, "2 fans") {
|
||||
t.Fatalf("topo page missing fan count caption: %s", body)
|
||||
// No observed ceiling in this test → tiles show no duty fill and say so.
|
||||
if !strings.Contains(body, "ceiling not measured") {
|
||||
t.Fatalf("topo fan tooltip should note the ceiling is unmeasured: %s", body)
|
||||
}
|
||||
|
||||
// Component-detail fallback endpoint must resolve the "fan" type.
|
||||
@@ -217,6 +218,23 @@ func TestTopoPageRendersCoolingFansAsFlexRow(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFanSpinPeriodSec(t *testing.T) {
|
||||
// Clamped at both ends; monotonically faster (smaller period) with RPM.
|
||||
if got := fanSpinPeriodSec(200); got != 2.2 {
|
||||
t.Fatalf("low RPM: got %v want 2.2 (slowest visible)", got)
|
||||
}
|
||||
if got := fanSpinPeriodSec(25000); got != 0.35 {
|
||||
t.Fatalf("high RPM: got %v want 0.35 (fastest visible)", got)
|
||||
}
|
||||
mid := fanSpinPeriodSec(7000)
|
||||
if mid <= 0.35 || mid >= 2.2 {
|
||||
t.Fatalf("mid RPM period %v out of band", mid)
|
||||
}
|
||||
if fanSpinPeriodSec(10000) >= fanSpinPeriodSec(3000) {
|
||||
t.Fatalf("higher RPM must spin faster (shorter period)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTopoPageRendersStorageDisksGroupedByType(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "audit.json")
|
||||
|
||||
Reference in New Issue
Block a user