Skip to content

perf(ctex): l3build check 4-engine 并行, 20min → 8min#898

Merged
Liam0205 merged 4 commits into
masterfrom
feat/parallel-check
Jun 26, 2026
Merged

perf(ctex): l3build check 4-engine 并行, 20min → 8min#898
Liam0205 merged 4 commits into
masterfrom
feat/parallel-check

Conversation

@Liam0205

Copy link
Copy Markdown
Contributor

背景

ctex 默认跨 pdftex/xetex/luatex/uptex 4 个 engine 跑 181 测试 × 2 checkruns, 串行 wall-clock ~20min. l3build 自己没有原生 -j, 这里手写并行 wrapper.

改动

1. ctex/build.lua

testdir 改读 L3BUILD_TESTDIR_SUFFIX env, 让每个 engine 进程用独立 build/check-<engine>/ 目录, 不争抢临时文件. 默认空 → build/check (兼容直接 l3build check 单进程跑).

2. scripts/check-parallel.sh (新增)

主测 4 engine 并发 (& + wait), 输出按 [engine] 前缀分行. -c configs 仍串行 (config 本身只针对部分 engine, 数量少不值得并行). 失败汇总 Phase 1/2 各自结果.

3. Makefile

  • check-ctex 默认走 ../scripts/check-parallel.sh + 喂三个 config
  • check-ctex-serial 保留旧串行用法供调试

4. .github/workflows/test.yml

Test ctex 步骤改用同款 wrapper, ubuntu/macos/windows 三个 matrix job 各自加速.

5. llmdoc/reference/build-and-test.md

同步 CI 步骤说明.

实测加速

本地 ubuntu (8 core):

场景 wall-clock
单 engine 主测 (l3build check -e xetex) 3min16s
4 engine 并行 + 3 config 串行 (新 make check-ctex) 8min09s
串行旧法 (4 × l3build check) ~20min

加速 ~2.5×. 没到 4× 因为 4 个 luatex/xelatex 进程同时啃 RAM + IO 争抢, 但 8min vs 20min 已经很值.

Test plan

  • CI test.yml 三个 OS 都跑通 (ctex 步骤)
  • CI ctex 的 wall-clock 缩短到 8min 上下
  • 4 个 engine 都有独立的 build/check-<engine>/ 目录
  • 失败时 patch-health.log 仍能正确 dump

Liam0205 added 2 commits June 26, 2026 22:51
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 的同一测试).
@github-actions

Copy link
Copy Markdown
Contributor

PR Review: perf(ctex): l3build check 4-engine 并行, 20min → 8min

📋 审查摘要
维度 评价
设计方案 ✅ 通过 L3BUILD_TESTDIR_SUFFIX env 隔离 testdir,兼容性好
代码质量 ⚠️ 发现 1 个重要问题
文档同步 ✅ llmdoc 已同步
向后兼容 check-ctex-serial 保留串行入口

🔴 Important: patch-health.log 路径在 CI error handler 中找不到

文件: .github/workflows/test.yml

原 CI 代码显式引用 build/check-test/config-ctxdoc/patch-health.log。新代码改为浅层 glob,只在 build/check-* 的直接子目录找 patch-health.log

问题:Phase 2 的 config 串行跑时 没有设置 L3BUILD_TESTDIR_SUFFIX,因此 testdir 仍为默认 build/check。l3build 对 -c test/config-ctxdoc 的输出路径是 build/check-test/config-ctxdoc/patch-health.log(子目录,非直接子项)。

glob build/check-* 能匹配到 build/check-test/,但代码只查找 $d/patch-health.log(即 build/check-test/patch-health.log),不会递归到 build/check-test/config-ctxdoc/patch-health.log

建议改为递归 glob,同时查找一级和二级子目录下的 patch-health.log


💡 Suggestions

1. CI step 丢失 set -x 调试追踪

Test ctex step 开头有 set -x,改为调用 check-parallel.sh 后不再有。脚本自身的 echo 输出可以部分替代,但在 CI 调试时 set -x 的逐行追踪更有价值。建议在 CI step 中保留 set -x

2. llmdoc/reference/build-and-test.md 未完整同步

PR 更新了文件第 248 行附近的 CI 步骤说明,但同文件第 27 行仍写着:

注意 make check(全包回归)单包即需 20min+,本地慎用,默认仍由 CI 跑。

