第六、七轮:离线 ort/WebGPU、R9 查看器整周期、安全层截止下沉、enc_once 前瞻 bug(feat 动态轴)、UTF-8、断点 RNG 续跑与 --stop-at、R2 池无关性自检、R8 出题缓存、本机自检 selftest、冒烟 smoke;遗留清单并入审查文档第六节

This commit is contained in:
Hark
2026-10-18 06:40:25 +08:00
committed by cbb
parent b6141d237c
commit 591678703a
29 changed files with 715 additions and 127 deletions
+71
View File
@@ -0,0 +1,71 @@
"""本机自检的进程部分(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':
r = subprocess.run(['tasklist', '/FI', f'PID eq {pid}', '/NH'], capture_output=True, text=True)
return str(pid) in r.stdout
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')
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: time.sleep(0.25)
return None, None
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()