From 9ed213417b978366d8dea0d05e146282f5db2bde Mon Sep 17 00:00:00 2001
From: cbb <2625274797@qq.com>
Date: Sun, 18 Oct 2026 13:57:48 +0800
Subject: [PATCH] =?UTF-8?q?feat(monitor):=20=E7=BD=91=E9=A1=B5=E5=8A=A0=20?=
=?UTF-8?q?CPU=20=E5=8D=A0=E7=94=A8=E5=8D=A1=EF=BC=88=E6=80=BB=E5=8D=A0?=
=?UTF-8?q?=E7=94=A8=E7=8E=AF=20+=2028=20=E6=A0=B8=E9=80=90=E6=A0=B8?=
=?UTF-8?q?=E6=9D=A1=EF=BC=89=EF=BC=8Cpsutil=20=E9=87=87=E6=A0=B7=E7=BC=93?=
=?UTF-8?q?=E5=AD=98=201=20=E7=A7=92=EF=BC=9B=E9=A1=BA=E4=BE=BF=E9=87=8D?=
=?UTF-8?q?=E5=90=AF=E6=8E=A7=E5=88=B6=E5=8F=B0=E8=AE=A9=E4=B9=8B=E5=89=8D?=
=?UTF-8?q?=E7=9A=84=E8=A1=A5=E9=87=8F=E8=BF=9B=E5=BA=A6=E5=8F=A3=E5=BE=84?=
=?UTF-8?q?=E4=B8=8E=E5=81=9C=E6=AD=A2=E8=A1=A5=E6=9D=80=E7=94=9F=E6=95=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
ml/monitor.html | 15 +++++++++++++++
ml/monitor.py | 19 ++++++++++++++++++-
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/ml/monitor.html b/ml/monitor.html
index 3beb255..14ab6d8 100644
--- a/ml/monitor.html
+++ b/ml/monitor.html
@@ -172,6 +172,7 @@
@@ -549,6 +550,20 @@ function renderStatus(s) {
${g.name}
`;
}).join('
') : empty('未检测到 nvidia-smi');
+ // CPU(psutil;没装就整块不显示)
+ const CP = s.cpu || {};
+ $('cputime').textContent = CP.n ? '实时' : '';
+ $('cpu').innerHTML = CP.n ? (() => {
+ const tot = CP.total ?? 0, C = 2 * Math.PI * 50, col = tot > 85 ? css('--bad') : tot > 60 ? css('--warn') : css('--ok');
+ const bars = (CP.per || []).map((v, i) => ``).join('');
+ return `
+ 每核占用(深色=忙)
`;
+ })() : empty('没装 psutil,无法读 CPU');
+
// 数据
const D = s.data || {}, st = D.stats, ix = D.index;
const row = (k, v, cls = '') => `| ${k} | ${v} |
`;
diff --git a/ml/monitor.py b/ml/monitor.py
index e8890b7..b021b4b 100644
--- a/ml/monitor.py
+++ b/ml/monitor.py
@@ -68,6 +68,23 @@ def read_log(name, offset):
return {'records': recs, 'offset': offset + end, 'size': size, 'reset': offset == 0, 'mtime': os.path.getmtime(f)}
+_CPU_CACHE = {'t': 0.0, 'v': {}}
+
+
+def cpu():
+ """CPU 占用:总百分比 + 每核(psutil 已装;没装就返回空,页面不显示这块)。"""
+ if time.time() - _CPU_CACHE['t'] < 1.0: return _CPU_CACHE['v']
+ try:
+ import psutil
+ per = psutil.cpu_percent(interval=None, percpu=True)
+ out = {'total': round(sum(per) / max(1, len(per)), 1), 'per': [round(x, 0) for x in per], 'n': len(per),
+ 'load1': round(os.getloadavg()[0], 2) if hasattr(os, 'getloadavg') else None}
+ except Exception:
+ out = {}
+ _CPU_CACHE.update(t=time.time(), v=out)
+ return out
+
+
_GPU_CACHE = {'t': 0.0, 'v': []}
@@ -203,7 +220,7 @@ def status():
pb = jload(P(RUNS, 'policy_bench.json'))
if pb: pb = {k: {kk: v.get(kk) for kk in ('n', 'ok', 'reached', 'collisionFrames', 'brakeRate', 'recoveryRate', 'livelock', 'inferMsP99', 'safetyMsP99')}
for k, v in pb.items() if isinstance(v, dict) and 'n' in v}
- return {'now': time.time(), 'gpu': gpu(),
+ return {'now': time.time(), 'gpu': gpu(), 'cpu': cpu(),
'vram_budget_gb': float(os.environ.get('VRAM_BUDGET_GB', 20)), # 本机桌面常驻占 4–5 GB,给训练的预算 19–20 GB
'pipeline': pl, 'check': CHECK.get(), 'lock': lock_info(), # 2026-10-18 第八轮修:上一版这三项被行尾注释吞掉,网页步骤条/锁状态拿不到
'stage_meta': [{'id': k, 'name': n, 'est_h': h, 'timeout_h': pstate.TIMEOUT_H[k]} for k, n, h in pstate.STAGES],