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 @@

GPU

+

CPU

@@ -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 `
+ +
${tot}%总占用
+
核心${CP.n} 个
+
${bars}
+
每核占用(深色=忙)
`; + })() : 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],