From 21ad209747348cca036bafd39d6a509ed3afc785 Mon Sep 17 00:00:00 2001 From: cbb <2625274797@qq.com> Date: Sun, 18 Oct 2026 16:15:44 +0800 Subject: [PATCH] =?UTF-8?q?feat(monitor):=20CPU=20=E5=8D=A1=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=9E=8B=E5=8F=B7=EF=BC=88psutil=20=E5=8F=AA=E7=BB=99?= =?UTF-8?q?=E6=A0=B8=E6=95=B0=EF=BC=8C=E5=9E=8B=E5=8F=B7=E8=B5=B0=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E8=A1=A8=20ProcessorNameString=20/=20Linux=20/proc/cp?= =?UTF-8?q?uinfo=EF=BC=89=EF=BC=8C=E5=8A=A0=E5=9C=A8=E5=8D=A1=E5=BA=95?= =?UTF-8?q?=E4=B8=8E=20GPU=20=E5=90=8C=E5=90=8D=E5=90=8C=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ml/monitor.html | 2 +- ml/monitor.py | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/ml/monitor.html b/ml/monitor.html index 2cfea17..5aa53e3 100644 --- a/ml/monitor.html +++ b/ml/monitor.html @@ -558,7 +558,7 @@ function renderStatus(s) {
${tot}%CPU
${gr('占用', `${tot}% · ${CP.n} 核`, tot, col)}
${bars}
-
每核占用(深色=忙)
`; +
${CP.model || 'CPU'} · 每核占用(深色=忙)
`; })() : ''; $('gpu').innerHTML = (gpuBlk + (gpuBlk && cpuBlk ? hr : '') + cpuBlk) || empty('未检测到 nvidia-smi / psutil'); diff --git a/ml/monitor.py b/ml/monitor.py index c56a21a..c7ff04d 100644 --- a/ml/monitor.py +++ b/ml/monitor.py @@ -17,7 +17,7 @@ N-11 Windows 子进程用 CREATE_NO_WINDOW 自带隐藏控制台:关掉控制台黑窗口训练照跑,重开控制台可接着看、可停止; N-9 生成阶段的行数按文件增量统计(只读新增字节),其他阶段不扫 shard; N-12 停止后的状态改写走 ml.pstate(单一写者、原子替换);N-14 阶段名/估时/权重由 ml.pstate.STAGES 下发。""" -import argparse, glob, json, os, re, shutil, signal, subprocess, sys, threading, time, webbrowser +import argparse, glob, json, os, platform, re, shutil, signal, subprocess, sys, threading, time, webbrowser sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from ml import pstate from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler @@ -71,6 +71,22 @@ def read_log(name, offset): _CPU = {'v': {}} +def cpu_name(): + """CPU 型号:psutil 只有核数,型号得自己读——Windows 在注册表,Linux 在 /proc/cpuinfo。""" + try: + if os.name == 'nt': + import winreg + with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'HARDWARE\DESCRIPTION\System\CentralProcessor\0') as k: + return re.sub(r'\s+', ' ', winreg.QueryValueEx(k, 'ProcessorNameString')[0]).strip() + with open('/proc/cpuinfo') as f: + for ln in f: + if ln.startswith('model name'): + return ln.split(':', 1)[1].strip() + except Exception: + pass + return platform.processor().strip() + + class CpuSampler(threading.Thread): """后台每秒阻塞采样一次 CPU。cpu_percent 是"距上次调用"的差值:放在请求里算,窗口取决于两次 HTTP 请求的间隔(网页 1 秒轮询 + 手动 curl 会把它压成几毫秒,读数恒为 0)——所以单独一个线程按固定 @@ -80,10 +96,11 @@ class CpuSampler(threading.Thread): def run(self): try: import psutil + name = cpu_name() # 型号只读一次,别每秒翻注册表 psutil.cpu_percent(interval=None, percpu=True) # 打桩:第一次恒为 0,丢掉 while True: per = psutil.cpu_percent(interval=1.0, percpu=True) - _CPU['v'] = {'total': round(sum(per) / max(1, len(per)), 1), 'per': [round(x) for x in per], 'n': len(per)} + _CPU['v'] = {'total': round(sum(per) / max(1, len(per)), 1), 'per': [round(x) for x in per], 'n': len(per), 'model': name} except Exception: _CPU['v'] = {}