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
@@ -76,7 +76,7 @@ Generic engineering rules live in `bible/rules/patterns/`.
|
||||
- GPU bandwidth check
|
||||
- `dcgmi diag -r nvbandwidth` (per CPU socket, then all selected GPUs, on multi-socket systems -- see `decisions/2026-07-27-nvbandwidth-per-socket-split.md`)
|
||||
- Fan ceiling check (Load tier / `3. Load` only)
|
||||
- `stressapptest` (or `stress-ng`) + `bee-gpu-burn` / `rvs gst` at 100%, run simultaneously
|
||||
- `ipmitool sdr type Fan` sampled 1 Hz until every fan plateaus (~1 min flat) or the 15 min cap
|
||||
- records each fan's observed peak RPM to `/var/log/bee-sat/fan-observation.json` (used by the Topology fan tiles); FAIL only on a fan at 0 RPM / IPMI cr-nr under load; **cancelled ("not applicable")**, never failed, if the host cannot be loaded or has no fan sensors
|
||||
- `stressapptest` (or `stress-ng`) + the hottest GPU load — `dcgmproftester -t 1004` / `targeted_power` (Power/Thermal Fit engine), **not** `bee-gpu-burn` — run simultaneously
|
||||
- `ipmitool sdr type Fan` on an adaptive interval (1 s floor, backs off to 30 s when the BMC gets slow, every read time-boxed) until every fan plateaus (~1 min flat, only trusted while telemetry is healthy) or the 15 min cap
|
||||
- records each fan's observed peak RPM to the fan-observation store (used by the Topology fan tiles: size ∝ ceiling, fill ∝ duty cycle); FAIL only on a fan at 0 RPM / IPMI cr-nr under load; **cancelled ("not applicable")**, never failed, if the host cannot be loaded or has no fan sensors
|
||||
- see `decisions/2026-09-04-fan-ceiling-check.md`
|
||||
|
||||
@@ -29,14 +29,30 @@ resulting RPM — does not work on our current platform:
|
||||
The `fan` SAT test (`platform.RunFanCheck`, formerly the unwired
|
||||
`RunFanStressTest`) drives load, not the BMC:
|
||||
|
||||
1. Start `stressapptest` (CPU + memory) and, when a GPU is present, a GPU burn
|
||||
(`bee-gpu-burn` / `rvs gst`) **simultaneously**, each in its own goroutine.
|
||||
1. Start `stressapptest` (CPU + memory) and, when a GPU is present, the
|
||||
**hottest sustained GPU load** — `dcgmproftester -t 1004` /
|
||||
`targeted_power`, via `resolveBenchmarkPowerLoadCommand`, the same engine
|
||||
Power/Thermal Fit uses — **simultaneously**, each in its own goroutine.
|
||||
NOT `bee-gpu-burn`: that is a compute-throughput burn that tops out around
|
||||
88% of TDP (measured ~525 W of 600 W on RTX PRO 6000 Blackwell) and never
|
||||
makes the fans demand their true ceiling. A first run on the MSI stand with
|
||||
`bee-gpu-burn` peaked F2U fans at 24 400 RPM vs a historical 26 000.
|
||||
A missing GPU is not an error — CPU/memory load alone exercises the cooling
|
||||
loop. Load sources reach full power at different times, so the plateau clock
|
||||
only starts once every launched source reports its process running (plus a
|
||||
fixed GPU ramp grace).
|
||||
2. Sample every fan once a second. Per fan, track the peak RPM and the last time
|
||||
it climbed by more than `PlateauDeltaRPM` (default 50).
|
||||
2. Sample every fan on an adaptive interval (floor 1 s). Each read is
|
||||
time-boxed (`readFansBounded` — a goroutine abandoned on timeout, so a
|
||||
KCS-wedged `ipmitool` can never block the loop); when reads are slow the
|
||||
interval backs off geometrically to 30 s and tightens again when they
|
||||
recover. Under 8-GPU + CPU load on the MSI stand, `ipmitool sdr type Fan`
|
||||
took ~14 s/call and at one point wedged for minutes — without this the
|
||||
"1 Hz" sampler silently degraded to one sample per 14 s and the plateau
|
||||
timer ran on stale data. A plateau is only declared while telemetry is
|
||||
healthy (interval near the floor, ≥5 recent samples); a degraded run just
|
||||
rides out to `MaxLoadSec` and records the peak it saw. Per fan, track the
|
||||
peak RPM and the last time it climbed by more than `PlateauDeltaRPM`
|
||||
(default 50).
|
||||
3. When no fan has climbed for `PlateauHoldSec` (default 60 s) and at least one
|
||||
fan rose meaningfully above baseline, declare the ceiling found and stop —
|
||||
**success**. `MaxLoadSec` (default 900 s) is a hard cap; hitting it is also
|
||||
|
||||
Reference in New Issue
Block a user