TypePHP 编译器 https://swoole.com/aot/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

6.1 KiB

2026-08-03 工作日志

TypePHP 编译性能分析(docs/COMPILATION_PERFORMANCE_ANALYSIS.md)

任务:分析编译实现、提升编译速度、评估 mago 替代 AST 解析。

编译管线(4 阶段):

  1. prepare:扫描+parse(#1)+符号表+拓扑排序(SourcePipelineTrait::prepare → Preprocessor::prepareFile)
  2. convert:parse(#2,重复)+NodeTraverser+生成 C++(Translator::doConvert)
  3. compile:PCH + pcntl 并行(Windows 串行)
  4. build:链接

实测瓶颈(src/ 139 文件,php-parser 5.6.1):

  • 解析吞吐仅 3.18 MB/s,单遍 parse+resolve ≈ 599ms
  • 每个 PHP 文件解析两次(prepare + convert)→ 纯 PHP 解析 ~1.2s 起步
  • 生成 .cc 无增量缓存(只有 phpx misc 有),writeFile 无内容比对 → mtime 必变触发全量重编
  • prepare/convert 串行;Windows 无 pcntl 串行编译
  • AST serialize 体积膨胀 28.8 倍(47.6MB/1.65MB),unserialize 260ms vs parse+resolve 599ms(快 2.3 倍)

提速方案(按 ROI):

  • S1(P0) prepare/convert 合并单次解析(AST 内存/磁盘缓存)
  • S2(P0) 生成 .cc 增量对象缓存 + writeFile 内容比对(key 须含公共声明头)
  • S3(P0) PCH/misc 指纹轻量化(mtime 先行,内容 hash 兜底)
  • S4(P1) 解析阶段 pcntl 并行
  • S5(P1) Windows 并行(Msvc /MP 或 proc_open)
  • S7(P2) 合并多次 NodeFinder 全树扫描

mago 评估结论:不建议替换。mago 是 Rust 的 PHP 工具链(lint/format/analyze),AST 是 Rust 结构 + CST 模型,与 TypePHP 深度耦合的 php-parser API(296 处引用/75 文件,依赖 NodeTraverser/NameResolver/ConstExprEvaluator/PrettyPrinter/attribute 机制)不兼容。JSON 桥接或 FFI 的成本会吃掉解析速度优势。合理定位:前置语法预检或未来原生前端路线参考。

产物:docs/COMPILATION_PERFORMANCE_ANALYSIS.md(完整报告)、.workbuddy/bench_ast.php(可复现基准脚本)

实施 S1+S2(下午追加)

S1 合并两次解析

  • CompilerBase 新增 parseCachedAst()(按 $this->file 缓存原始 AST)+ cloneAst()(CloningVisitor 深拷贝)
  • prepareFile()doConvert() 都改用它 → 每个文件只 parse 一次
  • 关键约束:RuntimeAttributeFactoryLowering/Visitor 是有状态 visitor(会向 AST 追加节点),同一棵 AST 不能二次遍历,必须返回深拷贝

S2 增量缓存

  • writeFile() 内容比对:相同不覆盖,返回 bool(mtime 稳定,防头文件抖动)
  • 新增 hasGeneratedObjectFileCache():key = sha256(编译命令 + PHP ABI + 生成的 func_decl.h/data_decl.h/_arginfo.h 内容 hash)
  • isGeneratedSourceFile():buildDir 前缀 + .cc 扩展判断
  • compileFile() 对生成的 .cc 走缓存;save()/genExtension() 仅实际写入时 format
  • 注意:extension-.cc 不应列入 header 依赖(内容随任何类变化,会让所有 .cc 全量失效)

实测(302 文件合成项目,dry,3 次均值):

  • 全量:基线 6011ms → 改动后 5629ms(-6.4%)
  • 增量(不清理 build,第 3 次):5023ms(-16.4% 相对基线冷构建)
  • dry 不含 C++ 编译,S2 完整收益需在 build 场景验证

环境/验证要点

  • 本机完整编译需要 PHP_HOME=D:/git/php/tpc_v1095_windows_x86_64(含 php8embed.lib、SDK/lib/php8ts.lib、phpx/)+ 复制 tpc_v1095/phpx.dllphpx/build/phpx.dll
  • tpc_v1095/tpc.exe 是编译自 D:\workspace\compiler 的二进制,本机无法运行(内嵌路径不符)
  • typephp-think(554 文件)补丁后 prepare 通过,convert 阶段 Cannot re-assign 是仓库源码类型系统比 v1095 正式版严格($str array→str),非本次改动问题
  • git 事故:git stash 失败损坏 refs(HEAD→speed_build 指向 a92fc0df 对象缺失)。已恢复:分支指向 18decac(可用 commit),onepiece-doudizhu 示例内容在暂存区完好。备份在 .git-backup-20260803/,确认后删除

git 恢复与提交(下午追加 2)

  • git stash 事故根因确认:stash 失败不仅丢 refs,还导致 onepiece-doudizhu-win32 全部 19 个文件的 blob 对象缺失(index 引用了不存在的对象)。工作区文件完好。
  • 恢复方法git reset -- <dir> 取消暂存 → git add <dir>(从工作区重建 blob)→ commit。已恢复为 449afc1 add onepiece-ddz game example(4226 行,与原提交同名)。
  • S1/S2 已提交ac7813d perf: cache AST across prepare/convert and add generated object cache(3 文件 +206/-14)。
  • 最终 git fsck = 0 missing,仓库健康
  • 遗留:.git-backup-20260803/(18MB,git 事故备份,确认后删)、.workbuddy/onepiece-backup/(文件级备份,可删)。

code-wiki 文档生成(2026-08-04)

  • 为 aot-compiler 生成了中文 AI Wiki:22 页,7 个章节(概览 / 前端解析 / 类型系统 / 代码生成 / 后端构建 / 优化性能 / 运行时边界)。
  • 重要修正:code-wiki skill 的文档写 <workspace>/.agents/wiki/,但 scripts/render.py 实际读取 <workspace>/.workbuddy/wiki/wiki_dir = os.path.join(workspace, ".workbuddy", "wiki"))。写 catalog.xml / pages 必须放 .workbuddy/wiki/,否则 render 报 "catalog.xml not found"。
  • 产物:D:\git\php\aot-compiler\.workbuddy\wiki/index.html(左侧目录导航 + 右侧 iframe,离线 Mermaid)。render 命令:python <skill>/scripts/render.py render <workspace> --lang zh

环境结论(重要)

  • 本机 MSVC 工具链不完整:cl.exe + C++ 标准库头存在(C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC/14.44.35207/include/cstring),但 Windows SDK(Windows Kits 目录)完全缺失 → 无法完成真实 C++ 编译链接,只能验证到 dry 模式(prepare+convert+生成 .cc)。
  • tpc_v1095_windows_x86_64 是完整 PHP 构建环境:php8embed.lib、SDK/lib/php8ts.lib、phpx/(含 lib/phpx.lib);phpx.dll 需复制到 phpx/build/phpx.dll 才能通过校验。
  • 完整编译需在装有 Windows SDK 的机器执行(用户原编译机)。