Files
Robot_Arm/ml/selftest_proc.py
cbb 8ad6b58fca ml: 显存预算按 19–20 GB 落地 + ort 本地副本入库 + R4 复跑(feat_dyn)通过
- 显存:APG batch 128→48(实测 d=192 下 128 无论 plans 60/150 都 OOM,崩前已分配 17.85 GiB;48/plans150=13.08、48/60=7.67);新增 ml/common/vram.py 每进程硬帽 VRAM_FRAC=0.78 并把 vram 峰值写进 train/APG 日志、监控页加「显存峰值」卡与按 20 GB 预算的显存条;smoke.json 补 apg 段并让自检带 --config。
- 自检修复:find_bash 兼容便携版 git 的 mingw64 布局(本机原返回 None → 网页「开始训练」起不动);selftest_proc.alive 读中文 tasklist 的 GBK 崩溃;rec 值非法 JSON 时静默丢项;gen_resume 判据剔除 plan_ms/cert.ms 两个墙钟字段(旧判据恒 false)。整轮重跑 7/8 通过、3.5 分钟,仅 train_term 为 Windows 真实限制(TERM 送不到原生 python)。
- vendor: onnxruntime-web 1.20.1 本地副本入库(约 33 MB),查看器与 R4/R9 探针不再依赖 npm/CDN;.gitignore 同步移除该目录。
- docs: 第八节 R4 复跑(feat_dyn 新模型):部署口径 P99 12.67 通过;WebGPU 首次实测 27.09(有界面窗口,adapter nvidia ampere);viewer_ref 随机模型 planP99 131 / starve 32.7% / lookaheadP99 170 / certFailWhy time 948 / tickGapMax 736,三条判读留给实现方。
2026-10-18 06:40:25 +08:00

76 lines
3.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""本机自检的进程部分(2026-10-18 第七轮,遗留 C-5:Windows 生命周期从未实测)。由 ml/selftest.sh 调用。
tree :按控制台同一套标志(Windows: CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW;POSIX: 新会话)起 bash → python + node 两个孙进程,
再用控制台同一套停止方法(Windows: taskkill /T /F;POSIX: 按会话 TERM)结束,检查孙进程是否全部消失。
detach :起一个"启动器"进程,它按同一标志拉起子树后立刻退出,检查子树是否还活着(等价于关掉控制台黑窗口后训练是否继续)。
输出一行 JSON:{"tree_killed": bool, "survive_parent_exit": bool, ...}"""
import json, os, subprocess, sys, time, tempfile, shutil
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT)
from ml.monitor import find_bash, kill_session # noqa: E402
FLAGS = {'creationflags': subprocess.CREATE_NEW_PROCESS_GROUP | 0x08000000} if os.name == 'nt' else {'start_new_session': True}
def alive(pid):
if os.name == 'nt':
# 中文 Windows 的 tasklist 表头是 GBK,text=True 会让读线程解码崩掉(stdout 变 None)→ 按字节读再容错解码
r = subprocess.run(['tasklist', '/FI', f'PID eq {pid}', '/NH'], capture_output=True, text=True, errors='replace')
return str(pid) in (r.stdout or '')
try: os.kill(pid, 0); return True
except OSError: return False
def tree_cmd(d):
py = sys.executable.replace('\\', '/'); dd = d.replace('\\', '/')
return (f'"{py}" -c "import os,time;open(\'{dd}/p.pid\',\'w\').write(str(os.getpid()));time.sleep(300)" & '
f'node -e "require(\'fs\').writeFileSync(\'{dd}/n.pid\',String(process.pid));setInterval(()=>{{}},1000)" & wait')
WAITERR = ['']
def wait_pids(d, t=20):
for _ in range(t * 4):
try: return int(open(os.path.join(d, 'p.pid')).read()), int(open(os.path.join(d, 'n.pid')).read())
except Exception as e: WAITERR[0] = type(e).__name__ + ': ' + str(e)[:90]; time.sleep(0.25)
return None, None # 起不来时把最后一次异常带进结果,别让 tree_started=false 变成没有原因的失败
def main():
bash = find_bash(); out = {'os': os.name, 'bash': bash}
if not bash: out['error'] = '找不到 bash'; print(json.dumps(out, ensure_ascii=False)); return
# tree
d = tempfile.mkdtemp(prefix='st_tree_')
p = subprocess.Popen([bash, '-c', tree_cmd(d)], stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **FLAGS)
pp, pn = wait_pids(d)
out['tree_started'] = pp is not None and pn is not None
if out['tree_started']:
if os.name == 'nt': subprocess.run(['taskkill', '/T', '/F', '/PID', str(p.pid)], capture_output=True)
else: kill_session(p.pid)
time.sleep(3)
out['tree_left'] = {'python': alive(pp), 'node': alive(pn)}
out['tree_killed'] = not any(out['tree_left'].values())
for x in (pp, pn): # 清场
if alive(x):
if os.name == 'nt': subprocess.run(['taskkill', '/F', '/PID', str(x)], capture_output=True)
else: os.kill(x, 9)
shutil.rmtree(d, ignore_errors=True)
# detach:启动器拉起子树后立即退出
d = tempfile.mkdtemp(prefix='st_det_')
launcher = ('import subprocess,sys;' f'f={FLAGS!r};' 'subprocess.Popen([sys.argv[1],"-c",sys.argv[2]],stdin=subprocess.DEVNULL,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,**f)')
subprocess.run([sys.executable, '-c', launcher, bash, tree_cmd(d)], timeout=30)
pp, pn = wait_pids(d)
time.sleep(3)
out['survive_parent_exit'] = bool(pp and pn and alive(pp) and alive(pn))
for x in (pp, pn):
if x and alive(x):
if os.name == 'nt': subprocess.run(['taskkill', '/F', '/PID', str(x)], capture_output=True)
else: os.kill(x, 9)
shutil.rmtree(d, ignore_errors=True)
print(json.dumps(out, ensure_ascii=False))
if __name__ == '__main__':
main()