From 0a1f1080907d903ed1b99d7e8a22914d57325f13 Mon Sep 17 00:00:00 2001 From: hoelee Date: Tue, 13 Oct 2026 00:36:39 +0800 Subject: [PATCH] =?UTF-8?q?docs(STATE):=202026-10-13=20=E4=BA=A4=E6=8E=A5?= =?UTF-8?q?=EF=BC=88=E9=97=B8=E9=97=A8=E9=85=8D=E5=AF=B9=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20/=20preset=20=E5=AE=9E=E6=B5=8B=20/=20=E5=AD=90=E8=BF=9B?= =?UTF-8?q?=E7=A8=8B=E4=BA=B2=E5=92=8C=E7=9C=9F=E7=9B=B8=20/=20run=5Fpinne?= =?UTF-8?q?d=20=E4=BA=8B=E6=95=85=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- STATE.md | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/STATE.md b/STATE.md index e0fdd31..cd72c53 100644 --- a/STATE.md +++ b/STATE.md @@ -43,6 +43,77 @@ python cache/vmaf_native.py --original <快照原档> --converted <线上档> -- cpu + gpu 两条 lane 在跑(`autostart_lanes=[cpu,gpu]`)。**本仓不要自己起编码** —— 引擎只作为 lane 的子进程被调用, 单档启动器(`run/relaunch_x265.sh` 等)只在看板不参与时应急用。 +## 2026-10-13:闸门配对修复 / preset 可选 / 子进程亲和真相 / run_pinned 事故 + +(控制面侧的对应记录见 `D:\dev\hoelee-resource-transcode\docs\OPERATIONS.md` 同名小节) + +### 1. `run_pinned` 把 `capture_output` 传给 `Popen` → 三个 lane 秒失败 64 项(`eb4b0bd`) + +引入子进程包装时把 `subprocess.run` 的语法糖 `capture_output` 直接透传给了 `Popen` —— +`Popen` 不认这个参数,`run()` / `_sh` / 三个 ffmpeg 调用点全部 `TypeError`。因为失败是**秒级**的, +队列会立刻重投,2.5 分钟内 **64 项把 3 次 attempts 烧光变 failed**。 +修法:在包装里展开 `capture_output=True` → `stdout/stderr=PIPE`。 +**修复被误判的项要精确**:`UPDATE files SET state='pending', attempts=0, fail_gear=NULL WHERE last_error LIKE '%capture_output%'` +(按错误文本定位;不要整批重置 failed,那会掩盖真失败 —— 例如 `PermissionError [WinError 32]` 是真失败)。 + +### 2. 闸门:对齐修好了配对,判决却用旧配对的帧占比(`767fa3a`,业主的假拒绝) + +`ssim_vs_source` 一直在做三阶段对齐搜索(fine ±6 / coarse ±100 / per-frame ±2), +但 **触发条件只看 `min < 0.985` 和 `mean < 0.995`,漏了帧占比**;而且采用对齐结果时只更新了 +`lo/mean/n`,**判决消费的 `stats["below"]` 仍是直配的计数** → 于是出现 +`mean 0.9974(对齐后)但 20/1199 帧低于 0.85(直配)` 这种自相矛盾的判决,把 `0912 洞见` 反复拒掉。 + +改动: +- 触发条件加上 `bad > MAX_BAD_SHARE * n`; +- `_paired_ssim` / `_perframe_best` 现在返回 `below` 计数,并且**同样剔除近平坦帧** + (之前对齐后的 min/mean 含黑场帧,会让对齐看起来比直配还差); +- 采用对齐结果时同步 `stats["below"]`,并打印 `X frames below before, Y after`。 + +**验证方法(便宜且可复用,全部本地、不需真编码)**:同一个 60 s 窗口造三份夹具 —— +健康对(应走快路径、0 坏帧)、**错位 1 帧的对**(`trim=start_frame=1`;实测 +`alignment repaired the pairing: 20 frame(s) below 0.85 before, 0 after`,与判决书 20/1199 逐项吻合)、 +真缺陷对(`hflip=enable='between(n,250,400)'`;mean 0.9612 / 151 帧 10.07% **仍被拒** ✓ 没变橡皮章)。 +脚本模式见 `C:/Users/hoelee/AppData/Local/hermes/cache/scratch/gate_fix_test.py`。 + +生产验收(`0912 洞见`,crf 24):`ssim min 0.9936 mean 0.9971 (1199 帧)` → `ok 580 MB -> 422 MB (73%)`。 + +### 3. 子进程亲和的真相(Windows)—— 别再指望"子进程继承 mask" + +- **`CreateProcess` 不继承** affinity mask(Linux 的 `sched_setaffinity` 才继承)→ 引擎的 + `pin_to_e_cores()` 只覆盖引擎自己;实测三个 ffmpeg 全在 `0x3FFFFFF`(26 核)。 +- **事后补钉也不行**:对已跑的 ffmpeg 调 `SetProcessAffinityMask` 与 `AssignProcessToJobObject` + 都返回 `ERROR_ACCESS_DENIED(5)`(x265 自己为 NUMA 设线程亲和),而同一个调用打在 `ping` + 子进程上成功 → 是 ffmpeg/x265 拒绝,不是权限问题。 +- **唯一可行的机制 = Job Object 的 `JOB_OBJECT_LIMIT_AFFINITY`**:子进程创建时**继承 job 成员资格**, + 调度器对所有后代强制执行。控制面因此把引擎所在 job 带上亲和限;引擎里的 `pin_child()` + 只是 best-effort(对非 ffmpeg 子进程有效)。 +- **验证必须读 ffmpeg 子进程的 `ProcessorAffinity`**,不是引擎的、也不是看板上的。 +- 代价实测:同片段 pools=8,限核 11.2 s vs 不限 11.7 s(噪声内),输出字节一致。 + +### 4. preset 现在可由控制面指定(`5e27ede`) + +新增 `--x265-preset` / `--nvenc-preset`(控制面按设置传入;常量只是手跑时的回落值)。 +**NVENC 默认 p6 → p7**(业主决定),x265 保持 `medium`。 + +x265 实测(crf 24、pools=2、1080p 60 s 窗口,耗时 = 编码器自报秒数 ±1 s): + +| preset | 体积 | 帧率 | 耗时 | SSIM mean | +|---|---|---|---|---| +| ultrafast | 6.05 MB | 25.0 | 60 s | 0.9952 | +| veryfast | 7.58 MB | 16.7 | 90 s | 0.9968 | +| fast | 7.90 MB | 12.5 | 120 s | 0.9969 | +| **medium(现用)** | 8.11 MB | 12.5 | 120 s | **0.9971** | +| slow | 9.00 MB | 5.0 | 300 s | 0.9975 | + +**固定 CRF 下换 preset 不会让文件变小**(±1–2%,另一个窗口方向甚至反转)→ 省体积要动 CRF, +preset 是画质微调;`ultrafast` 的 SSIM 0.9952 紧贴 0.995 门槛(会把项推去重试),`slow` 是 2.5× 时间换 +0.0005。 + +nvenc(cq 31):p1/p2/p3 10.23 MB · p4/p5 9.49 · p6 9.44 · p7 9.41(同 cq 下 SSIM 全 0.9973); +精确计时 p4 263 fps / p6 139 fps / p7 128 fps → **p7 = p4 的 2.05 倍时间换 0.9% 体积**。 + +⚠ **计时坑**:经引擎跑编码时,stall 看门狗的 30 s 轮询粒度会污染挂钟计时(两个不同 preset 都报 150.0 s)。 +要精确比速度就绕开引擎直接调 ffmpeg + `perf_counter`。 + ## 现在在跑什么 **只有 x265 一档在跑**(2026-10-09 20:51:41 起,单档启动器 `run/relaunch_x265.sh`)。