现在 make check-ctex 走并行约 8min,这个时间参考已过时。建议顺手更新。

3. check-parallel.sh 中 EXTRA_ARGS 未加引号

scripts/check-parallel.sh 第 39 行和第 67 行中 EXTRA_ARGS 未加引号,依赖 word splitting 来展开参数。当前 l3build 参数不含空格所以不会出问题,但从 shell 最佳实践看,建议改用数组传参。这是小问题,当前用法安全,仅作健壮性建议。


✅ 正面评价

  • 隔离策略清晰L3BUILD_TESTDIR_SUFFIX env 驱动 testdir 切换,零侵入 l3build 框架,默认空值兼容单进程直跑。
  • Phase 1/2 拆分合理:主测按 engine 并行(争抢 IO 但仍有 2.5x 加速),config 串行(数量少不值得并行开销)。
  • 串行入口保留check-ctex-serial 方便调试并行问题。
  • 输出可读性好[engine] 前缀 + 汇总表让 CI 日志易于定位失败 engine。

结论: 方案设计合理,加速效果显著。请修复 patch-health.log 路径问题后合入。

🤖 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,
不修.
@github-actions

Copy link
Copy Markdown
Contributor

PR #898 Code Review

🔴 Critical: trap EXIT 会在 CI 读取 patch-health.log 之前删掉并行工作目录

scripts/check-parallel.sh:46 设置了 trap 'rm -rf "$work_root"' EXIT

check-parallel.sh 以非零退出码返回时,trap 会先执行清理 tmp/parallel-check/然后控制流才到 test.yml|| {。此时 ../tmp/parallel-check/*/ctex/build/check/patch-health.log 已被删除,永远不会被找到

建议:将 trap 从无条件 EXIT 改为只在成功时清理:

cleanup() { [ "$?" -eq 0 ] && rm -rf "$work_root"; }
trap cleanup EXIT

🟡 Important: CI 注释仍引用已废弃的 L3BUILD_TESTDIR_SUFFIX 方案

Commit 2 (07e17e7) 已将隔离策略从 L3BUILD_TESTDIR_SUFFIX env 改为独立子工作目录 snapshot,但以下两处注释仍描述旧方案:

  1. test.yml 第 96-98 行:描述 L3BUILD_TESTDIR_SUFFIX env 切 testdir
  2. Makefile 第 87-90 行:描述 L3BUILD_TESTDIR_SUFFIX env 让每个 engine 用独立的 build/check-<engine> 目录

两处都应改为描述当前的 tmp/parallel-check/<engine>/ snapshot 隔离策略。


🔵 Suggestion: snapshot_pkg 静默吞错可能导致难以定位的 l3build 失败

scripts/check-parallel.sh:56-592>/dev/null 会吞掉 git ls-filestar 的错误。如果 snapshot 不完整,l3build 会以令人困惑的方式失败。建议至少保留 stderr。

🔵 Suggestion: Makefile 第 12 行注释未同步

Makefile:12 仍写着 单包 20min+,但 check-ctex 已经并行化到 ~8min。可以同步更新。


总体评价

整体方案合理:用独立子工作目录 + git ls-files | tar 快照实现进程间隔离,避开 l3build 内部相对路径问题,bash 3.2 兼容性也处理得当。PIPESTATUS[0] 精确捕获 l3build 退出码、Phase 2 configs 仍走原目录串行的设计决策都很稳健。

主要需要修的是 trap 时序问题(会导致 CI 失败时丢失诊断信息)和 两处过时注释

🤖 Generated with Claude Code

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".
@github-actions

Copy link
Copy Markdown
Contributor

🔍 PR 增量审查

项目 结果
结论 ✅ APPROVE
审查范围 07e17e7..5680fa3 (commit 3 + commit 4)
审查截止 5680fa3fcdd41977e340e5a05c6105d9d7749578

前两轮审查提出的所有问题已在 commit 3 (7132afa) 和 commit 4 (5680fa3) 中修复,逐项确认:

✅ 已修复问题确认 (6/6)

# 问题 修复 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

@Liam0205 Liam0205 merged commit 4c490f3 into master Jun 26, 2026
4 of 7 checks passed
Liam0205 added a commit that referenced this pull request Jun 26, 2026
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,
不修.
@Liam0205 Liam0205 deleted the feat/parallel-check branch June 26, 2026 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant