feat(monitor): 网页加 CPU 占用卡(总占用环 + 28 核逐核条),psutil 采样缓存 1 秒;顺便重启控制台让之前的补量进度口径与停止补杀生效
This commit is contained in:
@@ -172,6 +172,7 @@
|
||||
<section class="hero">
|
||||
<div class="card" id="pipe"></div>
|
||||
<div class="card"><h2><span>GPU</span><span class="r" id="gputime"></span></h2><div id="gpu"></div></div>
|
||||
<div class="card"><h2><span>CPU</span><span class="r" id="cputime"></span></h2><div id="cpu"></div></div>
|
||||
</section>
|
||||
|
||||
<section class="card" id="prog"></section>
|
||||
@@ -549,6 +550,20 @@ function renderStatus(s) {
|
||||
<div class="gname">${g.name}</div>`;
|
||||
}).join('<hr style="border:none;border-top:1px solid var(--line);margin:14px 0">') : 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) => `<div title="核 ${i + 1}: ${v}%" style="flex:1;min-width:0;height:100%;background:${v > 85 ? css('--bad') : v > 60 ? css('--warn') : css('--accent2')};opacity:${0.25 + 0.75 * Math.min(1, v / 100)}"></div>`).join('');
|
||||
return `<div class="gpuwrap"><div class="ring"><svg width="116" height="116"><circle cx="58" cy="58" r="50" stroke="#1b2433" stroke-width="10" fill="none"/>
|
||||
<circle cx="58" cy="58" r="50" stroke="${col}" stroke-width="10" fill="none" stroke-linecap="round" stroke-dasharray="${C}" stroke-dashoffset="${C * (1 - tot / 100)}" style="transition:stroke-dashoffset .6s"/></svg>
|
||||
<div class="c"><div><b>${tot}%</b><span>总占用</span></div></div></div>
|
||||
<div class="gpurows"><div class="gr"><div class="l"><span>核心</span><b>${CP.n} 个</b></div><div class="mini"><div style="width:${Math.min(100, tot)}%;background:${col}"></div></div></div>
|
||||
<div style="display:flex;gap:2px;height:26px;margin-top:6px">${bars}</div></div></div>
|
||||
<div class="gname">每核占用(深色=忙)</div>`;
|
||||
})() : empty('没装 psutil,无法读 CPU');
|
||||
|
||||
// 数据
|
||||
const D = s.data || {}, st = D.stats, ix = D.index;
|
||||
const row = (k, v, cls = '') => `<tr><td>${k}</td><td class="n ${cls}">${v}</td></tr>`;
|
||||
|
||||
+18
-1
@@ -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],
|
||||
|
||||
Reference in New Issue
Block a user