From c80a39e7acaf4bb33883cb2c8069957180a92c23 Mon Sep 17 00:00:00 2001 From: Michael Chus Date: Wed, 15 Apr 2026 07:16:18 +0300 Subject: [PATCH] Add power results table, fix benchmark results refresh, bound memtester - Benchmark page now shows two result sections: Performance (scores) and Power / Thermal Fit (slot table). After any benchmark task completes the results section auto-refreshes via GET /api/benchmark/results without a full page reload. - Power results table shows each GPU slot with nominal TDP, achieved stable power limit, and P95 observed power. Rows with derated cards are highlighted amber so under-performing slots stand out at a glance. Older runs are collapsed in a
summary. - memtester is now wrapped with timeout(1) so a stuck memory controller cannot cause Validate Memory to hang indefinitely. Wall-clock limit is ~2.5 min per 100 MB per pass plus a 2-minute buffer. Co-Authored-By: Claude Sonnet 4.6 --- audit/internal/platform/sat.go | 6 +- audit/internal/webui/api.go | 5 ++ audit/internal/webui/pages.go | 142 ++++++++++++++++++++++++++++++++- audit/internal/webui/server.go | 1 + 4 files changed, 149 insertions(+), 5 deletions(-) diff --git a/audit/internal/platform/sat.go b/audit/internal/platform/sat.go index 41ebb89..2be426b 100644 --- a/audit/internal/platform/sat.go +++ b/audit/internal/platform/sat.go @@ -552,9 +552,13 @@ func (s *System) RunMemoryAcceptancePack(ctx context.Context, baseDir string, si if passes <= 0 { passes = 1 } + // Bound memtester with a hard wall-clock timeout: ~2.5 min per 100 MB per + // pass, plus a fixed 2-minute buffer. Without this, a stuck memory + // controller can cause memtester to spin forever on a single subtest. + timeoutSec := sizeMB*passes*150/100 + 120 return runAcceptancePackCtx(ctx, baseDir, "memory", []satJob{ {name: "01-free-before.log", cmd: []string{"free", "-h"}}, - {name: "02-memtester.log", cmd: []string{"memtester", fmt.Sprintf("%dM", sizeMB), fmt.Sprintf("%d", passes)}}, + {name: "02-memtester.log", cmd: []string{"timeout", fmt.Sprintf("%d", timeoutSec), "memtester", fmt.Sprintf("%dM", sizeMB), fmt.Sprintf("%d", passes)}}, {name: "03-free-after.log", cmd: []string{"free", "-h"}}, }, logFunc) } diff --git a/audit/internal/webui/api.go b/audit/internal/webui/api.go index 3ea975e..e756a46 100644 --- a/audit/internal/webui/api.go +++ b/audit/internal/webui/api.go @@ -1529,6 +1529,11 @@ func (h *handler) handleAPINetworkRollback(w http.ResponseWriter, _ *http.Reques writeJSON(w, map[string]string{"status": "rolled back"}) } +func (h *handler) handleAPIBenchmarkResults(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + fmt.Fprint(w, renderBenchmarkResultsCard(h.opts.ExportDir)) +} + func (h *handler) rollbackPendingNetworkChange() error { h.pendingNetMu.Lock() pnc := h.pendingNet diff --git a/audit/internal/webui/pages.go b/audit/internal/webui/pages.go index b6bc7dd..173796c 100644 --- a/audit/internal/webui/pages.go +++ b/audit/internal/webui/pages.go @@ -2002,7 +2002,7 @@ func renderBenchmark(opts HandlerOptions) string { -` + renderBenchmarkResultsCard(opts.ExportDir) + ` +`+`
`+renderBenchmarkResultsCard(opts.ExportDir)+`
`+`