perf(ctex): l3build check 4-engine 并行, 20min → 8min#898
Conversation
ctex 默认跨 pdftex/xetex/luatex/uptex 4 个 engine 跑 181 测试 × 2 checkruns, 串行 wall-clock ~20min. l3build 无原生 -j, 这里手写 并行 wrapper. 策略: - ctex/build.lua: testdir 改读 L3BUILD_TESTDIR_SUFFIX env, 让每个 engine 进程用独立 build/check-<engine>/ 目录, 不争抢临时文件. 默认空 → build/check (兼容直接 l3build check 单进程跑). - scripts/check-parallel.sh: 主测 4 engine 并发 (& + wait), 输出按 [engine] 前缀分行. -c configs 仍串行 (config 本身只针对部分 engine, 数量少不值得并行). 失败汇总 phase 1/2 各自结果. - Makefile: check-ctex 默认走 ../scripts/check-parallel.sh + 喂三个 config; check-ctex-serial 保留旧串行用法供调试. - .github/workflows/test.yml: Test ctex 步骤改用同款 wrapper, ubuntu / macos / windows 三个 matrix job 各自加速. 本地实测 (ctex 主测 + 3 config): - 单 engine 主测 = 3min16s - 4 engine 并行 + 3 config 串行 = 8min09s - 串行旧法 = ~20min llmdoc/reference/build-and-test.md 同步 CI 步骤说明.
之前方案让 testdir 切到 build/check-<engine>/, 但 LaTeX 内部用相对 路径写 .log (例 c70rm.fd → ../c70rm.fd), 与 .tlg 不匹配, baseline 全 报 diff. macos CI 上立刻在 abstract01 fail. 新方案: 每个 engine 在 tmp/parallel-check/<engine>/<pkg>/ 跑, testdir 仍是 build/check (原相对路径不变). 用 git ls-files | tar 高效快照 (比 cp -r 快, 只跟 git 跟踪文件, 不带 build/). 兄弟 deps 也 snapshot: checkdeps (从 build.lua 抠) + support/ (build.lua 末尾 dofile 共享 build-config.lua 必须). wrapper 完全去 bash 4+ 特性 (前版本 declare -A 在 macos bash 3.2 炸), 用字符串拼接管 pid/engine/rc 映射. ctex/build.lua 回到原状, 不再依赖 env. wrapper 是唯一隔离机制. 本地验证: abstract01 单测 ✓ (之前 macos CI 上 fail 的同一测试).
PR Review: perf(ctex): l3build check 4-engine 并行, 20min → 8min📋 审查摘要
🔴 Important:
|
bot review 提出:
1. [重要] patch-health.log 路径不递归: build/check-* 浅层 glob 找不到
build/check-test/config-ctxdoc/patch-health.log (config 跑的二级
位置) 和 tmp/parallel-check/<engine>/ctex/build/check/ (wrapper
独立子工作目录里). 改成显式列出三类候选位置.
2. [小] wrapper EXTRA_ARGS 用 "$*" 字符串拼, 未来传 --first foo 这种
会因 word splitting 出错. 改用 "$@" 数组 + bash 3.2 安全的
${arr[@]+"${arr[@]}"} 展开形式 (空数组也不炸).
3. [小] llmdoc 第 27 行还是旧 "20min+" 说法, 跟最新 8min 不一致.
同步.
set -x 那条建议: yml 里 set -x 实际还在 (line 95), bot 误读 diff,
不修.
PR #898 Code Review🔴 Critical: trap EXIT 会在 CI 读取 patch-health.log 之前删掉并行工作目录
当 建议:将 trap 从无条件 cleanup() { [ "$?" -eq 0 ] && rm -rf "$work_root"; }
trap cleanup EXIT🟡 Important: CI 注释仍引用已废弃的
|
1. [Critical] trap EXIT 无条件 rm 删工作目录, 早于 test.yml 的 || 块 cat patch-health.log. 修法: cleanup() 只在 \$? == 0 时删, 失败保留 tmp/parallel-check/ 让上层能 dump 诊断日志. 2. [Important] test.yml + Makefile 两处注释还在描述废弃的 L3BUILD_TESTDIR_SUFFIX 方案. 同步改为 wrapper 独立子工作目录 + git ls-files | tar snapshot. 3. [Nit] snapshot_pkg/snapshot_dep 用 2>/dev/null 吞了 tar/git 错误, snapshot 失败时 l3build 在难以定位的地方炸. 拿掉吞错, 让 stderr 直接冒出来. 4. [Nit] Makefile 第 12 行 check verb 描述还说 "20min+", 同步改为 "ctex 经 check-ctex 4-engine 并行 ~8min".
🔍 PR 增量审查
前两轮审查提出的所有问题已在 commit 3 (
|
| # | 问题 | 修复 commit | 状态 |
|---|---|---|---|
| 1 | [Critical] trap EXIT 无条件删 work_root,CI 块读不到 patch-health.log | 5680fa3 |
✅ cleanup() 现只在 exit 0 时删除 |
| 2 | [Important] patch-health.log 浅层 glob 找不到 config 子目录下的日志 | 7132afa |
✅ 改为显式列出三类候选路径 |
| 3 | [Important] test.yml / Makefile 注释仍引用废弃的 L3BUILD_TESTDIR_SUFFIX 方案 | 5680fa3 |
✅ 同步为 wrapper 独立子工作目录描述 |
| 4 | [Nit] EXTRA_ARGS 未加引号,word splitting 风险 | 7132afa |
✅ 改用数组 + bash 3.2 安全展开 |
| 5 | [Nit] snapshot_pkg/snapshot_dep 用 2>/dev/null 吞错 | 5680fa3 |
✅ 已移除,stderr 直接冒出 |
| 6 | [Nit] Makefile / llmdoc 多处 20min+ 未同步 | 7132afa + 5680fa3 |
✅ 已统一为 ~8min |
最终代码质量确认
- 隔离策略:git ls-files | tar snapshot 到 tmp/parallel-check/engine/ 独立子工作目录,testdir 保持 build/check 不变,避开 l3build 相对路径问题 - 设计干净。
- bash 3.2 兼容:无 declare -A、数组空展开安全、awk 替代 sed -u - macOS 默认 bash 可跑。
- 错误处理:PIPESTATUS[0] 精确捕获 l3build 退出码、Phase 1/2 分别汇总、失败时保留 work_root 供诊断。
- 向后兼容:check-ctex-serial 保留串行入口供调试。
代码良好,无新问题。等 CI 三平台通过后可合入。
🤖 Generated with Claude Code
bot review 提出:
1. [重要] patch-health.log 路径不递归: build/check-* 浅层 glob 找不到
build/check-test/config-ctxdoc/patch-health.log (config 跑的二级
位置) 和 tmp/parallel-check/<engine>/ctex/build/check/ (wrapper
独立子工作目录里). 改成显式列出三类候选位置.
2. [小] wrapper EXTRA_ARGS 用 "$*" 字符串拼, 未来传 --first foo 这种
会因 word splitting 出错. 改用 "$@" 数组 + bash 3.2 安全的
${arr[@]+"${arr[@]}"} 展开形式 (空数组也不炸).
3. [小] llmdoc 第 27 行还是旧 "20min+" 说法, 跟最新 8min 不一致.
同步.
set -x 那条建议: yml 里 set -x 实际还在 (line 95), bot 误读 diff,
不修.
背景
ctex 默认跨 pdftex/xetex/luatex/uptex 4 个 engine 跑 181 测试 × 2 checkruns, 串行 wall-clock ~20min. l3build 自己没有原生
-j, 这里手写并行 wrapper.改动
1.
ctex/build.luatestdir改读L3BUILD_TESTDIR_SUFFIXenv, 让每个 engine 进程用独立build/check-<engine>/目录, 不争抢临时文件. 默认空 →build/check(兼容直接l3build check单进程跑).2.
scripts/check-parallel.sh(新增)主测 4 engine 并发 (
&+wait), 输出按[engine]前缀分行.-cconfigs 仍串行 (config 本身只针对部分 engine, 数量少不值得并行). 失败汇总 Phase 1/2 各自结果.3.
Makefilecheck-ctex默认走../scripts/check-parallel.sh+ 喂三个 configcheck-ctex-serial保留旧串行用法供调试4.
.github/workflows/test.ymlTest ctex步骤改用同款 wrapper, ubuntu/macos/windows 三个 matrix job 各自加速.5.
llmdoc/reference/build-and-test.md同步 CI 步骤说明.
实测加速
本地 ubuntu (8 core):
l3build check -e xetex)make check-ctex)l3build check)加速 ~2.5×. 没到 4× 因为 4 个 luatex/xelatex 进程同时啃 RAM + IO 争抢, 但 8min vs 20min 已经很值.
Test plan
build/check-<engine>/目录patch-health.log仍能正确 dump