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
6.1 KiB
2026-08-03 工作日志
TypePHP 编译性能分析(docs/COMPILATION_PERFORMANCE_ANALYSIS.md)
任务:分析编译实现、提升编译速度、评估 mago 替代 AST 解析。
编译管线(4 阶段):
- prepare:扫描+parse(#1)+符号表+拓扑排序(SourcePipelineTrait::prepare → Preprocessor::prepareFile)
- convert:parse(#2,重复)+NodeTraverser+生成 C++(Translator::doConvert)
- compile:PCH + pcntl 并行(Windows 串行)
- 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.dll到phpx/build/phpx.dll tpc_v1095/tpc.exe是编译自D:\workspace\compiler的二进制,本机无法运行(内嵌路径不符)- typephp-think(554 文件)补丁后 prepare 通过,convert 阶段
Cannot re-assign是仓库源码类型系统比 v1095 正式版严格($strarray→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 的机器执行(用户原编译机)。