docs/current/07-质量与裁定/20260922_性能探究实录.md
GitHub ↗
当前有效

性能探究实录(2026-09-22)

28175 字·约 71 分钟 阅读 2026-10-10 17:07

AS-OF:2026-09-22。四轮实测探究的时间快照,数字仅对当日环境负责;复跑方式见 §7 探针资产。 口径:本机 AMD AI Max 395(高性能机,低端/移动端应按更差预估;跨机引用一律用比值不用绝对值);moon 0.1.20260915;vitro/engine@0.4.0;Rust 侧用 native/target/release/vitro_cli.exe 现成产物(冻结区,只跑未改)。 复跑:2026-09-22 同日晚经贡献者机(Intel i9-14900HX 笔本)重建全部探针后四轮复跑——核心比值全部复现、无一翻转,wasm 反超面扩大至 7/7;§1–§4 数字保持原机 as-of 不动,复跑数字与新发现见 §8,压力两维(arrinit/body)初测倍率已经 §9 勘误重估。 复跑 2:2026-09-26 S6 执行器落地后(vitro/engine@0.5.0)原机四轮复跑 + 执行层首测(兑现 §10 义务①)——管线/压力/时间旅行全部复现,bubble200 修正为可跑完(§11.4),wasm 反超面 6/7→2/7,构建时间新发现(cmd/run 链接 cliff,§11.8),全 MoonBit 栈对拍 356/366(§11.5);见 §11。 复跑 3:2026-09-29 S7 批五号(wasm-gc 单出口,2f18e10)落地后,原机按 §7 全探针复跑——本轮最大变量是环境而非代码:本机每进程启动开销已从同年 9-26 的 5.8-13ms 涨到 145-190ms(同机同二进制实测),dangerouslyDisableSandbox 无改善 ⇒ §1/§2/§9 的「逐进程/逐文件」口径本轮不可复跑,逐层与逐文件绝对值一律不得引用;可引用结论 = 执行层(§12.2):wasm-gc 跑完整引擎比 native 快 2-2.8×,而管线层只能记「持平或略优」;§11.9-4 的「管线 1.24× 翻转」按不可复现、归因不可定销账(同日方法对齐 A/B:0.5.0 与 HEAD 中位重合)。另发现全量 native release 构建因 gateway 的 +native 声明必失败(LNK1561,已给验证过的拆包修法),以及启动开销可归因到「进 main 之前 ~148ms」。详见 §12。 探针纪律:全部探针与产物置于 tmp/perf_probe/(gitignore /tmp/ 覆盖),git 工作区零流入;当日 git status 与探针前逐字一致。 结论速览:①管线层 MoonBit(native)比 Rust oracle 慢 1.4–1.6×,压力端恶化至 ~3×;②时间旅行(unified)是性能累赘实锤——每步全量快照 21μs(全速 320×),vs CPython 慢 3–4 个数量级,病灶是每步 CPU 而非内存;③wasm-gc 主场景 6/7 场景持平或反超 native,比 native 快 1.7×(lexer)/2.3×(GC);④路线裁定:bytecode→wasm 生成器为全速执行正解,模板超级指令搬运计划退役。——四条均经贡献者机复跑复核(§8)。

1. 第一轮:活跃区管线基线(native)

四层 dump 入口(cmd/ 差分工具,native release)对 baseline 365 例,3 轮中位,端到端口径(含进程启动与写盘):

入口(层) baseline 365 knr 81 leetcode 138 gap 16
dump_tokens(lexer,raw+pp 双遍) 0.37s 0.13s 0.22s 0.02s
dump_ast(parser) 0.26s 0.10s 0.19s 0.02s
dump_typeck 0.26s 0.12s 0.24s 0.02s
dump_compile(codegen) 0.30s 0.13s 0.25s 0.02s
  • 四层全跑 ≈1.2s,每例全管线 ≈3.3ms;单文件全管线延迟中位 12.3ms(n=10,含启动);gap 16 例 0.02s ≈ 纯启动下限
  • 构建/防线:moon clean 后全量 release native 构建 6.2s(37 tasks,不含 core 预编译恢复);moon check 热 0.65s;moon test 全绿 2.4s(例数以 facts moonbit_test_passed 真值为准——原机记录时点后 +1,见 §8.3-①)
  • 语料全量仅 ~350KB,"MB/s 吞吐"无意义,以每例毫秒与总耗时为准

2. 第二轮:用户场景 + Rust oracle 对比 + 压力测试

用户场景(教学 IDE 后端 = vitro_cli compile/run,执行层 Rust 承担,moonbit 执行器未到 S6):baseline 365 例全量 compile 中位 8.2ms、run 9.9ms,p90 11.3ms,零超时;6 个非 0 退出逐一归因全是诊断用例(e2_angle_local_header / e2_include_cycle / e2_include_not_found_* / e3_static_assert_fail / j1_declarator_depth),预期行为。

同层对比(两侧均 native release,同口径):

维度 Rust MoonBit 倍率
进程启动 4.6ms 11.4ms 2.5×
tokens 层目录批处理(baseline 365) 0.24s 0.35s 1.4×
compile 层逐文件单文件中位 8.9ms 13.3ms 1.5×

压力测试(自生成 6 维度 × 3 规模档 17 文件,tmp/perf_probe/stress/;排除 4 个两侧皆设计性拒绝文件后 13 文件逐维度):

维度 MoonBit/Rust 倍率(小→大档)
深嵌套循环(14 层) 1.40 → 1.61×
大数组初始化(5 万元素) 1.47 → 2.39×
大平铺多函数(8000 个) 1.93 → 2.85×
巨体单函数(5 万语句,684KB) 1.97 → 3.03×
海量局部变量(5000 个) 2.32 → 3.27×(最差)

规律:差距随输入规模扩大拉大,纯吞吐趋近 3×。优化定位优先看 locals(槽位分配)/ flat(全局符号注册)/ body(块线性扫描)。

设计性拒绝两侧同构(压力语料意外收获):表达式链超 AST 深度预算 512(Rust ParseError code 1006 / MoonBit stage=parse fail_json)、全局数据区 60KB 上限(MoonBit 拒绝文本与 Rust 逐字相同——照搬纪律的体现)。出口形态不同:Rust rc=1+stderr,MoonBit rc=0 + fail_json 产物(产物名 <stem>.c.compile.json,stem 含 .c)——moon dump 工具 rc=0 不代表成功,须查产物 ok 字段。

3. 第三轮:时间旅行性能裁定

裁定:时间旅行现状实现是性能累赘(实锤)。 初始结论曾误判"57ms 封顶、成本可控"——系 baseline 小语料步数太小无法暴露 O(步数×状态) 爆炸;换真实程序 + 外部对象(CPython 同逻辑)对比后反转:

程序 CPython Vitro run 全速 Vitro unified 时间旅行
fib(20) 递归 0.5ms 18.6ms 6.1s
冒泡排序 200 元素 3.3ms 20.1ms 60s 超时跑不完(§11.4 修正:75s 上限下 68.8s / 1,621,540 步跑完,原判定系超时设置截断)
500×500 嵌套循环 13.9ms 26.4ms 60s 超时跑不完
  • 全速 run vs CPython:1.9–37×(可用);unified vs CPython:4300–18000×(灾难)
  • 记录开销:每步 21μs(fib20 共 284,591 步/6.1s),全速同程序 65ns/步 → 320×
  • 归因(读码 native/src/unified/):每步全量快照(vm.snapshot/snapshot_into:变量+数组+指针+access log)+ payload 全历史驻留;教学单步语义是语句级,指令级全量记录无消费方
  • 内存维度实测修正(曾误判"移动端直接 OOM"):ctypes 采样峰值——run 2.0MB,unified fib 28.3MB / bubble200 46.6MB / arr_10000(万元素数组)51.6MB,内存温和(几十 MB 级);engine.rs 注释中 63.6GB 前科系 replay 负索引 bug(已修)非常态。真病灶是每步 CPU(collector 无条件重建快照对象),不是内存
  • VM guest 地址空间 = MEM_SIZE 1MB(moonbit/bytecode/memory.mbt 与 crates/vitro_runtime/src/memory_state.rs 同构同值):全局区 64KB 上限(可用 60KB)、堆 0x5000 起、栈自 1MB 顶下延。状态天然有界 → 全量检查点上界 1MB/个,checkpoint 方案上界可证明
  • 常态资源画像:单次 run 峰值工作集 2.0MB/提交 0.4MB(轻量级,与任务管理器常驻读数 39.4MB 是不同口径)

优化方案(权重修正版,按杠杆排序):

  1. 按需物化(主攻):collector 惰性化,每步只记最小事实(步号/PC/写集),变量表/数组快照仅在 UI 请求该步时从最近检查点+重放构建——直接砍掉 21μs 大头
  2. checkpoint + 确定性重放:每 N 步全量检查点,回退=最近检查点+重放 ≤N 步(教学 VM 确定性是天然优势;重放千步 <1ms)
  3. 写集 undo log:每步只记"地址+旧值",单步回退 O(1);collector 已有 AccessType::Write 观测基建
  4. 语句边界粒度 + 环形历史窗口(次要):指令级不记;学生实际回退最近几十步,环形覆盖封顶内存
  • 协议解耦:StepPayload v0.1 已冻结(61/61 回放)、TS 层免役——优化全部动在引擎内部,呈现协议不动
  • 预期:每步 21μs → <0.5μs,冒泡排序时间旅行从 60s+ 跑不完进秒内;移动端真实约束是低端机延迟 ×3–5 后是否无感(按重放 <1ms 账,成立)

4. 第四轮:wasm-gc 全面测试 + 路线裁定

背景:主场景是 wasm(浏览器/TS 层),此前全部数据是 native。独立 MoonBit 模块(tmp/perf_probe/wasm_bench/,mooncakes 装 vitro/engine@0.4.0,不触碰工作区)8 场景 argv 参数化基准,双后端同题对比,逐场景扣除启动开销。

首轮单点:2000 次 tokenize(856B×4 源)——moonrun(V8/TurboFan)137ms vs native exe 230ms,wasm 快 1.7×。

二轮全面(12 文件语料):

场景 wasm-gc 纯算 native 纯算 倍率(w/n)
lexer(×200) 37.7ms 62.0ms 0.61×
parser(×150) 65.3ms 82.4ms 0.79×
typeck(×100) 58.3ms 61.5ms 0.95×
codegen(×100) 82.4ms 92.2ms 0.89×
GC 分配压力(Map+Array ×200) 14.8ms 34.3ms 0.43×
lexer 大输入(12 文件拼接 ×50) 15.0ms 12.3ms 1.23×(唯一弱项)
深递归 400 层 ×2000 毫秒级安全 毫秒级 —
  • 启动:moonrun(V8+wasm 实例化)21.6ms / native 10.3ms
  • 产物体积:wasm 375KB vs exe 820KB(-54%)
  • 唯一弱项=大批量:大输入慢 23%;缩放检查 12× 输入=18.3× 时间(超线性,疑似 GC/内存增长;native 亚线性 9.2×)。绝对值 μs 级,教学规模(~450B/文件,15μs/次)无感;批量属 CI/对拍管道场景由 native 承担
  • 总评:6/7 场景 wasm-gc 持平或反超 native;管线全链折算 ≈ Rust 的 0.9–2.8×,典型负载基本追平——"月兔完整实施后会更差"在主场景不成立(native 后端 1.5–3× 的劣势只属于次要的桌面场景)
  • 未测口径:SpiderMonkey/JSC(moonrun=V8)、浮点密集、js 后端

路线裁定:

  1. 全速执行正解 = bytecode→wasm 生成器(用户提出,实测与读码坐实):opcode 包 Instruction 为栈式三元组(opcode+单 operand+loc),wasm 亦栈式——PushConst→i32.const、算术→i32.*;1MB 平铺内存→wasm memory 16 页,指针=i32 地址 load/store 直译;越界=wasm 原生 trap 白送且可转教学诊断(现 VM 手写 bounds check);host libc→wasm import。主要工程量仅一处:跳转→wasm 结构化控制流(stackify 类;第一版可函数内 dispatch loop 保守形态,照样吃 V8 JIT)。平台一次覆盖:浏览器/Node/wasmtime/移动 webview;iOS W^X 限制消失(JIT 是引擎特权)
  2. 模板超级指令搬运计划退役(收回"可搬月兔"旧建议):其前提"自研解释器承担全速执行"在 wasm 主场景下不成立;组合爆炸维护债照搬即负资产。解释器只服务单步/时间旅行,观测才是价值
  3. 与双模式架构对齐:run 全速=wasm 生成器产物;unified/单步=月兔解释器+按需物化(§3)

5. 路线总图(性能改进杠杆,按收益排序)

# 动作 空间 批次归属
1 时间旅行按需物化 + checkpoint + 写集 每步 21μs→<0.5μs(320×) S6 后执行器批的前置设计输入
2 bytecode→wasm 生成器(run 全速) 对比解释器形态 10–100× 复用 S5 bytecode+14 键 schema
3 压力三维(locals/flat/body)记账不动手 ~3×,教学规模无感 触发线:真实场景端到端 >100ms
4 编译管线 已毫秒级 不动
— 模板超级指令搬运 8.8× 退役

6. 测试方法学坑(全部亲历,防复发)

  1. vitro_cli 子命令是字面量:[exe, file, "-o", out] 漏写 dump-compile 会静默打印 usage(365 例"全失败"假象)——差分驱动脚本必须断言输出形态
  2. MoonBit 缺参 fail 路径有 backtrace 成本:测启动开销必须用正常路径调用(缺参 76ms vs 正常 11.4ms 假象)
  3. moon dump rc=0 不代表成功:失败走 fail_json 产物,查产物 ok 字段
  4. 小语料测不出超线性爆炸:baseline 几百步的程序把时间旅行测成"57ms 封顶";压力语料必须让步数上真实规模
  5. 绝对值不可跨机外推:本机 AI Max 395;跨机引用一律用比值(vs CPython / vs native)
  6. 忽略区探针也有构建约束:moon.mod import 是 module 依赖,包级 import 必须写 moon.pkg;const 名大写;Windows 路径反斜杠禁止进字符串字面量(os.path.basename 先处理)
  7. 内存采样禁止轮询(贡献者机复跑亲历,同日):采样循环按 interval 轮询 GetProcessMemoryInfo 会拖慢被测子进程——unified fib20 实际 8.1s 被拖成 >60s 假超时(拖慢 8×+)。峰值工作集应在进程退出后单次读内核维护的 PeakWorkingSetSize(等效且零干扰);分钟级长程序轮询失真不明显,秒级/亚秒级程序必中招(§3 的 run 2.0MB 疑同因低估,见 §8.3-④)
  8. (2026-09-26)Rust dump-tokens 必须同时给 --out 与 --raw/--pp 之一:缺任一 rc=1,压力 17 文件全体假拒绝——新写驱动前先跑一例核对子命令参数形态(坑 1 同族复发,亲历)
  9. (2026-09-26)MoonBit dump 产物为紧凑 JSON({"ok":true} 无空格):按 "ok": true 带空格形态文本匹配全 miss;ok 字段判定需兼容两种空格形态(坑 3 的匹配层细节)
  10. (2026-09-26)moon build 指定包用相对 module 根的裸包名:moon build lexer 可、moon build moonbit/lexer canonicalize 失败;且增量判定对 mtime 不敏感(touch 不触发重编)——单包编译实验须做内容变更,或改用"逐包推进"(见坑 11)
  11. (2026-09-26)全量构建时间分解用"逐包推进":moon build <pkg> 按依赖序逐包推进、每步计时,一发定位慢点;moon -v 输出经管道全缓冲,逐命令时间戳测不出(亲历无效实验,白付一次全量)
  12. (2026-09-26)unified 默认 --max-steps 100000:fib20(284,591 步)被静默截断且摘要报"可能存在无限循环"——复跑必须显式放大;它也是 §11.4 bubble 修正的直接原因(60s 超时 × 步数上限双截断假象)
  13. (2026-09-26)解析 CLI wrapper 先抓完整 repr 采样、再写正则:Rust run 的 wrapper 含全角标点(程序运行完成,返回值:)、完成行之后还可能粘引擎泄漏报告附注、[warning]/[stderr] 呈现行混入 stdout、Windows 管道 CRLF、MoonBit 侧 Latin-1 逐字节展开——本轮 5 发才中,全部可由一次采样避免(防误剥程序自打的伪装附注:附注剥除须验证块体纯度,且只剥尾部)

7. 探针资产与复跑

资产 位置 复跑
管线吞吐 tmp/perf_probe/bench_pipeline.py python bench_pipeline.py --rounds 3
多维对比(启动/批处理/逐文件/用户场景) tmp/perf_probe/bench_compare.py python bench_compare.py
压力语料生成(6 维度 × 3 档) tmp/perf_probe/gen_stress.py python gen_stress.py
时间旅行三线对比 + 内存采样 tmp/perf_probe/ext_cmp/(含 C/Python 等价基准) 见脚本内联
wasm-gc 全面基准(8 场景) tmp/perf_probe/wasm_bench/ `moon build --release --target <native
执行层对比(2026-09-26 新增) tmp/perf_probe/bench_moon_run.py python bench_moon_run.py(MoonBit run.exe vs Rust run × baseline;预编译 exe 直跑)
压力驱动(§9.3 同口径重建,2026-09-26) tmp/perf_probe/run_stress.py python run_stress.py(dump vs dump 逐层计时 + 查产物 ok 字段 + 执行层附加段)
时间旅行四线对比(2026-09-26 重建) tmp/perf_probe/ext_cmp/run_cmp.py python run_cmp.py(CPython/Rust run/Rust unified/MoonBit run;内存=退出后单次读 PeakWorkingSetSize)
wasm-gc 8 场景驱动(2026-09-26 重建) tmp/perf_probe/wasm_bench/run_bench.py moon.mod 依赖随发版升级 → 双后端构建 → python run_bench.py
全 MoonBit 栈对拍(2026-09-26 新增) tmp/perf_probe/diff_moon_run_full.py python diff_moon_run_full.py(baseline 逐例 stdout+返回码对拍 MoonBit cmd/run vs Rust run)

探针位于 gitignore 覆盖区(/tmp/、moonbit/_build/),不入库;清理不影响本档案结论的可复现性(生成器可重造全部语料)。 2026-09-22 贡献者机复跑注:上表探针未随库留存(持有人机本地),复跑时按本表口径全部重建(脚本重写、口径对齐),重建版同位于 tmp/perf_probe/(gitignore 区,同样不入库):bench_pipeline.py / bench_compare.py / gen_stress.py+run_stress.py / ext_cmp/run_cmp.py(三 .c 基准内嵌) / wasm_bench/(gen_bench.py 单源生成模块 + run_bench.py 驱动)。复跑结果见 §8。

8. 贡献者机复跑(2026-09-22 同日晚)

AS-OF:2026-09-22 晚。贡献者复现验证轮:按 §7 口径重建全部探针后在本机复跑四轮,目的=验证 §1–§4 结论是否机器无关。核心比值全部复现,无一翻转。本节数字为贡献者机 as-of,与 §1–§4(AI Max 395)并列;跨机只比比值。 口径:Intel i9-14900HX 笔本(24 核 32 线程;CPUID 报 Family 6 Model 183);moon 0.1.20260920;工作区 HEAD 317dbbf(git 干净);vitro/engine@0.4.0;Rust 侧同用 native/target/release/vitro_cli.exe 现成产物(只跑未改)。

8.1 逐轮结果(比值口径,✅=复现)

维度 贡献者机 原机(§1–§4) 判定
release 全量构建(moon clean 后) 9.11s / 37 tasks 6.2s ✅ 量级一致
moon test 210/210 绿·AS-OF 2026-09-22(冷 2.86s/热 0.99s) 全绿 2.4s(例数旧值,见 §8.3-①) ✅
moon check 热 0.68s 0.65s ✅
四层 dump 吞吐(baseline 365) 0.55/0.37/0.37/0.41s 0.37/0.26/0.26/0.30s ✅ 层序一致,整体 ~1.4×
进程启动(Rust/MoonBit) 14.4/23.5ms 4.6/11.4ms ✅ 倍率 1.6×(原 2.5×)
tokens 批处理倍率 1.3×(0.61/0.46s) 1.4× ✅
compile 逐文件倍率 1.49×(26.3/17.7ms,p90 33.4/25.3) 1.5× ✅ 精确复现
用户场景非 0 退出 6 例清单与 §2 逐字一致 同左 ✅
单文件全管线延迟(4 进程) 132.5ms 12.3ms ✅ 归因=本机启动开销(4×~24ms 启动主导,非管线变慢)
unified fib20 7.9s / 284,591 步(与 §3 逐字同) = 27.8μs/步 6.1s / 21μs ✅
unified 冒泡 200 >60s 跑不完 同 ✅
unified nested500 52.9s(灾难级) >60s ✅ 灾难判定不变
unified 内存峰值(fib/bubble/nested) 29.4/47.7/28.2MB 28.3/46.6/— ✅ 吻合(内存温和结论成立)
wasm-gc vs native 反超面 7/7(lexer 0.54× / GC 0.47× / typeck·codegen 0.66× / biglex 0.57×;启动 22.6/33.8ms) 6/7(biglex 1.23× 唯一弱项) ✅ 且更强(原弱项本机反超)
wasm 产物体积 -44%(543KB/970KB) -54% ✅ 同向
  • diff 驱动复测(d15a3be 后形态):typeck_diff gap / parser_diff gap 均 0.5s(提交声明 1.3s/1.2s,"秒级"成立)
  • wasm-gc 绝对值与 §4 不可比(复跑载荷不同:12 文件 90.4KB 内嵌语料),比值口径下结论增强;native 后端 1.5× 级劣势属于次要桌面场景的判定不变

8.2 压力五维(本机倍率 MoonBit/Rust,小→大档)

维度 本机初测 同口径重估(§9.3) 原机(§2) 判定
深嵌套循环(14 层) 1.29→1.65× 同初测 1.40→1.61× ✅
海量局部变量(5000) 2.40→2.42× 同初测 2.32→3.27× ✅
大平铺多函数(8000) 3.25→3.81× 同初测 1.93→2.85× ⚠️ 系统性偏高
大数组初始化(5 万) 6.31→13.87×(跨口径) ~3.96×(697/176ms) 1.47→2.39× ⚖️ 勘误(§9.3)
巨体单函数(5 万语句) 2.71→0.54×(跨口径假反超) ~3.5×(1124/318ms) 1.97→3.03× ⚖️ 勘误(§9.2/9.3)

勘误(2026-09-23):初测 arrinit/body 两行系跨口径(Rust compile 不序列化产物 vs MoonBit dump_compile 序列化 29–62MB 产物 JSON),重估后"13.87×"与"0.54× 假反超"均不成立;真缺口转为 §9.2 的 Rust compile 命令 O(n²)。后续引用压力倍率一律以重估列为准,初测数字仅作轨迹保留。

设计性拒绝同构复现:global_reject 拒绝文本两侧逐字一致(3 条;容器形态 Rust=数组、MoonBit=\n 合并单串——文本同构、容器异构,复跑脚本按文本口径机判);expr_reject 两侧同拒。勘误线索:Rust E1006 实测文本为"嵌套过深(超过 256 层)",§2 记"AST 深度预算 512"——疑两层预算(解析深度/AST 深度),待读码核对后勘误 §2(§8.3-⑤)。

8.3 新发现登记(复跑增量,按影响排序)

  1. moon test 真值 +1(已裁定):本机复跑实测 210 全绿,reports/facts.json 的 moonbit_test_passed 当时为过时 cached 值;同日晚 CI facts --run 刷新真值为 210,与本机一致——裁定:上游真实增量,非环境差异。对账纪律:测试例数一律引 facts 真值键,文档不写裸数(§1 同步)。
  2. Rust compile 命令 O(n²)(已归因闭环,初判勘误):初判"codegen 超线性"经逐层计时+读码反转——编译管线全程线性(dump-compile 5 万语句 318ms),超线性在 compile 命令相对裸管线多走的算法检测层:native/src/compiler/cfg.rs 两处 O(n²)(build_seq 每语句建块+连边 blocks.iter().find 全表扫;find_unreachable_blocks DFS 每节点全量重扫边表)。§2"优化定位优先看 locals/flat"不受影响(管线无辜)。归因过程与交叉验证见 §9.2;修复前禁止以该路径作对比分母(§9.4)。
  3. arrinit/body 初测倍率系口径假放大(勘误):初测跨口径(Rust compile 无产物序列化 vs MoonBit dump_compile 有,29/62MB JSON 实证)。同口径重估:arrinit 13.87×→3.96×、body 0.54×(假反超)→3.5×(§9.3)。§8.2 表已修正。
  4. §3 的 run 峰值内存 2.0MB 疑为低估:本机 run 退出后读 PeakWorkingSetSize 实测 8.6MB;§3 的 2.0MB 来自轮询采样,run 全速 <20ms 退出,轮询大概率未及采样(坑 7 同因)。unified 值两机吻合(§8.1)支持此判断;"内存温和"结论不受影响,反而更成立。
  5. E1006 深度口径(见 §8.2 末):实测 256 vs 记载 512,读码核对后择一勘误。

8.4 复跑资产

同 §7 注:全部重建探针位于 tmp/perf_probe/(gitignore 区)。四轮命令:python bench_pipeline.py --rounds 3;python bench_compare.py;python gen_stress.py && python run_stress.py;python ext_cmp/run_cmp.py + wasm_bench/(python gen_bench.py → moon add vitro/engine@0.4.0 → moon build --release --target <native|wasm-gc> → python run_bench.py)。

9. 深挖:压力两维归因反转与对比口径裁定(2026-09-23,贡献者机)

本节是 §8.2/§8.3 初测的归因闭环与勘误,单源记录——后续引用压力倍率、Rust compile 缺口、月兔优化裁定一律以本节为准,勿再散引初测数字。

9.1 逐层计时(3 轮中位,ms)

语料 MB tokens MB ast MB typeck MB compile Rust dump-tokens Rust dump-compile
arrinit_s 86 61 65 167 36 42
arrinit_m 142 113 109 367 52 98
arrinit_l 237 193 199 697 89 176
body_s 139 139 146 237 62 67
body_m 287 302 353 585 133 151
body_l 527 609 708 1124 252 318

读法:①两侧管线(含 Rust)全程线性——Rust dump-compile 67→151→318ms(语句 2.25×/2.1×);②同口径比值:tokens 层 ~2.1×、全管线 3.5×(body_l);③MoonBit body 各层均匀 2–3×,非单层塌陷。

9.2 真缺口:Rust compile 命令的算法检测层 O(n²)

vitro_cli compile(body_l)=2067ms vs dump-compile=318ms → 差值 1749ms(87%)在管线之外;差值曲线 20/183/1749ms(1万/2.5万/5万语句)超线性。

  • compile 走 engine::compile_pipeline::run_multi_file_pipeline(session 管线),相对 cmd_dump_compile 的裸四段管线多出:算法检测、补全快照、诊断/警告装配等附加阶段
  • 根因 native/src/compiler/cfg.rs(algorithm_detector 的 CFG 特征提取)两处 O(n²):
    1. build_seq(cfg.rs:399)——每条语句单独建基本块(5 万语句 = 5 万块/5 万边),fall-through 连接时 blocks.iter().find(|b| b.id == from) 每连一条边线性扫全块表 → 建图 O(n²)
    2. find_unreachable_blocks(cfg.rs:56)——DFS 每出栈一个节点就全量重扫整张边表找后继 → O(V×E)
  • 交叉验证:flat_l(8000 个小函数,同为 5 万语句)compile 仅 175ms——每函数块数 O(1),总量线性,与两处 O(n²) 的"单函数巨体"触发形态吻合;update_completion_snapshot 只扫顶层声明(structs/globals/funcs 签名),排除
  • 教学场景影响:几十行 → 几十个块,O(n²) 不可测;系压力语料才触发的债,baseline 363 例全小文件故从未暴露
  • 处置:登记不修(与 5e315e6 O2 债同形态);若将来修复,冻结区走 §2 白名单(缺陷修复)+红→绿(先造单函数巨体压力锚用例);修复前禁止以该路径作性能对比分母(§9.4)

9.3 口径勘误:arrinit/body 初测倍率

初测跨口径:压力表拿 Rust compile(不序列化产物)比 MoonBit dump_compile(序列化产物)。产物体积实证:arrinit_l Rust 侧 62MB / MoonBit 侧 29MB JSON,body_l 达 88MB——序列化+写盘本身就是差值大头。

同口径(dump vs dump)重估:arrinit 13.87× → 3.96×(697/176ms);body 0.54× 假反超 → 3.5×(1124/318ms)。§8.2 表已更新,初测数字保留作轨迹。勘误教训入坑:跨引擎对比必须两侧同出口形态——compile 类"只报成败"命令与 dump 类"序列化产物"命令不可互比。

9.4 对比口径裁定(917251e 门 1 先例)

蓝图第一手复核记录第三/四轮:名义红 3.83× 系对照物失真(理想化 Rust 孪生比现役解释器快 23×),换产品口径后门 1 翻转为通过,教训入档——"比值结论必须声明分母引擎"。本轮是同构问题的镜像:病灶分母(Rust O(n²) compile)会让月兔显得好,方向相反、结构相同。

裁定三条:

  1. 禁止以 Rust compile 的算法检测路径作分母(§9.2 修复前);
  2. 月兔优化的度量只用三个健康口径:①自身优化前后同语料同口径;②vs Rust 健康管线(dump 口径)的比值;③教学绝对负载校准(≤10M 步 ≤1s、99 分位 ≤3s,沿复核记录第四轮);
  3. "Rust 区不优化"是冻结纪律使然(oracle 只许白名单/安全修复/防线维护),不是为对比服务的策略——O(n²) 按 §9.2 处置,不充当你追我赶的背景板。

9.5 月兔优化空间(档案闭合项不再投入)

已闭合(917251e 门 0–3 + 5e315e6 裁决):惯用法层(FixedArray 无去界检公开原语、编码形态 ±4%——"无隐藏杠杆,不再追加")、载体层(packed 1:3.8 实测)、VM 热循环(MoonBit-V8 快于现役解释器 3.3×、慢于 JIT 2.8×,S6 按条件 A 每指令 ≤迷你 VM×3 验收)、typeck O2 债(perf_budget 闸 8/200 挡着)。

真杠杆(§5 重申,门 1 数据背书):

  1. 时间旅行按需物化 + checkpoint + 写集(每步 21μs→<0.5μs,320×)——勘察期 C-2"Trap 回退改重放(消每步 1MB 快照)"即同方向;
  2. bytecode→wasm 生成器(10–100×)——门 1 证 wasm-gc/V8 为优势交付目标,路线裁定更硬;
  3. 管线压力维度(重估后 2–4×):维持"记账不动手"(触发线:真实场景端到端 >100ms);若触发,顺序 lexer(2.1×,码元访问/分配热点)> codegen > typeck(闸)。

10. 遗留与后续触发线

  • wasm-gc 的 SpiderMonkey/JSC、浮点密集、js 后端三口径未测(不影响主线结论)
  • typeck/codegen 在 wasm 上的比例数据已补(§4),但 timeck Map 重结构的大批量超线性根因(GC/内存增长)未深挖——批量管道仍走 native,无行动义务
  • 执行器(S6 后)落地时:①把执行层纳入本探针体系(那是性能真正会动的层);②时间旅行按 §3 方案实现,不照搬 Rust 全量快照现状
  • locals/flat/body 三维优化触发线:真实教学场景端到端 >100ms 或某语料跑不完

11. S6 执行器落地后复跑(2026-09-26,原机)

AS-OF:2026-09-26。S6 vm 片完成(HEAD 6c90c7f)、0.6.0 发版批决策前;vitro/engine@0.5.0;moon 0.1.20260920;原机 AMD AI Max 395(与 §1–§4 同机)。baseline 语料 366 例(= §1 的 365 + 上游 1 例)。 义务兑现:§10 行动义务①"执行器落地时把执行层纳入本探针体系"——新增 §11.3 执行层首测与 §11.5 全栈对拍。 探针纪律:新增/重建脚本置 tmp/perf_probe/(§7 表已更新);当日工作区另有 6 个并发改动文件(vm_diff/gen_host_route/ci 等另一开发线),本批零触碰、探针全部落在 gitignore 区。 结论速览:①§1/§2/§9 全部复现、无一翻转;②执行层首测:baseline 端到端 MoonBit/Rust = 1.42×,计算密集全速执行差 6–16×(杠杆 2 的 S6 后第一手证据);③时间旅行 21–23μs/步复现、fib 步数逐字复现,bubble200 修正为 ~69s 可跑完(§3 原判定系超时截断);④wasm-gc 反超面 6/7→2/7(管线三场景一致 1.24×,登记待观察);⑤构建新发现:cmd/run 链接 199s(run.c 10.8MB 单 C 单元,cc -O2 超线性),编译期工具链债登记不动手;⑥全 MoonBit 栈对拍 356/366 逐例一致,新登记 va_copy 缺陷与自定义 include 缺口(§11.9)。

11.1 管线与防线(vs §1)

项 本次 §1(0.4.0) 判定
四层 dump 吞吐 baseline366(3 轮中位) 0.451/0.287/0.284/0.344s 0.37/0.26/0.26/0.30s(365 例) ✅ +1.1–1.2×,层序形状一致
moon check 热 833ms 0.65s ✅
moon test 实测时点(2026-09-26)433/433 5.04s;facts moonbit_test_passed 同日为 434(并发开发线 +1,§8.3-① 同形态) 210 例 2.4s ✅ 全绿,时间随例数近线性

11.2 多维对比与用户场景(vs §2)

项 本次 §2 判定
进程启动 rust/moon 5.8/13.0ms = 2.2× 4.6/11.4ms = 2.5× ✅
tokens 批处理 baseline 1.33× 1.4× ✅(stress17 批处理 2.4× 系新采口径,登记)
compile 逐文件 baseline 1.58×(15.2/9.4ms) 1.5× ✅
用户场景 compile/run 中位 9.3/10.8ms(p90 11.0/12.6) 8.2/9.9ms(p90 11.3) ✅
非 0 退出 6 例与 §2 逐字一致 同 ✅
Rust dump-compile 异常 9 例 = 6 诊断 + include 族 3 例 6 例 口径注记:dump-compile 对自定义 include 3 例 rc=1 而 compile 不拒——命令间失败集合差异,非回归

11.3 执行层首测(新增,S6 义务①)

三程序全速(3 轮中位,含启动;内存=退出后单次读峰值工作集,坑 7):

程序 CPython Rust run MoonBit run.exe MB/Rust
fib(20) 递归 0.54ms 22.5ms 43.0ms 1.92×
冒泡 200 3.00ms 22.6ms 142.7ms 6.32×
500×500 嵌套 17.1ms 30.2ms 475.3ms 15.7×
  • baseline366 端到端 run:MoonBit 中位 15.3ms(p90 16.9)/ Rust 10.8ms = 1.42×——教学小程序编译主导,执行差距被掩盖;计算密集程序暴露解释器差距 6–16×。峰值内存 MoonBit 9.2MB / Rust 7.8MB,均温和
  • 含义:条件 A 验收的是"≤迷你 VM×3"的月兔内部标尺;本表补 vs Rust oracle 的真缺口——全速执行差距落在 §5 杠杆 2(bytecode→wasm 生成器,10–100×)的覆盖域内,坐实"解释器只服务单步/时间旅行、全速执行交给 wasm 生成器"的分工

11.4 时间旅行(vs §3)

程序 CPython Rust run Rust unified 步数 每步 峰值内存
fib(20) 0.54ms 22.5ms 6.63s 284,591(与 §3 逐字同) 23.3μs 29.2MB
冒泡 200 3.00ms 22.6ms 68.8s 跑完 1,621,540 42.4μs 47.7MB
500×500 17.1ms 30.2ms >75s 超时 — — 28.0MB
  • 每步开销与内存峰值与 §3/§8.1 精确吻合(21μs/27.8μs;28.3/46.6/28.2MB)✅ "内存温和、真病灶每步 CPU"结论加固
  • §3 修正一处:bubble200 的"60s 跑不完"实为 60s 超时设置截断——75s 上限下 68.8s 完成(162 万步);其每步 42.4μs 比 fib 的 23.3μs 贵 ~1.8×,与"数组大快照更贵"一致。nested500 灾难判定不变。unified vs CPython 12,000–23,000×,优化方案(§3)的量化前提原样成立

11.5 全 MoonBit 栈对拍(新增)

moonbit/cmd/run(批五号全栈入口:lexer→parser→typeck→codegen→VM)× baseline366 逐例对拍 Rust vitro_cli run 的 stdout+返回码:

归类 例数 说明
逐例一致 356 stdout 行序列+返回码全同;全部 366 例无崩溃无超时
两侧同拒 6 编译诊断用例(e2/e3/j1),文案异构、语义同构
MoonBit 拒、Rust 成功 3 缺口②:自定义 include 未闭环(§11.9)
真语义 DIFF 1 缺口①:va_copy 未生效(§11.9)
  • 非缺陷形态差异(对拍口径已归一,记录备查):Rust CLI 把引擎附注([warning] note/泄漏报告/stderr 行)合并进 stdout 流,MoonBit cmd/run 三通道分离(后者符合 E-P1-5 设计);cmd/run 对非 ASCII 程序输出 Latin-1 逐字节展开(main.mbt 注释已声明,Go 驱动归一)——伪装用例靠"只剥尾部附注块+验证块体纯度"防误剥
  • 对拍脚本 diff_moon_run_full.py 留档 tmp/perf_probe/(gitignore 区,§7 表),本轮方法学坑(全角标点 wrapper/CRLF/Latin-1 展开/附注剥除防误伤)全部固化在脚本内注释,可直接复跑(§6 坑 13)

11.6 压力五维(vs §9.3,dump vs dump 同口径,3 轮中位)

维度(小→大) 本次 MB/Rust §9.3 重估列 判定
深嵌套 nest_4→14 1.63→1.98× 1.40→1.61× ✅
平铺 flat_500→8000 2.05→3.14× 1.93→2.85×(§2 初测) ✅ 同向
巨体 body_500→50000 2.10→3.80× ~3.5× ✅
大数组 arr_1000→10000 1.57→2.09× ~3.96×(l 档) ✅ 同向(arr_50000 本轮两侧同拒,大档不可测)
局部变量 locals_1000→5000 2.51→3.53× 2.32→3.27× ✅
  • 设计性拒绝两侧同构复现:arr_50000(全局数据区 60KB)+ expr 全三档(E1006)= 4 文件,MoonBit 走 fail_json(rc=0+ok:false)、Rust rc=1
  • 逐层计时形状同 §9.1(body_50000:MoonBit tok/ast/tck/cpl = 575/695/827/1657ms vs Rust dump-compile 436ms),管线线性、差距均匀分布;维持"记账不动手"(触发线核对:真实场景端到端 10–15ms ≪ 100ms)

11.7 wasm-gc(vs §4,0.5.0 首测,5 次中位扣启动)

场景 本次 w/n §4(0.4.0) 判定
lexer ×200 0.71× 0.61× ✅ 反超保持
GC 压力 ×200 0.65× 0.43× ✅ 反超保持
parser ×150 1.23× 0.79× ⚠️ 翻转
typeck ×100 1.24× 0.95× ⚠️ 翻转
codegen ×100 1.24× 0.89× ⚠️ 翻转
lexer 大输入 ×50 1.91× 1.23× ⚠️ 弱项扩大
启动 moonrun/native 26.7/12.2ms 21.6/10.3ms 同量级
  • 反超面 6/7→2/7:三管线场景收敛到同一 1.24×,系统性而非噪音(5 次中位);绝对差值 μs 级教学负载无感(百次 20–30ms),批量管道仍走 native
  • 处置:登记待观察——0.6.0 前复跑若同形,值得归因 0.4.0→0.5.0 间哪个包的代码形态在 V8 下退化;暂无行动义务。深递归场景本轮无分辨率(native 扣启动后为负);产物体积未复测(§4 的 -54% 口径不变)

11.8 构建时间(新发现,归因闭环)

全量 release native 冷态 151–294s / 43 tasks(§1:6.2s / 37 tasks),方差 1.55×(293.5→189.4→151.4→186.8s)。逐包推进分解(坑 11):

组 耗时 说明
15 个库包合计 ~4s(每包 0.0–0.4s) lexer/parser/typeck/codegen/vm/host 等
dump 四件各 4–5s ~19s 链接闭包 4.7–7.7MB
cmd/run 链接 198.9s run.c 10.8MB 单 C 编译单元
  • 归因:cmd/run 是唯一链接 S6 执行器闭包(vm+host+libc+memory)的入口,生成的 run.c 达 10.8MB,cc -O2 超线性(对照:dump_compile.c 7.7MB→5.2s、dump_ast.c 4.7MB→4.1s——7.7→10.8MB 体积 1.4×、时间 38×,cliff 明确);debug 全量 4.1s 无此问题;热态复跑 3.5s(全缓存)
  • 编译器矩阵定案(同机同文件补测):MSVC cl 14.51 /O2 = 159.3s(独立复测;moon 源码 build_lower/compiler/msvc.rs 固定 /O2)vs llvm clang 22.1(msvc-target,同 ABI 同头文件)16.0s vs MinGW-w64 gcc(彼时 16.2.0)31.8s——病态锁死 MSVC cl 优化后端(10×/5×),非 MoonBit C 产物对编译器普遍病态、非本机环境问题;对照口径:cl 与 clang 同 ABI 同头,唯一差异是优化器
  • 绕过手段(本机已终验):moon 支持 MOON_CC 环境变量覆盖 C 编译器(源码 compiler_flags.rs ENV_MOON_CC,clang 走非 MSVC 通用分支)——MOON_CC=clang 全量 release 构建 17.1s / 43 tasks rc=0(默认路径的 12–17×);运行期产物语义等价(同一 C 源不同编译器),但 clang 路径非 moon 官方默认,是否切换作发版批拍板项
  • 性质:编译期工具链债,不影响运行期;§1 的 6.2s 时代执行器闭包尚不存在,与 §1 不可直接互比。CI 的 moon test 走 debug 档不触发该 cliff,受影响的只是本机 release 全量构建
  • 单函数归因(2026-09-26 深挖闭环):run.c 共 257,275 行,病态 100% 锁定 moonbit_init——moonc 为整个模块闭包生成的全局初始化巨函数:单函数 18,498 行 / 589KB,本质上是一个巨型直线基本块(18,457 条语句 / 仅 1 个 if / 零循环零 goto,只复用 18 个 distinct 临时变量——初记"~1.8 万个局部临时变量"系把 18,403 次引用误作变量个数,勘误);挖空该函数后 cl /O2 159.3s → 6.3s,文件仅缩 5.6%(602,900 / 10,776,823 B;初记"10%"系 MiB/MB 口径混用,勘误);clang 编同一文件 13–16s 无异常,gcc 全量 30s→清空后 21s(仅 1.4×——该函数对 gcc/clang 基本无害,病态 MSVC 特有)。cliff 真身不是"文件大"而是"这个单函数"
  • 两机复核(贡献者机 i9-14900HX / VS 18.5 / MSVC 14.44+14.50):clang -O2 13.5s、gcc -O2 31.3s 与本机几乎重合(单线程相当,排除硬件解释);MSVC cl /O2:14.50 = 71–73s、14.44 = 76s vs 本机 14.51 = 159.3s → 2.2× 工具集版本退化;clang-cl /O2 = 16.7s(同 ABI 同头同 MSVC 目标,4.4× 全在 MSVC 优化后端);端到端默认 cl 82.3s vs MOON_CC=clang 23.2s(43 tasks rc=0)
  • 同机版本 A/B(本机补装 14.50.35717)——初测 1.81× 已勘误:独立测量对(88.0s vs 159.3s)混入热漂移,用户交替 A/B(14.51→14.50→14.51→14.50,同份 run.c)定案 101.14s vs 68.66s = 1.47×(区间 96–126 vs 68–81 不重叠;冷首跑可达 1.94×);挖空 init 后 14.51 = 4.93s 反而快于 14.50 = 5.63s——退化是该函数形状特有,非通用变慢(此条比倍率本身更锋利)。定案形态:moonbit_init 巨函数 × MSVC 优化后端 = 病态基底(cl 下 ~20×、gcc 下仅 1.4×),14.51 工具集形状特有再乘 ~1.5×;绕过 MOON_CC=clang 两机验证(17.1s / 23.2s,rc=0;前提:仅 generated-C 路径,direct-object MSVC 目标忽略非 cl 兼容 MOON_CC——builders.rs 警告实锤)。另有今天即可用的包级绕过:link.native.cc-flags 覆盖默认 flags(has_user_flags 非空即不塞 /O2,compiler_flags.rs:1063/1318 + builders.rs:1113 实锤)
  • 处置:登记不动手(纯编译期成本,运行期/CI/日常增量不受影响);复现资产见下两条
  • ✅ 已提报:moonbitlang/moon#2254(2026-09-26 晚,rustin-beep 身份 API 创建,open 待 triage)——两轮用户审阅批(数字勘误 1.81×→交替 A/B 1.47×、巨型直线基本块勘误、/O2 落点改 compiler_flags.rs、link.native.cc-flags 现有绕过、TL;DR 置顶、/d2 建议移出)+独立复跑全数通过(1.52×/清空方向/gcc 1.4×/init 155 行)后提交;源码基线 tag perf-cliff-repro-20260926 已推远端(040fbb1)。哈希口径勘误(用户第三批发现):整文件 sha 依赖构建目录——moonc 发射的 #line 指令内嵌绝对源路径(10,964 行,A/B 两份差 230,244 B,e9c1d0a vs 136ec81c);路径无关指纹=moonbit_init 区间(void moonbit_init() { 至闭合 },602,899 B 不含尾换行)sha256=08943e7c…,跨克隆逐字节一致;issue/tag 描述/dc 草稿已全改此口径;干净克隆重建交错 A/B 第三次复现 1.59×(154.91/97.63)。外部贡献者打 label 403("Must have admin rights"),留给官方 triage。Context 节已补(2026-09-27,用户两轮拍板)——"who is hitting this":定位=教学导向的白箱 C 子集引擎(纯 MoonBit 编写,自管 guest 完整内存模型:自有地址空间/堆状态机/每次访存受检)+ 443 测试与 Clang 逐字节对齐(用途=支撑"产物正确、纯构建期问题"的诊断可信度,非规模宣传);触发叙述="Being a teaching-scale project, we did not expect to hit a build-time cliff of this size"→推论"门槛不高(链接若干包到一个可执行就会撞)";示好=愿充当回归样本(MIT/一条命令复现/可跑预发布工具链回报计时)。位置在 Environment 与 Notes 之间(动线:技术事实→谁在撞→建议方向)。用户纠偏记录(表述纪律):初稿为"装高手"把"教学"定位藏掉、写成通用编译器口吻,被用户点出"怎么写得跟工业级编译器一样"——正解=说别人没有的具体技术事实(能掌控内存的白箱)而非堆通用规模数字;用户素材中的"平台级项目""三出口架构"等用词未采用(前者偏夸大、后者所指不明)。release 页已标 [repro asset] 前缀+中英双语性质声明(防路人误认为产品发行版)
  • 第二位贡献者审阅批之一(2026-09-26 晚,8 条意见全数实测后销项;该审阅者=issue 中的 Reporter 2,即此前提供跨机数据(i9-14900HX / VS18.5 / MSVC 14.44+14.50)的长期贡献者,已授权公开该关联):
    • ①标题倍率勘误:原 ~20x slower than clang 无支撑——20× 实为"cl 有/无 init"的自身形状敏感度,非 vs clang 口径;实测 cl vs clang = 87–126s vs 12–16s = ~5–10×(随工具集/热态)。已改标题与正文(标题现为 ~5-10x slower than clang; 14.51 regressed ~1.4-1.6x)
    • ②机理断链修正:原文归因"new SSA-based loop optimizer"与实测零循环自相矛盾;实测结构=扁平常量表初始化(18,495 语句中 18,347 条 base[i]=v 元素 store、98.2% 纯整数字面量,主体是 17,425 元素堆数组 + 644/88 两个小数组)。已重写为形状描述+撤回 pass 级猜测(pass 归因留待微软侧)
    • ③/Bt+ 直接测量替代"删除推断":c1.dll(前端) 0.329–0.370s vs c2.dll(后端) 85.56s(14.50)/119.35s(14.51)——前端仅占 0.3%,版本差 1.40× 全在后端;已写进 issue(取代"请上游跑 WCTR"的表述,义务自扛)
    • ④/d2ReducedOptimizeHugeFunctions 实测(新缓解手段):14.51 119.8→32.1s(3.7×)、14.50 86.0→40.1s(2.1×);开启后 14.51(32.1s) 反超 14.50(40.1s)——第三次以独立手段印证"退化是形状特有"。blast radius 实测极小:全文件 182 函数中仅 init 超阈值(第二名 1,050 行),且 init 每进程仅跑一次→减少其优化的运行期代价可忽略。已作为"已验证缓解"入 issue Notes(并声明非请求 moon 默认加此未文档化 flag)
    • ⑤ReducedOptimizeThreshold 语义勘误:该开关语义是"对超阈值(默认 20,000 指令)巨大函数减少优化以缩短编译时间"且 opt-in(VS2019 16.4 引入;TensorFlow/Unreal 均需显式设置)——原文当"太大所以慢"的依据,方向反了。已改为"实测用它有效,与该诊断一致"(MS 博客链接已核 200+ 含该 flag 与 20000 阈值)
    • ⑥平台无关理由补强(策略):gcc 同形状也慢 1.4×(30→21s) + 单 TU 使缓存/并行最小粒度=整个 10.8MB(改一行废整条 ccache 条目、TU 永远只占一核) + 该单元亦是交给 LTO/调试器的粒度 → 论证从"MSVC 的 bug"升格为"moonc 代码生成器的结构缺陷"(后者才排得上期)
    • ⑦release asset 已挂:perf-cliff-repro-20260926 含 run.c(10,776,823 B 直链下载)+ perf-cliff-repro-kit.zip(探针 7.3KB:矩阵//Bt+//d2/挖空对照);上游验证门槛从"装 moon 构建"降至"一行 cl 命令",issue 的 Option B 已改指该直链
    • 未销项:第二台物理机的 14.51 数据(贡献者机未装 14.51;同机 clean clone 不计)——记为待办,用于独立确认版本退化
  • 第二位贡献者审阅批之二(2026-09-27,病因因果)——"单基本块"系未验证因果,已实测推翻:
    • 他的实验:不改任何原有语句,只在函数体插 K−1 个不可折叠分支把巨块切 K 块 → 切块收益仅 ~33%(他的基线 67.83s→K=16 45.47s,0.67),K≥16 饱和,K=256 回升;clang 不受影响。结论:真正驱动成本的是"单函数承载的指令总量"(函数级优化域规模),"单基本块"只是伴生现象
    • 本机独立复现(交替两轮,排除热漂移):K=1 = 88.05/84.09s vs K=16 = 55.88/56.49s(均值 86.07→56.19 = 0.65),clang @K=256 = 11.22s;归一化与他精确吻合(他 0.66–0.74 / 我 0.65–0.71)
    • 补充实验(他止步处:因 33 处跨行复合初始化怕劈断语法而停手——我的顶层语句边界扫描器解决了):把 moonbit_init 拆成 N 个 static 函数(开头 25 条声明提升为 file-static,按顶层语句边界切分,依次调用)。交替确认:基准 87.09/91.49s vs 拆 4 函数 5.88/5.96s = 15.1×;拆 2 = 19.14s(4.7×);拆 64 = 4.29s
    • 决定性对比:拆成 4 个函数(5.92s)比"删空全部代码"(4.93–6.63s)还快 → MSVC 成本几乎全部来自"单个函数的规模",与代码总量无关;且饱和极早(N=4 已拿到 ~99% 收益),处方(per-package init chaining)无需细粒度
    • 语义验证(闭环):拆 4 版链接成 exe(libruntime.lib+libfs.lib,手工 LIB 补静态 CRT),跑 5 个 baseline 用例——rc+stdout 与原版逐字节一致(SAME 5/5) → 拆分方案语义等价、可行
    • 完整干预阶梯(cl 14.51 /O2,归一化到各自基线):切块 K=16 0.65 / /O1 0.75–0.88 / /d2 0.42 / 拆 2 函数 0.22 / 拆 4 函数 0.07 / 拆 64 0.05 / 删空 0.06–0.10
    • 结论与销项(✅ 已 PATCH 2026-09-27):处方方向正确且已量化("拆成几个函数"即可,4 段饱和);病因措辞已改——谁若按"缺基本块边界"去修(插 dummy 分支)最多白干 2/3。#2254 五处修订已上线:①Actual 病因句改为"the block shape is a symptom, not the cause"并指向新节 ②新增 1c 干预阶梯(切块 0.65–0.67//O1 0.75–0.88//d2 0.42/拆 2 = 0.22/拆 4 = 0.07/拆 64 = 0.05/删空 0.06–0.10,含拆分的机械做法、5/5 语义验证、以及"只插块边界最多白干 2/3"警示)③Notes #1 补量化(4 段即饱和,无需 per-package 粒度)④⑤口径统一——"Reporter 2" → "second contributor's machine"(用户拍板:第二贡献者已做完实验、不参与后续处理,由我们负责整合与叙述;不称 external reviewer)。dc_draft 同步补干预阶梯(对微软=直接印证其 huge-function 阈值设计)
  • 新 issue 观察(2026-09-27,#2255):Windows Defender 把官方 moonfmt.exe 隔离为 Trojan:Win32/Bearfoos.B!ml(报告者 moon 0.1.20260904,VirusTotal 0 检出)。与 #2254 无技术因果(一个是 AV 误报二进制、一个是编译器优化时间),但同属"Windows 工具链摩擦",且为本轮"首跑惩罚=AV/Defender 扫描"的归因提供同环境侧证(我们这台机器上 Defender 确实活跃)。处置:不评论(我们未遇到该问题,信息量低),仅记录。
  • 第三轮评估(2026-09-28,依赖清除后复盘;材料=用户两轮评估汇总+本会话三轮补测)——先勘误后采纳:
    • 勘误(报告三处):①"24 行源码"错——main.mbt 实为 1,095 行 / 81,757 B(17,425 个数字的物理排布,报告 0 节与 5.5 节自相矛盾,5.5 自己已修正);②tag 177.9s vs HEAD 134.3s 并列展示有误导——两份 init 结构逐字节等价(见下),32% 差异是测量方差,非版本差异;③"门槛=元素数上万"仍是外推(其 5.1 只测两个极端)
    • ✅ 结构等价严格证明(5.2,本会话独立核验通过):tag vs HEAD init 区间逐行不同 18,432 行,抹掉所有数字后 0 行差异 ⇒ 纯标识符编号平移(用户口径 5.2 精确;我此前"percent-level timings unchanged"的措辞被其 5.3 方差数据打掉——同文件散布 109/117.9/142.3s,百分比级不可证)
    • ✅ 阈值曲线(5.1+5.3+本会话三轮补测合成):语句数 1→4,006→8,006→12,006→17,431,cl /O2 ≈ 0.3/3.1/12.9/29.5/109s(热);每语句成本 0.774→1.611→2.457→6.253 ms,前两段吻合平方律(k≈2.0),末段跳 k≈3.5;复测方差:N=4000 = 2.88/2.94s(±2%),N=8000 = 12.66–15.43s(±10%),N=12000 = 33.13/38.82s(±8%)——曲线形状可信,单点绝对值有 ±10–15% 散布
    • ✅ /d2 阈值实测定位(报告"未做"的关键对照,本会话补齐,方向推翻其推断):语句数 4,000→0.99×(无效果);8,000→2.73×(已生效);12,000→3.45×;17,431→4.16× ⇒ MSVC huge-function 阈值落在 4,000–8,000 语句之间(报告推断"12k–17.4k"错;按 ~1.4 指令/语句折算 ≈6k–11k 指令,低于文档默认 20,000——说明 moonc 的 store 序列展开后指令数远超语句数,或 14.51 的实际阈值行为与文档记载有出入,留给微软判定),且收益随规模单调递增
    • ✅ 5.4 caveat 实测复现:函数构造(非字面量)的 init = 3 行/144B/2 语句、悬崖不复现——本会话补测 hello_probe.c(1 语句)= 0.06s;字面量要求已写进 issue Option C
    • issudedraft 状态:issue_revision_draft_0928.md 三处修订方向全部成立,但需两处再修:①删"percent-level timings are unchanged"(改"structure and timings unchanged"或引方差区间);②Option C 补实测阈值曲线(4k 无感/8k 已触发)替代"未测中间地带"句;③门槛句不再写"上万",改引实测曲线——✅ 三处已修并 PATCH(2026-09-28,用户批准):修订内容=①Context 门槛句改实测曲线(1→4k→8k→12k→17.4k 语句 ≈ 0.3/3/13/30–39/110–142s,每语句成本超线性,±10–15% 散布声明)②Steps 重排 A/B/C:A=minimal(mb_probe.zip 3.7KB 直链,生成器一行,字面量 caveat 引实测)/B=run.c 直链/C=full sample(补 git checkout perf-cliff-repro-20260926+注明 tag 带旧依赖而 main 零依赖可离线)③Source baseline 补 HEAD 现状(fe7c1f49…,结构等价:18,432 行差抹数字归零)+阈值实测(4k=0.99×/8k=2.73×/12k=3.45×/17.4k=4.16×,低于文档 20k 指令默认)+删"percent-level"(方差不可证);TL;DR Repro 行补 minimal 提及。mb_probe.zip 已上传 release(3,736B;release body 同步登记);本地 issue_draft.md 已同步线上版。不重打 tag 的裁定维持(老 tag=数字基准;新 tag 等 Bytes 改造落地后打 perf-cliff-fixed-* 形成 before/after 对)
  • 跟进待办:①DC 双报告——英文草稿已备 D:\code\build_cliff_probe\dc_draft.md(三问式:/O2 剖面/阈值覆盖/文档化缓解;附 run.c 或 release 直链);②moonbit-docs MOON_CC 文档 PR(等 #2254 表态);③MOON_CC 换编译器不触发重编(no work to do)实测后单开;④第二台物理机的 14.51 数据;⑤DC 提交后回 #2254 贴链接互链
  • 上游尽调(2026-09-26,免重复):moonbitlang/moon 全 issue 库检索无人报告过 MSVC 对大型生成 C 单元的编译超线性——本报告为首例;相邻工作:#1958 已拆分的是 moon 运行时库 C(lib/runtime/*.c)而非 moonc 为用户模块生成的单元;#1378(open)优化档位 profiles 仍是 feature 请求;#2085 确认 Windows 探测顺序 MSVC > MinGW > system cc(默认撞 cliff 是有意设计);#1714(open)正在完善 clang 工具链行为;#1091(open)MOON_CC 暂不支持带参。业界背景:MSVC 大 TU 慢于 clang 为常识(Firefox 2018 转 clang-cl、Developer Community 单文件 15× 病态先例),issue 措辞应落在"moon 默认组合(单单元 × cl /O2)的乘积效应 + MOON_CC 文档露出",勿写成"MSVC 是 bug"

11.9 遗留与拍板项(2026-09-26 新增)

  1. va_copy 缺陷(e1_va_copy,D 级 29 用例未覆盖):va_copy(ap2, ap) 后从副本 va_arg 读取全得 0——Rust 侧 8.0 13.0 vs MoonBit 8.0 0.0(第一遍 va_arg 正确、副本游标丢失,host va_* 族);host 包小改,可随 0.6.0 修复批
  2. 自定义 include 未闭环(include_custom_header/e2_has_include_chain/e2_include_guarded,D 级未覆盖):cmd/run 单文件入口只把主文件装入源表,自定义 .h 不落盘装载(与 CWD 无关、.h 实际存在,已实测排除环境因);Rust oracle 按磁盘解析成功——涉及 lexer/入口约定,工程量较大。两项均不阻发版(cmd/run 为仓库开发工具,不在 mooncakes 对外面),建议进发版批三决策的已知缺陷清单,工程量不同可分开拍板
  3. 构建 cliff(cmd/run 链接 199s)是否上工具链债清单:随发版批拍板(§11.8)
  4. wasm 管线三场景 1.24× 翻转:0.6.0 前复跑定性(§11.7)——已定性(2026-09-29,§12.2):「不可复现、归因不可定」——同日方法对齐 A/B 下 0.5.0 与 HEAD 中位逐场景重合,两版本都没有 1.24×;本条按此销账。本轮唯一硬结论 = 执行层 wasm-gc 快 2-2.8×(新基线)
  5. §10 触发线核对:管线三维维持"记账不动手";时间旅行优化方案(§3)量化前提复验成立,仍按计划作为执行器批前置设计输入

12. S7 wasm-gc 单出口落地后复跑(2026-09-29,本地 HEAD 工作区)

AS-OF:2026-09-29 11:00-12:00。触发 = S7 批五号「wasm-gc 单出口落地」(2f18e10,gateway 建包 + Node 宿主)。 口径:被测 = 本地 HEAD 工作区(3a51667,与 2f18e10 仅差一个 docs 提交,代码同);机 = AMD Ryzen AI Max+ 395 / 16 核 32 线程 / Win11 build 26200(与 §1-§4 同机);moon 0.1.20260920;vitro/engine moon.mod = 0.6.0(0.7.0 发版批未执行);Rust 侧用现成 native/target/release/vitro_cli.exe(源无更新,find -newer = 0)。 探针纪律:产物全部落 tmp/perf_probe/(gitignore /tmp/ 覆盖),工作区零流入;本次新增探针与定标见 §12.8。 结论速览:①环境那一项已闭环——会话内进程创建 ~148ms 是本 agent 会话特有(会话外 3.5-5.0ms,同分钟对照),不用重启、不用改 VBS/HVCI/Defender;权威数字已在会话外整套复采;②**§11.9-4 已销账**:0.5.0 与 HEAD 在清环境下逐场景重合到 ±0.05 ⇒ 「管线 1.24× 翻转」判为 §11.7 当日测量假象;③编译管线没退化(tokens 0.357/ast 0.241/typeck 0.237/compile 0.275s,与 §1 重合);wasm-gc 侧 lexer 0.62-0.65、parser 0.80、GC 0.33-0.49 偏 wasm,typeck/codegen 持平;④执行层最硬:wasm-gc 跑完整引擎比 native 快 2.0× / 2.7× ⇒ §11.3 的「落后 6-16×」是 native 后端的性格;⑤**「大输入是 wasm 唯一弱项」与实测相反**:16× 点 wasm 0.70-0.74×、增长两侧都≈线性;⑥全栈对拍 360/6/0/0(va_copy 与自定义 include 两缺口已闭环);⑦时间旅行逐字复现(步数·每步·峰值内存),§3 方案量化前提成立;⑧moon build --release --target native 全量因 gateway +native 声明必失败(LNK1561),已定位到 moon 的通用行为并验证了拆包修法;⑨探针套件暴露并修掉一个真缺陷(subprocess(text=True) 依赖 UTF-8 环境变量,会话外必崩)。

12.1 环境:会话内进程创建开销(定案:会话特有;权威数字改用会话外采集)

度量 2026-09-26(实录/探针构建期) 2026-09-29 实测 倍率
vitro_cli.exe 启动(§11.2 记 5.8ms) 5.8ms 146.5ms 25×
探针 native exe 场景0(§11.7 记 12.2ms) 12.2ms 193.3ms 16×
moonrun 启动(§11.7 记 26.7ms) 26.7ms 159.5ms 6×
python -c pass — 358.0ms —
  • 不是沙箱:dangerouslyDisableSandbox 复测无改善(146.5 vs 148.8ms)。不是被测二进制的锅:2026-09-26 构建、当时记 12.2ms 的旧探针 exe 本次实测 193.3ms ⇒ 纯环境侧。
  • 本机当日 Defender RealTimeProtection=True / BehaviorMonitor=True / TamperProtected=True,另有 Androws*(Android VM)等第三方组件在跑——候选原因未定,效果确定。
  • 泄流型工具另有每文件写盘税:bench_pipeline 扣启动定标后仍偏高 ~1.8-2.3×(每轮写 366-732 个文件)。
  • 处置(已闭环):该开销只影响 agent 会话内部,机器本身正常(会话外 3.5-5.0ms),不需要重启、不需要改 VBS/HVCI/Defender。已在普通窗口用同一套探针整套复采(入口 tmp/perf_probe/run_all_user.cmd,日志 tmp/perf_probe/user_run_logs/),§12.2 / §12.4 / §12.5 的权威数字全部改用该批。会话内采集的绝对值永久作废、只作轨迹。
  • 方法学结论(入规程):该开销下唯一可靠形态 = 同进程内重复 + 同源空转场景自校准(wasm_bench 形态——加数与减数同源,开销对消)。禁用固定常数扣启动:该值在 140-190ms 间漂移 ±30%,<500ms 的测量做减法会翻符号(本次 run_cmp 的 fib 扣完变负即此)。

深挖追加(12:10-12:15,同环境):该开销不只是大,还会在一个 run 内漂,单点定标会被击穿。实测:同一 0.5.0 二进制同小时三次跑,parser 纯算 0.67/1.42/0.67(2× 抖动);HEAD 某轮把 lexer 纯算压成 2.4ms(真值 ~37ms),整轮作废。修法已验证:驱动器改成每个场景前后各测一次场景0、取两次均值作该场景基线(run_bench_head/run_bench2.py),drift 中位即落到 ±2-5ms,3 轮比值可复现(见 §12.2 修订表)。⇒ 探针学纪律:空转基线必须与被测场景同轮次交替测,不能整轮只测一次。

决定性对照(12:23,用户普通窗口):同一脚本 tmp/perf_probe/launch_cost.py 在普通 cmd 窗口(非 agent 会话)跑 ⇒ 114KB 4.6 / 2.5MB 6.0 / 7MB 4.7ms,CreateProcess 1.7ms、进 main 前 5.0ms、退 main 后 1.3ms;同一分钟本会话内复测仍是 145.3-151.4ms ⇒ 该开销是本 agent 会话的进程派生链特有的,不是机器策略。⇒ 撤回先前「VBS/HVCI × Defender 实时」的归因(那些策略在两侧完全相同,故不是原因)。本会话内的绝对值一律不得引用;干净数字必须在普通窗口采集(§12.9 给了整套入口)。

12.2 wasm-gc 场景(权威口径:会话外清环境 + 漂移控制 + 双版本 3 轮)

探针 tmp/perf_probe/wasm_bench_head/(新):依赖经 .mooncakes/vitro/engine 目录联接指向本地 moonbit/(HEAD),非 mooncakes 发布版。口径与 §4/§11.7 同题同法(外层计时 / 场景0 = 空转 / 扣启动 / 5 轮中位 / moonrun(V8·TurboFan) vs native exe)。场景 1-7 = 原管线面;场景 8-9 = 新增执行层 VM 面(run_vm:tokenize→parse→typeck→codegen→setup_from_output→vm.run());场景 10-12 = lexer 规模梯子(模块级预建的 1×/4×/16× 大输入,构造只进场景0)。

本节数字来自会话外清环境(普通控制台窗口,启动开销 3.5-5.0ms、drift ±1.4ms),两侧同用漂移控制版 run_bench2.py(每场景前后各测场景0取均值)、5 轮中位。会话内那几轮(单点定标、被 §12.1 的开销与漂移击穿)只作轨迹,不得引用。

A/B 对照(决定性,双版本各 3 轮,同一小时同一方法):用 mooncakes 0.5.0 的旧探针(tmp/perf_probe/wasm_bench/,2026-09-26 构建产物,即 §11.7 同源)与 HEAD 对跑:

场景(纯算 wasm/native) 0.5.0 三轮 0.5.0 中位 HEAD 三轮 HEAD 中位
1 lexer ×200 0.61/0.64/0.63 0.63 0.64/0.65/0.62 0.64
2 parser ×150 0.77/0.79/0.79 0.79 0.80/0.80/0.80 0.80
3 typeck ×100 0.96/0.96/0.96 0.96 0.98/0.97/0.94 0.97
4 codegen ×100 0.90/0.92/0.93 0.92 0.94/0.92/0.92 0.92
5 GC 压力 ×200 0.48/0.47/0.50 0.48 0.36/0.49/0.33 0.36
6 lexer 大输入 ×50 1.32/1.39/1.42 1.39 1.41/1.32/1.49 1.41

⇒ 两版本中位逐场景重合到 ±0.05(唯一 0.12 的差在 GC —— 该场景纯算仅 17-47ms,最短) ⇒ §11.7 的「三管线场景一致 1.24×」既非 0.4.0→0.5.0 的版本效应,也不可复现,判为当日测量假象。§11.9-4 按「不可复现、归因不可定」销账(§11.7 未记录绝对值,无法回溯是哪个环节偏了);不再写「HEAD 回到 0.71-0.98×」这种把噪声当结论的措辞。清环境下三轮逐位重复(多数场景 ±0.02),方法本身已可信。

HEAD 全场景(会话外清环境,漂移控制,纯算 wasm/native):

场景 §4(0.4.0) §11.7(0.5.0) HEAD r1/r2/r3 判定
1 lexer ×200 0.61× 0.71× 0.64/0.65/0.62 wasm 快 ~1.6×
2 parser ×150 0.79× 1.23× 0.80/0.80/0.80 wasm 快 ~1.25×
3 typeck ×100 0.95× 1.24× 0.98/0.97/0.94 持平(wasm 略优)
4 codegen ×100 0.89× 1.24× 0.94/0.92/0.92 持平(wasm 略优)
5 GC 压力 ×200 0.43× 0.65× 0.36/0.49/0.33 wasm 快 2-3×
6 lexer 大输入 ×50 1.23× 1.91× 1.41/1.32/1.49 wasm 慢 ~1.4×
8 VM 执行 fib(20) ×10 — — 0.49/0.49/0.49 🆕 wasm 快 2.0×
9 VM 执行 nested300 ×3 — — 0.37/0.37/0.36 🆕 wasm 快 2.7×
10 大输入 1× ×50 — — 1.33/1.28/1.32 wasm 慢 ~1.3×
11 大输入 4× ×50 — — 0.87/0.86/0.89 持平
12 大输入 16× ×50 — — 0.74/0.72/0.70 wasm 快 ~1.35×
  • 执行层最硬:场景 8/9 三轮分别 0.49/0.49/0.49 与 0.37/0.37/0.36(绝对值 100-500ms,远离噪声底)。wasm-gc 下跑完整引擎(S6 的 vm/host/memory 闭包,即 gateway 的 +wasm-gc 闭包)比 native 快 2.0× / 2.7× ⇒ §11.3 的「执行层落后 Rust 6-16×」是 native 后端的性格,不是引擎的性格。这条为路线裁定(wasm-gc 为主交付面)再添一手证据。
  • 管线层:持平或略优,不是反超。lexer 0.62-0.65(wasm 快 ~1.6×)、parser 0.80(~1.25×)、GC 0.33-0.49(2-3×)偏 wasm;typeck 0.94-0.98、codegen 0.92-0.94 基本持平。与 §4 的原始读数同量级(§4: lexer 0.61 / parser 0.79 / typeck 0.95 / codegen 0.89)⇒ 0.4.0→HEAD 之间这条线没有实质变化。
  • 「lexer 大输入是唯一弱项」不成立(方向相反):规模梯子 1× 1.28-1.41×(wasm 慢)→ 4× 0.86-0.89(持平)→ 16×(单输入 ~1.4MB)0.70-0.74×(wasm 快 ~1.35×)。增长指数:native 4×→16× 为 4.04×、wasm 3.36×(对 4× 输入)⇒ 两侧都接近线性,谈不上超线性;与 §4/§11.7 记的「wasm 超线性、native 亚线性」相反。1× 点(纯算 ≈12-18ms)仍靠近噪声底,只有 4×/16× 两点算硬;据此把 §10 的该遗留项改为「方向存疑、待复核」。
  • 启动(清环境):native 场景0 7.6-9.5ms / moonrun 17.1-18.0ms(§11.7: 12.2 / 26.7ms)。
  • 产物体积:探针 wasm 619KB / native exe 1,235KB。gateway 产物体积未复测(§4 的 -54% 口径不变)。

12.3 全 MoonBit 栈对拍(diff_moon_run_full.py,正确性面)

cmd/run(lexer→parser→typeck→codegen→VM 全栈)× baseline 366 例,逐例对拍 Rust vitro_cli run 的 stdout 行序列 + 返回码:

归类 §11.5(0.5.0) 本次(HEAD)
逐例一致 SAME 356 360
两侧同拒 6 6
MoonBit 拒 / Rust 成功 3 0
真语义 DIFF 1 0
  • §11.9 登记的两个缺口(va_copy 未生效、自定义 include 未闭环)均已闭环(apply_reply 幽灵栈值修复;cmd/run 的 SourceProvider 接线)。366 例无崩溃、无超时、无非预期差异。
  • 本口径不受 §12.1 环境开销影响结论(归类判据是 stdout/返回码,不是时间)。

12.4 管线 / 多维 / 压力(会话外清环境真值)

本节原为会话内虚高数字(全部作废,只留 §12.1 的轨迹)。以下为会话外清环境复采(两轮独立复跑)。

四层 dump 吞吐 baseline366(3 轮中位):tokens 0.357 / 0.370、ast 0.241 / 0.246、typeck 0.237 / 0.241、compile 0.275 / 0.280s。

  • 与 §1(0.37/0.26/0.26/0.30s)基本重合,比 §11.1(0.451/0.287/0.284/0.344s)更快 ⇒ 编译管线没有退化;层序形状一致,knr/leetcode/gap 按语料规模同比缩放。

多维对比(bench_compare.py):

项 本次(清环境) 实录对照 判定
段1 进程启动 rust/moon 4.0 / 9.7ms §11.2: 5.8 / 13.0ms(2.2×) ✅ 同向(2.4×)
段2 tokens 目录批处理 baseline rust 0.233 / moon 0.338s = 1.45×(moon/rust) §2: 0.24 / 0.35s = 1.4× ✅ 精确复现
段2 stress17 rust 0.589 / moon 1.254s = 2.13×(moon/rust) §11.2 注记 2.4× ✅ 同向
段3 compile 逐文件 baseline rust 中位 7.2 / moon 10.7ms = 1.49×(moon/rust);总 2.774 / 4.120s §11.2: 1.58×;§2: 1.5×;§8.1: 1.49× ✅ 比值精确复现(绝对值见下注)
段3 异常集合 rust 9 例 = 6 诊断 + include 族 3 §11.2 注记 9 例 ✅ 逐字同
段4 用户场景 compile 中位 6.4ms(p90 7.5)/ run 中位 8.0ms(p90 9.2) §2: 8.2 / 9.9;§11.2: 9.3 / 10.8 ✅ 同量级
段4 非 0 退出 6 例:e2_angle_local_header / e2_include_cycle / e2_include_not_found_angle / e2_include_not_found_quote / e3_static_assert_fail / j1_declarator_depth §2/§11.2 同 6 例 ✅ 逐字同
  • ⚠️ 一处跨日绝对值异常(登记):段3 的比值 1.49× 与 §8.1/§2 逐字吻合,但 rust 侧绝对值从 §11.2 的 15.2ms 降到 7.2ms(2.1×),moon 侧 9.4→10.7ms 基本不动。当前 native/target/release/vitro_cli.exe 的 mtime 是今日 10:58(find -newer = 0 ⇒ 二进制比全部 .rs 新,但**§11 之后被重建过**)。⇒ 比值可用,跨日绝对值不可直接比;要追究得比对两次构建的 flags。
  • 会话内那组方向是错的(段3 曾算成 0.93×):根因是会话不仅加启动税,对文件写入也加税,而 dump 类每轮写 366-732 个文件、两侧不等比放大。

压力五维(run_stress.py,dump vs dump 同口径,3 轮中位)——比值 = moon/rust(>1 = moon 慢):

维度(小→大) 本次 §11.6 判定
深嵌套 nest_4 → 14 1.71 → 1.55× 1.63 → 1.98× ✅ 同量级(趋势差在噪声内)
平铺 flat_500 → 8000 2.24 → 2.67× 2.05 → 3.14× ✅
巨体 body_500 → 50000 2.16 → 3.41× 2.10 → 3.80× ✅
大数组 arr_1000 → 10000 1.68 → 2.38× 1.57 → 2.09× ✅
局部变量 locals_1000 → 5000 2.50 → 3.08× 2.51 → 3.53× ✅
  • 设计性拒绝两侧同构复现:arr_50000(全局数据区 60KB)+ expr_1000/5000/20000(E1006)= 4 文件;MoonBit 走 fail_json(rc=0 + 产物 ok:false)、Rust rc=1 —— 与 §11.6 逐条同。
  • 执行层附加段(端到端 run,含编译):rust 16.6-84.9ms / moon 41.0-85.2ms,比值(moon/rust)1.00-3.10×;locals_5000 两侧持平(1.00×)而 nest_14 / arr_10000 达 3.10× ⇒ 形状依赖明显,样本仅 5 个,不作一般结论。

12.5 时间旅行与执行层(会话外清环境真值)

unified(单进程长跑,两环境同值 ⇒ 会话开销无关):

程序 CPython Rust unified 步数 每步 峰值内存
fib(20) 0.51ms 6.32s 284,591 22.20μs 29.0MB
冒泡 200 2.83ms 58.24s 1,621,540 35.92μs 47.8MB
500×500 13.90ms >75s 超时(--max-steps 5000000) — — 28.0MB
  • 与 §11.4(6.63s / 23.3μs;68.8s / 42.4μs;nested 超时;29.2 / 47.7 / 28.0MB)逐项吻合,步数逐字复现(284,591 / 1,621,540)⇒「每步 CPU 是病灶、内存温和」的裁定与 §3 优化方案的量化前提原样成立。

全速执行(3 轮中位):

程序 CPython Rust run MoonBit run MB/Rust 峰值(moon/rust)
fib(20) 0.51ms 17.9ms 33.4ms 1.87× 9.2 / 7.8MB
冒泡 200 2.83ms 20.0ms 132.3ms 6.60× 9.3 / 7.9MB
500×500 13.90ms 24.0ms 437.8ms 18.27× 9.2 / 7.9MB
  • 与 §11.3(22.5/22.6/30.2ms、43.0/142.7/475.3ms、比值 1.92 / 6.32 / 15.7×)吻合 ⇒ 「计算密集 6-16×」结论复现;峰值内存与 §11.3 的 9.2 / 7.8MB 逐字同。
  • baseline366 端到端 run:MoonBit 中位 13.1ms(p90 15.5,0 失败)/ Rust 7.8ms(p90 8.7,6 非 0)⇒ MoonBit/Rust = 1.68×(§11.3 记 1.42×,同向、略高)。会话内那组(153.7 / 155.0ms,比值 1.00×)纯属开销主导,作废。

12.6 gateway native 构建失败:根因隔离 + 修法验证(深挖,与性能无关)

  • 现象:cd moonbit && moon build --release --target native(全量)报 Failed with 131/218 warnings, 0 errors → Error: failed to run build for target Native / Caused by: failed when building project,EXIT=127。
  • 定位:C 层唯一错误 = LINK : fatal error LNK1561: 必须定义入口点,紧跟 正在创建库 ...\gateway\gateway.lib 之后;其余 5 个 cmd/* 目标全部编译链接成功(run.exe 冒烟 hi 42 通过)。两次全量构建复现(一次与其他会话并发、一次静默后独占),与并发无关。
  • 根因判断:moonbit/gateway/moon.pkg 声明 supported_targets = "+wasm-gc +native" + pkgtype(kind: "foreign_library"),但 native 后端对该包仍尝试链接可执行文件 ⇒ 无入口点 ⇒ LNK1561。
  • 为什么一直没暴露:ci.yml 只跑 moon build --release --target wasm-gc gateway(234 行)、--target native cmd/serve(223 行)、--target native cmd/run(310 行)——从不做全量 native release 构建,+native 声明从未被验证。
  • 影响:任何人按文档跑「全量 native 构建」(§11.8 的 151-294s 那条)现在都会失败;§11.8 构建时间口径本轮无法复测。局部构建不受影响。
  • 根因隔离(4 行最小模块):新建 tmp/perf_probe/fl_probe/(一个 foreign_library 包 + 一个 native executable 消费者,形态照搬 gateway / cmd-serve)⇒ moon build --release --target native lib 复现 LNK1561(0 warnings / 0 errors),而 --target native app(消费者)RC=0、--target wasm-gc lib RC=0。⇒ 是 moon 对 foreign_library 包单独做 native 构建的通用行为,与代码规模 / 警告数 / gateway 内容无关;也解释了 cmd/serve 为何一直没事(它只是消费方)。
  • 两条直觉修法均被证伪:
    • ① 去掉 +native → native 消费者立刻 Selected backend 'native' is incompatible with the dependency graph. 'app' requires 'lib' which supports [wasm-gc] ⇒ 不可行(cmd/serve 正是 native 消费者)。
    • ② pkgtype 改回默认 library → [4219] #export_name "hello" can only be used in a foreign library ⇒ 不可行(4 个导出面必须 foreign_library)。
  • ✅ 已验证修法 = 拆包(tmp/perf_probe/fl2/ 实测全程通过):核心逻辑放 library 包(supported_targets = "+wasm-gc +native",被 native 消费者与 wasm 外壳共用);另建一个只含 #export_name 面的 foreign_library 外壳,supported_targets = "+wasm-gc" 单目标。实测:全量 moon build --release --target native RC=0(10 tasks)、native 消费者冒烟输出 hi、--target wasm-gc wrap 产出 wasm 且导出面在;产物侧唯一 import 是 {"module":"_","name":"hi","kind":"global"}(importedStringConstants,非功能性 import)⇒ 不破坏 gateway 现有的「零功能性 imports」性质。
  • 落地牵连面(未动手):wasm 产物路径会从 .../build/gateway/gateway.wasm 变为外壳包路径 ⇒ scripts/wasm_gateway/host.js 默认路径 + ci.yml(234 行)要同步;新包须进 scripts/moonbit/pkg_deps 的 L8 登记、mbti_sync、moonbit_surface 白名单/边表;moonbit CHANGELOG/README 包图连坐。⇒ 这是一批活而非一行修,故本轮只交验证过的配方,不擅自重构。
  • 无论选哪条路,CI 都应补一条全量 native release 构建门——本次漏检的根因就是「声明了 target 却没有任何步骤构建它」。
  • 上游定位与提 issue 判断(2026-09-29 查证):
    • 官方 v0.10.4 发布说明已写明「native 后端编译静态/动态库仍在打磨,该特性目前主要面向 Wasm/JS 后端」;第三方项目 XiLaiTL/moobile(docs/EVIDENCE.md)也撞到同一处并记为「与官方文档所述一致」,绕法是自编生成的 C。⇒ 「native 不支持 foreign_library」不是未知缺陷,不提(提了会被当 known 关掉)。
    • 但症状中有一块文档没覆盖,值得提一条窄口径 issue:①supported_targets = "+native" 被 moon check --target all 静默接受,只在 C 链接阶段炸;且与编译器无关——MOON_CC=clang 下同一模块失败,只是换成 lld 的措辞 lld-link: error: subsystem must be defined;②爆炸半径 = 整个模块:模块内只要有一个 foreign_library(哪怕没有任何 native 可执行文件链接它),模块级 moon build --release --target native 就整体失败 ⇒ 一个 wasm-gc 库产物会毒化全模块的 native 构建;③对照:同形状的纯 library 包(全新模块、同样 +wasm-gc +native)单独 native 构建 RC=0 且不进链接步骤(只产 .core/.mi),而 foreign_library 会先产 .lib/.obj/.exp 再跑一次 exe 链接 ⇒ 差别只在 pkgtype;最小复现只需 3 个文件(tmp/perf_probe/flmin/)。
    • 建议口径:只请求「早失败/清晰诊断(像现有的 Selected backend 'native' is incompatible with the dependency graph 那样) + 不毒化整模块」,不要写成「请实现 native foreign_library」。草稿备于 tmp/perf_probe/moon_issue_draft_foreign_library_native.md(未提交)。
    • 源码级定位(2026-09-29,浅克隆 moonbitlang/moon @ 22eb0ba):①crates/moonutil/src/package.rs 的 PackageKind + 遗留 force_link;②build_lower/lower_build.rs:204-211 由 is_main/force_link 反推 pkgtype;③build_lower/compiler/build_common.rs:247 把 -pkg-type 传给 moonc——仓库自己的 dummy_core/bundle_all_targets.jsonl.snap:9 就证明 -target native 也照发 -pkg-type foreign_library,且 moonc 接受了;④计划层为它生成 ArtifactKey::Executable,最终落到 compiler/msvc.rs:68 link_executable_command(调用点 lower_build.rs:1204)——LNK1561 就在这一步。⇒ PR #1877 正文写明「native 的拒绝留给 moonc」,而 moonc 没拒绝 = 契约缺口(不是「功能没做完」)。
    • 关联检索(确认无重复):#1877(merged,即上述契约来源)/ #2251(open,DSL 迁移跟踪,与 #1877 同作者)/ #1887(open,native 库链接参数语法)/ #992(closed,link_configs)/ #2195(closed,MSVC 本地化输出乱码——我们看到的 LNK1561: ���붨����ڵ� 乱码错误文本就是它,已修)。提 issue 地点 = moonbitlang/moon(与 §11.8 的 #2254 同仓库)。
    • PR 判断(是否替上游动手):先提 issue 带定位,PR 等上游确认语义。修法有两种互斥语义:①拒绝(与 #1877 「留给 moonc」一致,但会让「wasm 导出 + native 消费」组合彻底无解)②native 下按 library 处理(我们的场景直接可用,但等于替未完成特性开路)——选哪条是上游的设计决定,猜错等于白干;且 moon 集成测试是 jsonl.snap 快照制,改行为要连锁重生成,本机还需完整 Rust 工具链构建。⇒ 性价比最高的贡献 = issue 里给到源码定位 + 3 文件复现(上游从 issue 到修复可能只要几分钟),并在 issue 里主动提出「确认语义后我可提 PR + 测试」。
    • 提交时机(2026-09-29 拍板):草稿已就绪但暂缓提交——国庆+中秋连休窗口(约 13 天),上游本就零响应(#2254 提交 3 天 0 评论 0 标签),假期内提交只是排队。随手可发:tmp/perf_probe/moon_issue_draft_foreign_library_native.md 即可粘贴终稿。关键点:最小复现是独立 3 文件模块(tmp/perf_probe/flmin/),不依赖本仓库任何代码 ⇒ 本条不受仓库正在进行的 gateway/serve/CI 修复批影响,无需重新取证。

12.7 本轮方法学坑(已入 .agents/skills/vitro-workspace-review/references/04-工具链与踩坑.md)

  1. safe-delete 钩子拦探针的 rmtree:bench_pipeline / run_stress 首跑 RC=1,stderr [safe-delete][SAFE_DELETE_BULK_CONFIRM_REQUIRED] {"count":739,"threshold":50,"scope":"turn"}——每轮删除输出目录在文件数 >50 时被拒,且同 turn 内逐次删除累计计数。处置:删除全部改为 os.rename 改名让位(*_old_<ns>),语义等价(每轮仍是空目录),已写入两个脚本。⇒ 以后写探针不要用删除做目录复位(记 04-D5)。
  2. 机器级启动开销(§12.1):逐进程口径失效;自校准形态是唯一可靠出路(记 04-C8)。
  3. 禁用固定常数扣启动(±30% 漂移会翻符号,同上条)。
  4. moon.mod 的 import 必须带版本号:import { "vitro/engine" } ⇒ moon.mod only supports versioned registry dependencies;本地工作区依赖的正确接法 = "vitro/engine@<本地 moon.mod version>" + .mooncakes/vitro/engine 目录联接(记 04-A17)。
  5. MSYS bash 的 fork 本身很贵(ls ×10 ≈ 350ms/次级别)⇒ 别用 date +%s%N 包 bash 循环测进程启动(记 04-C9)。

12.8 复跑资产

资产 位置 复跑
wasm-gc 场景探针(新,本地 HEAD 依赖 + 执行层 + 规模梯子) tmp/perf_probe/wasm_bench_head/ python run_bench.py(原版) / python run_bench2.py(漂移控制版,推荐);BENCH_NATIVE_EXE / BENCH_SCENES / BENCH_ROUNDS 可覆盖
0.5.0 旧探针(方法对齐 A/B 用) tmp/perf_probe/wasm_bench/ 已拷入 run_bench2.py: BENCH_SCENES=1,2,3,4,5,6 python run_bench2.py
工具启动定标(新) tmp/perf_probe/calib/calib.json 见 §12.4 口径
tokens 层形状取证(新) tmp/perf_probe/tokens_dig.py PERF_RUNID=<id> python tokens_dig.py
gateway 根因最小模块(新) tmp/perf_probe/fl_probe/(foreign_library+双 target)/ fl2/(拆包方案) 各自 moon build --release --target native [pkg]
启动开销时间戳探针(新) tmp/perf_probe/stamp/(Go,main 入口打时间戳) go build -o stamp.exe .
其余 6 套(原样) tmp/perf_probe/{bench_pipeline,bench_compare,run_stress,bench_moon_run,diff_moon_run_full}.py、ext_cmp/run_cmp.py 各脚本头注;PERF_RUNID=<id> 规避 safe-delete
本轮原始日志 tmp/perf_probe/{suite_20260929,suite2_20260929,bench_head_run1..3,bench_cc_compare,bench_ab_050_vs_head,ab_old_drift,dig_20260929}.log、env_diag.txt、fingerprint.txt —
  • 改动 2 个原探针脚本(bench_pipeline.py / run_stress.py)的目录复位方式(删除 → 改名),口径未变;改动原因与语义等价性见 §12.7-1。
  • 前置注意:全量 native release 构建会撞 §12.6 的 LNK1561,需逐目标构建(moon build --release --target native cmd/run 等)。
  • 新增驱动器 run_bench2.py 与旧版并存:旧版仅作轨迹保留,新结论一律引 run_bench2(漂移控制)。

12.9 深挖:进程启动开销归因(只读取证)

  • 量级见 §12.1。尺寸无关:clang 自编的 114KB tiny.exe(空 main)与 7MB vitro_cli.exe 同价,moonrun 也同价。父进程无关:python 父与 PowerShell 父同价 ⇒ 不是 Python/MSYS 的 spawn 路径问题。
  • 拆开看:CreateProcess 返回 ≈ 22.6ms(尺寸无关);进程创建 → 子进程进 main ≈ 125ms;main 出口之后 ≈ 3ms。用一个在 main 入口打印 time.Now() 的 Go 探针(tmp/perf_probe/stamp/)做时间戳锚 ⇒ ~148/151ms 全部花在「进 main 之前」(映像加载 + 扫描),不在退出路径,也不在被测程序的计算里(空 main 一样付)。
  • 无预热收敛:同一 exe 连发 12 次,min/med/max = 144.3/159.8/239.3ms,不随重复下降 ⇒ Defender 常见的「扫一次后按哈希缓存」在此不成立;本机 Get-MpPreference 的 EnableFileHashComputation = False,与该现象相容。
  • 签名无关:微软签名的系统 exe(System32\hostname.exe 150 / where.exe 146.7ms)与自编未签名(114KB 144.4ms)、7MB Rust(149.4ms)同价 ⇒ 不是针对第三方二进制的签名/信誉校验,而是每次进程创建都付的统一成本(微软自家签名系统工具也不例外)。
  • 环境侧(仅作背景,已非归因):SecurityCenter2 只注册 Windows Defender 一个 AV(RealTime / BehaviorMonitor / TamperProtection / NIS 全开,AMRunningMode = Normal),无第三方 AV/EDR 滤镜驱动;VBS 在运行(VirtualizationBasedSecurityStatus = 2)且 HVCI / 内存完整性在运行(SecurityServicesRunning = 2);bindflt(Windows Bind Filter Driver)Running/Auto;无内存压力(63.6GB 中空 35.1GB,页面文件 71/4096MB,CPU 4%);Smart App Control 关闭(VerifiedAndReputablePolicyState = 0,非 SAC)。
  • 归因已改(决定性对照):同一脚本在普通 cmd 窗口跑 ⇒ 114KB 4.6 / 2.5MB 6.0 / 7MB 4.7ms、CreateProcess 1.7ms、进 main 前 5.0ms、退 main 后 1.3ms;而同一分钟在本会话内复测仍是 145.3-151.4ms ⇒ 该开销是本 agent 会话的进程派生链特有的。上面那些策略(VBS/HVCI/Defender 实时)在两侧完全相同,故不是原因——先前按「特征相符」做的归因已撤回,保留取证供后来者对照。⇒ 不需要为本项重启机器(机器本身 4.6-6.0ms,正常)。
  • 会话内绕不过(已穷举):CREATE_NO_WINDOW 168.5 / DETACHED_PROCESS 145.1 / CREATE_NEW_CONSOLE 489.6ms(⇒ 控制台分配不是主因,但它本身也贵) / dangerouslyDisableSandbox 无效 / WMI Win32_Process.Create、Start-Process、cmd /c 均被工具策略拦截 ⇒ 未能从会话内建立干净的派生链。最可能的机制是 agent 注入层(同层的 safe-delete 钩子已实证注入进 Python 内部并劫持 os.remove),但证据只到「会话特有」,机制未坐实。
  • 处置(已执行):①不要为本项重启(机器本身正常);②已在普通窗口跑完整套 tmp/perf_probe/run_all_user.cmd,日志落 tmp/perf_probe/user_run_logs/,§12.2 / §12.4 / §12.5 已改用该批真值;③基线对照:launch_cost_pre_reboot.txt(会话内 144.2 / 22.5 / 151.4 / 2.9ms)vs 清环境(3.5-5.0ms / CreateProcess 1.4-1.6ms / 进 main 前 4.0-4.9ms / 退 main 后 1.1-1.3ms)。不要据此判「引擎变慢」。

12.10 深挖:tokens 层形状差异(解释 §12.4 的方向矛盾)

工具 tmp/perf_probe/tokens_dig.py(逐文件 dump-tokens 单侧计时;n=5 中位)。

口径自警(重要):本表整体在会话内采集,且用固定常数扣启动(§12.1 已判其脆弱)⇒ 只作方向性参考;权威口径见 §12.4 的清环境压力五维(同一批语料、dump vs dump)。

语料 KB MoonBit 扣后 Rust 扣后 比值
body_500 6.9 23.9ms -13.7ms 噪声底,不可比
body_5000 68.4 59.8ms 3.8ms 噪声底,不可比
body_50000 683.7 509.5ms 201.6ms 2.53×
flat_500 / flat_2000 18.7 / 74.9 30.8 / 79.1ms -4.8 / 5.3ms 噪声底
flat_8000 303.5 198.1ms 58.8ms 3.37×
locals_5000 162.8 102.8ms 17.7ms 5.81×
arr_1000 / arr_10000 3.9 / 38.2 21.2 / 46.9ms -14.9 / -2.7ms 噪声底
  • 方向差异的成因 = 语料形状(清环境复核):baseline 是 366 个小文件(MoonBit/Rust 1.45×),stress17 由大文件主导(2.13×)——两侧都是 MoonBit 更慢,只是小文件批量时差距小一半;大文件上逐字节差距显形,且差距随形状变(locals 最差)。⇒ 会话内那次把它读成「小文件 moon 更快(1.20×)」是写盘税不等比放大造成的假方向,已作废。
  • 但不支持「超线性」:body 梯子(6.9KB→68.4KB→683.7KB)MoonBit 为 23.9→59.8→509.5ms,每 10× 尺寸为 2.5× / 8.5× 时间(指数 ≈ 0.93-1.0)⇒ 近似线性。与 §2/§11.6「差距随规模拉大」相容,但那是常数因子随形状变化,不是复杂度变化 —— 该措辞宜统一。
  • 与 §12.2 的 16× 梯子合看(那里 native 4×→16× 略超线性、wasm 近似线性):两处都表明「增长指数」不是稳定结论,单点噪声太大,维持待复核,不翻案。

12.11 遗留与拍板项(2026-09-29,会话外复采后更新)

  1. 环境启动开销(§12.1/§12.9):已闭环 —— 定案为本 agent 会话特有(会话内 ~148ms / 会话外 3.5-5.0ms,同分钟对照),不需要重启、不需要动 VBS/HVCI/Defender;整套探针已在普通窗口复采,权威数字见 §12.2/§12.4/§12.5。⇒ 后续任何「逐进程」口径,一律在会话外采集(入口 tmp/perf_probe/run_all_user.cmd)。
  2. gateway +native(§12.6):两条直觉修法(去 +native / 改 library)均已实测证伪;拆包配方已实测通过(library 核心 + wasm-gc-only 外壳:全量 native RC=0、导出面在、消费者冒烟过)。现在只剩「是否落地」+ 落地时的连坐清单(host.js / ci.yml / pkg_deps / mbti / surface / 包图),并建议同时补一条 CI 全量 native release 构建门。
  3. §11.9-4 已销账:0.5.0 与 HEAD 在清环境下逐场景重合到 ±0.05(§12.2)⇒ 「三管线场景 1.24× 翻转」判为 §11.7 当日测量假象,按「不可复现、归因不可定」关闭。本轮硬结论 = 执行层 wasm-gc 快 2.0× / 2.7×(场景 8/9 三轮全 0.49 / 0.36-0.37),以此作新基线;管线层:lexer 0.62-0.65、parser 0.80、GC 0.33-0.49 偏 wasm,typeck/codegen 持平。
  4. lexer 大输入方向存疑(§10 遗留项改写):1× 慢 1.28-1.41×,但 4× 持平、16× 反超到 0.70-0.74×(单输入 ~1.4MB)⇒ 「大输入是 wasm 唯一弱项」与实测相反;增长指数两侧都≈线性(native 4.04× / wasm 3.36× 对 4× 输入),不存在「wasm 超线性」。维持「待复核」,不翻案。
  5. 压力三维(locals/flat/body)维持「记账不动手」:清环境比值 locals 3.08× / body 3.41× / flat 2.67×(§11.6: 3.53 / 3.80 / 3.14),同量级;触发线(真实场景端到端 >100ms)未越。
  6. 跨日绝对值异常(新,登记待查):段3 逐文件 compile 的 rust 侧绝对值 15.2ms → 7.2ms(moon 侧 9.4→10.7ms 不动),而比值 1.49× 与 §8.1 逐字吻合;当前 vitro_cli.exe 是今日 10:58 构建的产物 ⇒ 怀疑 §11 之后 oracle 被重建过(flags 未知)。比值可用、跨日绝对值不可比。

13. S8 收官批全量性能复跑 + HEAD vs 0.7.0 同时段 A/B(2026-10-04,本地 HEAD 工作区)

AS-OF:2026-10-04 13:00-13:35。触发 = 新版本(S8 收官批,HEAD c3351d6)全量性能验证。 口径:被测 = 本地 HEAD 工作区(c3351d6,moon.mod 仍 0.7.0);A/B 对照 = tag vitro-engine-0.7.0(git archive 到 tmp/perf_probe/ab070_tree/ 重建);机 = AMD Ryzen AI Max+ 395 / 16C32T / Win11(与 §1-§4/§12 同机);moon 0.1.20260920;Rust oracle = native/target/release/vitro_cli.exe(Oct 3 22:06,find -newer = 0)。 探针纪律:产物全部落 tmp/perf_probe/(gitignore /tmp/ 覆盖),工作区零流入;当日工作区另有用户并发的 demo 改动(7 文件 + 2 新增),本批零触碰。 结论速览:①无回归 —— 同小时交替 A/B(HEAD vs 0.7.0,5 轮)四层管线 0.86-1.01×、执行层计算密集三程序 0.99-1.08×,新版与上一发布版性能等价;②§12 全部比值基线复现(wasm/native 11 场景、时间旅行每步、执行层缺口、压力五维、moon/rust 逐文件 1.50 vs 1.49);③全栈对拍 361/6/0/0(语料 +1);④方法学新增:会话启动税(§12.1)可用 Windows 计划任务绕开 —— 派生链脱离 agent 注入层,启动开销回落 6.3ms(会话内 168ms),不必再人工开普通窗口;⑤低轮次中位在本机当前噪声下极脆(首轮冷启动 + 周期性尖峰),复采一律 ≥5 轮。

13.1 方法学:绕开会话启动税(可复用,替代 §12.1 的「必须人工开窗口」)

§12.1/§12.9 定案「agent 会话内进程创建 ~148ms、权威数字必须在普通窗口复采」。本轮实测给出无需人工开窗口的等价手段:把探针套件交给 Windows 计划任务跑。

派生链 114KB tiny 7MB vitro_cli 进 main 前
agent 会话内(bash → python → 子进程) 166.7ms 168.4ms 166.7ms
Windows 计划任务(Task Scheduler 派生) 5.0ms 6.4ms 4.6ms
§12.9 普通 cmd 窗口(对照) 4.6ms 4.7ms 5.0ms
  • 做法:PowerShell Register-ScheduledTask(-Execute <python> -Argument <脚本> -WorkingDirectory D:\code\Vitro)+ Start-ScheduledTask。任务由 Task Scheduler 服务派生,不在 agent 进程树内 ⇒ 不继承会话注入层。
  • 编排器 tmp/perf_probe/run_suite_clean.py:把 §12.8 的 8 组探针串成一发(可 --steps/--rounds 裁剪),日志落 user_run_logs_clean/<stamp>/,末尾写 DONE.txt 供轮询。
  • 坑:cmd /c / Start-Process / WMI Win32_Process.Create 在工具策略下被拦,Register-ScheduledTask 可用(且 cmd.exe 从 Bash 调用一律被拦,故编排器写成 Python 而非 .cmd)。

13.2 同时段 A/B:HEAD(S8) vs 0.7.0(决定性)

脚本 tmp/perf_probe/ab_head_vs_070.py(每轮 A/B 交替,5 轮),baseline367 同语料同口径,同一小时内:

项 A=HEAD B=0.7.0 A/B
dump_tokens 0.393s 0.408s 0.96×
dump_ast 0.247s 0.255s 0.97×
dump_typeck 0.240s 0.278s 0.86×
dump_compile 0.305s 0.301s 1.01×
run fib(20) 38.5ms 35.7ms 1.08×
run 冒泡200 138.9ms 137.1ms 1.01×
run 500×500 449.9ms 452.9ms 0.99×
run baseline 前 80 例(端到端) 1.041s 0.899s 1.16×
  • 四层管线 0.86-1.01×(HEAD 不慢于 0.7.0);计算密集执行 0.99-1.08×(等价)。⇒ S8 批未引入可测回归。
  • 唯一 >1.1 项(baseline 80 例端到端 1.16×)由进程启动主导(80 进程 ×~10ms),且为整段 sweep 交替(非逐例交替),段内漂移可致偏 ⇒ 不作结论,登记(§13.8-3)。
  • 旁证:dump 工具 exe 体积 HEAD/0.7.0 逐一相同(637440 / 930304 / 366592 / 821760),但 moonc 把绝对源路径写进 #line(§11.8 已录)⇒ 哈希必然不同,哈希不可判等,只能实测。

13.3 四层管线 + 多维(vs §12.4)

run_suite_clean.py 的 3 轮版本中位被尖峰污染(tokens baseline 1.223s),重采 5 轮 ×2 次:

层(baseline367,3-5 轮中位) 复跑 r1 复跑 r2 A/B 的 A 列 §12.4 判定
dump_tokens 0.429s 0.417s 0.393s 0.357 / 0.370s ✅ 同量级
dump_ast 0.296s 0.283s 0.247s 0.241 / 0.246s ✅
dump_typeck 0.299s 0.261s 0.240s 0.237 / 0.241s ✅
dump_compile 0.358s 0.397s 0.305s 0.275 / 0.280s ✅
  • 首轮冷启动 + 周期性尖峰是主噪声源:rounds 常现 [1.6, 0.28, 0.30, 0.31, 0.25] 形态(首轮 ~5×),3 轮中位会被尖峰抬 2-3×。⇒ 复采纪律:≥5 轮(bench_pipeline.py 默认 3 轮建议改 5)。
  • 语料 baseline = 367 例(165KB)(§12 时 366,+1 新例);knr 81 / leetcode 138 / gap 17。
  • 多维(02 步):段1 启动 rust 6.0 / moon 13.7ms = 2.28×(§12.4 2.4×);段3 逐文件 compile moon/rust 总耗时 1.50× / 1.51×(§12.4 1.49×),单文件中位 rust 8.9-9.2 / moon 13.6-13.7ms;段4 用户场景(Rust-only)compile/run 中位 10.1 / 10.9ms(§12.4 6.4 / 8.0 系当日 oracle 重建后的低值,§11.2 为 9.3 / 10.8 ⇒ 本轮与 §11.2 更近);非 0 退出 6 例逐字同。
  • 段2(tokens 目录批处理)本轮 2 轮中位 moon 0.68-0.72s,比同操作的 01 步 5 轮中位(0.417-0.429s)高 1.6-1.7× ⇒ 该段只有 2 轮且复用同一输出目录,尖峰即翻倍,本环境不可信;需要 tokens 批处理比值时以 01 步 5 轮为准。

13.4 wasm-gc 双后端(vs §12.2)

wasm_bench_head(依赖经 .mooncakes/vitro/engine 目录联接指向本地 HEAD;旧副本系 0.6.0 陈旧拷贝,已改名让位)双后端 ×3 轮(场景 0 前后自校准 / 5 轮中位):

场景(纯算 wasm/native,<1 = wasm 快) 本轮 r1 / r2 / r3 §12.2(HEAD) 判定
1 lexer ×200 0.64 / 0.59 / 0.59 0.62-0.65 ✅
2 parser ×150 0.77 / 0.75 / 0.72 0.80 ✅
3 typeck ×100 0.90 / 0.98 / 0.93 0.94-0.98 ✅
4 codegen ×100 0.92 / 0.93 / 0.97 0.92-0.94 ✅
5 GC 压力 ×200 0.47 / 0.44 / 0.46 0.33-0.49 ✅
6 lexer 大输入 ×50 1.15 / 1.25 / 1.47 1.32-1.49 ✅
8 VM 执行 fib(20) ×10 0.51 / 0.49 / 0.50 0.49 ✅ wasm 快 2.0×
9 VM 执行 nested300 ×3 0.36 / 0.36 / 0.38 0.36-0.37 ✅ wasm 快 2.7×
10 / 11 / 12 大输入 1× / 4× / 16× 1.28 / 0.86 / 0.75 1.28 / 0.86 / 0.70 ✅
  • 启动 native 场景0 9.5-10.8ms / moonrun 20.4-22.7ms(§12.2 7.6-9.5 / 17.1-18.0,同量级略高);产物体积 wasm 622,279B / native exe 1,238,528B。
  • 方法对齐对照(0.5.0 旧探针,同小时)lexer 0.65/0.62/0.64、parser 0.89/0.78/0.80、typeck 1.06/0.99/1.18、codegen 0.94/1.04/0.98、GC 0.48/0.47/0.47、biglex 1.33/1.34/1.28 —— 与 §12.2 的 0.5.0 列(0.63/0.79/0.96/0.92/0.48/1.39)重合 ⇒ 方法本身可信,§11.9-4 的销账维持。
  • 执行层最硬结论沿用:wasm-gc 跑完整引擎比 native 快 2.0× / 2.7×(场景 8/9 三轮全 0.49-0.51 / 0.36-0.38)。

13.5 时间旅行 + 执行层(vs §12.5)

口径补注(2026-10-04 复核,补前文未写明):下表 unified 三列是 Rust oracle(vitro_cli unified,冻结区)的实测,不是 MoonBit 侧——探针(ext_cmp/run_cmp.py 线 3)只测过 Rust unified,moonbit/cmd/ 亦无 unified 入口。⇒ MoonBit 引擎的时间旅行至今无任何实测数字;MoonBit 侧已按 ⑤-5.1 拆掉每步 1MB 全量快照(time_travel/engine.mbt:155/253,Trap 回退改「检查点+正向重放」),但该改造的效果从未被量过。引用本节数字时勿当作「MoonBit 引擎的时间旅行性能」;测法与缺口见 §14。

程序 CPython Rust run MoonBit run MB/Rust unified 步数 每步 峰值
fib(20) 0.51ms 20.8ms 36.2ms 1.74× 6.48s 284,591 22.76μs 28.9MB
冒泡 200 2.07ms 21.0ms 135.2ms 6.43× 61.81s 1,621,540 38.12μs 48.0MB
500×500 14.24ms 28.3ms 447.1ms 15.80× >75s 超时 — — 27.5MB
  • 与 §12.5(22.20 / 35.92μs;29.0 / 47.8MB;1.87 / 6.60 / 18.27×)逐项吻合,步数逐字复现(284,591 / 1,621,540)⇒「每步 CPU 是病灶、内存温和」的裁定与 §3 优化方案量化前提原样成立。
  • baseline367 端到端 run:MoonBit 中位 16.1ms / Rust 9.7ms = 1.66×(§12.5 1.68×)。

13.6 压力五维(vs §12.4,run_stress.py dump vs dump 同口径,3 轮中位)

维度(小→大,比值 = moon/rust) 本轮 §12.4 判定
深嵌套 nest_4 → 14 1.72 → 1.67× 1.71 → 1.55× ✅
平铺 flat_500 → 8000 2.11 → 3.11× 2.24 → 2.67× ✅
巨体 body_500 → 50000 1.80 → 3.25× 2.16 → 3.41× ✅
大数组 arr_1000 → 10000 1.94 → 2.46× 1.68 → 2.38× ✅
局部变量 locals_1000 → 5000 2.57 → 3.47× 2.50 → 3.08× ✅
  • 设计性拒绝两侧同构复现:arr_50000(全局数据区 60KB)+ expr_1000/5000/20000(E1006)= 4 文件;MoonBit 走 fail_json(rc=0 + 产物 ok:false)、Rust rc=1 —— 与 §11.6/§12.4 逐条同。
  • 执行层附加段(端到端 run,含编译)moon/rust 0.99-2.99×(§12.4 1.00-3.10×),形状依赖同前;locals_5000 两侧持平(0.99×)。

13.7 正确性:全 MoonBit 栈对拍(非性能面,一并复核)

cmd/run(lexer→parser→typeck→codegen→VM)× baseline 367 例,逐例对拍 Rust vitro_cli run 的 stdout + 返回码:

归类 §12.3(366 例) 本轮(367 例)
逐例一致 SAME 360 361
两侧同拒 6 6
MoonBit 拒 / Rust 成功 0 0
真语义 DIFF 0 0
  • +1 SAME 即新语料例;§11.9 两缺口(va_copy / 自定义 include)保持闭环,366→367 例无崩溃无超时无非预期差异。

13.8 遗留与登记

  1. 低轮次中位脆(首轮冷 + 周期尖峰):§12 口径「3 轮中位」在本机当前状态下会被抬 2-3×;后续复跑一律 ≥5 轮。
  2. tmp/perf_probe/out/ 持续膨胀(本轮后 7.1GB、含 893 个 *_old_* 陈旧目录)——改名让位法只改名不清理(§12.7-1),长期需一次性清理;不影响任何结果(计时只覆盖被测 exe)。
  3. baseline 端到端 A/B 1.16× 未定(启动主导 + 整段 sweep 非逐例交替),登记待「逐例交替」复测;计算密集三程序已证等价,故不作回归线索。
  4. 跨日绝对值不可比已知项再确认:§12.11-6 的 oracle 重建疑云 + 本轮环境抬升(同时段 A/B 显示 HEAD 本身 0.393/0.247/0.240/0.305,比同日 01 步 5 轮中位低 5-20%)⇒ 判据永远是比值或同时段 A/B,不是跨日绝对值。
  5. 压力三维(locals/flat/body)维持「记账不动手」:触发线(真实场景端到端 >100ms)未越。§10 遗留项(wasm 大输入方向、SpiderMonkey/JSC 口径)状态不变。

13.9 复跑资产

资产 位置 复跑
干净派生链编排器(新) tmp/perf_probe/run_suite_clean.py 计划任务:-Execute <py> -Argument "tmp\perf_probe\run_suite_clean.py --stamp <s> [--steps 01,02] [--rounds 5]";会话内直接跑无效(启动税)
HEAD vs 0.7.0 A/B(新) tmp/perf_probe/ab_head_vs_070.py + tmp/perf_probe/ab070_tree/(tag vitro-engine-0.7.0 经 git archive 重建树) AB_ROUNDS=5 python ab_head_vs_070.py(须计划任务)
本轮日志 tmp/perf_probe/user_run_logs_clean/20261004_{head,r1,r2}/、tmp/perf_probe/ab_out/ab_ab.log —
其余 8 套 同 §12.8(bench_pipeline / bench_compare / run_stress / ext_cmp/run_cmp.py / bench_moon_run / diff_moon_run_full / wasm_bench_head / wasm_bench) 各脚本头注

前置:全量 moon build --release --target native 本轮 35 tasks / 0 errors / 5m46s 通过(gateway 拆包后全量 native 门成立,§12.6 已闭环);cmd/run 仍受 MSVC cliff 支配(§11.8)。

14. 时间旅行优化现状 + JIT 正交性(2026-10-04 复核,代码级)

触发:用户问「时间旅行如何优化 / JIT 要不要重启」。本节是读码 + 文档交叉复核结论,无新实测(实测缺口见 §14.2)。

14.1 §3 处方的落地状态(MoonBit 侧 = 存续实现)

§3 处方(按杠杆排序) 状态 证据
② checkpoint + 确定性重放 ✅ 已落 time_travel/engine.mbt:155「不再每步拍 1MB 全量快照(Rust engine.rs:169-170 的 pre_step_snap 机制」+ :253「⑤-5.1:无每步快照(pre_step_snap 不迁)」+ :366 rollback_before_trap(检查点+正向重放到 trap 前一步);S8 三段-c(2026-10-01)
④ 语句边界粒度 + 环形历史窗口(次要) △ 窗口已落 / 粒度未改 环形窗口:time_travel/window.mbt FrameWindow(@deque 两端 O(1) 摊还,参数 2_000/0.2 逐字保留)已落;但 engine.mbt:254 仍是 match vm.step() 之后每指令步一次 collect——语句边界粒度未做(§3「教学单步语义是语句级,指令级全量记录无消费方」原话)
① 按需物化(原「主攻」) ❌ 未做 time_travel/collector.mbt:71 collect 仍无条件每步构建完整 StepPayload(local_vars + pointer_snapshots + 语义标签 + 算法推断;照搬 Rust collector.rs)
③ 写集 undo log ❌ 未做 time_travel/*.mbt 全量 grep undo / 旧值 / AccessType 零命中

⇒ 「消每步 1MB 快照」已兑现(常态 O(1MB)→O(1),trap 帧 O(interval));剩余大头 = 每步 collect 的对象构建——与 §3 原判「真病灶是每步 CPU(collector 无条件重建快照对象)」同址。

14.2 实测缺口(补测前任何「要不要做 ①」都是脑测)

  • MoonBit 侧时间旅行零实测:§3/§12.5/§13.5 的全部 unified 数字(21 / 22.76 / 38.12μs 每步)都是 Rust oracle;moonbit/cmd/ 只有 run/serve,无 unified 入口,探针从未测过 MoonBit 侧(见 §13.5 口径补注)。
  • 两个测法:(a) 临时探针模块直调 UnifiedEngine::run_batch(照 tmp/perf_probe/wasm_bench_head 形态:junction 到本地 moonbit/ + moon build --release --target native)→ 干净的 μs/步;(b) 驱动 cmd/serve step 族数 N 步 → 含 wire 开销,只能当上界。建议 (a),并把它并成 scripts/perf_baseline 的新 mode(复用刚入库的留证机制,§13.9)。
  • 不要动 Rust 侧:native/ 是冻结的 diff oracle 且 0.9.0 脱钩、1.0 退役——优化它零收益。

14.3 验收线须产品定

优化须可证伪,例如「任意教学程序整段回放到末尾 ≤3s」。当前无此目标,故 §3 当时给的量化目标(每步 21μs→<0.5μs)只是工程目标,不是验收线(§10 触发线同款逻辑)。

14.4 JIT:与本议题正交,且从未被永久关闭

  • 正交:JIT 加速「解释执行 opcode」(全速执行);时间旅行成本在「每步采集」。§3/§4 路线裁定本身就把两者分开——全速执行正解 = bytecode→wasm 生成器(§4.1,已由 wasm-gc 出口拿到执行层 2.0-2.8×);unified/单步 = 解释器 + 按需物化(§3)。
  • 现状:F-3「JIT 倾向不搬」,依据「宿主 V8 自带 JIT」;架构审阅 20260921 §2.5 判 P1——该依据只对 wasm-gc 出口成立,native 出口不成立(门 1 实测解释器 512ms vs JIT 55ms = 8.8×),建议按出口分别裁定。
  • 排期:S9 = 「JIT 复核」;0.8.0 明确含「JIT 评估(只判定书不实现——S9 复核输入)」;W^X 加载器先例已备(kimicc jit/stub.c:139-206,约 500 行总代价,调查报告 §4.4)。
  • ⇒ 不需要"重启":它从未被关闭,是已排期的复核 + 判定书;真正决定其命运的是出口裁定(native 出口是否保留),不是性能数字。

15. S8 交付面全量性能实测(2026-10-04 晚,CLI 口径 + 库级对照)

AS-OF:2026-10-04 21:20–21:35。触发 = 新 CLI 出口(vitro,a66e5c9)就位后的首次 S8 交付面全量性能实测。 口径:两臂——CLI 臂 = vitro 逐进程端到端(含进程创建 + gateway JSON wire);库级臂 = tmp/perf_probe/s8_bench 直调引擎(纯算,扣启动)。两臂均经 Windows 计划任务启动(绕 agent 会话启动税:CLI 臂 boot 11.7ms / 库级 9ms,会话内对照 128ms)。 机/构建:AMD Ryzen AI Max+ 395 / 16C32T / Win11;MOON_CC=clang(全量 native 29s)。

15.1 CLI 臂(vitro <cmd>,逐进程端到端,5 轮中位)

场景 中位 派生
boot(api ping) 11.7ms 启动基线
compile fib / bubble 15.5 / 12.9ms
run fib(20) / bubble(200) / nested(500×500) 32.8 / 144.7 / 446.4ms 对 §13.5 的 Rust run 20.8/21.0/28.3ms → mb/Rust 1.58 / 6.89 / 15.8×(§13.5 记 1.74 / 6.43 / 15.80×,同量级)
step fib(20) 全量 284,591 帧 25,194ms 88.5 μs/帧(含 wire)
step bubble 截断 199,999 帧 41,871ms 209 μs/帧
api compile(teaching) 9.5ms 帧出 algorithm_matches
api diagnostics_probe 9.1ms 八段全出
api ast.dump 8.9ms

15.2 库级臂(纯引擎 tmp/perf_probe/s8_bench,5 轮中位扣启动)

场景 纯算 派生
unified fib(20)(284,591 帧) 4043ms 14.2 μs/帧
unified bubble 截断(400,000 帧) 24,738ms 61.8 μs/帧
逐步 batch=1(2000 次调用) 32.1ms 16.1 μs/次
seek_to 窗内 ×200 1514ms 7.57 ms/次
seek_to 越窗 ×50(检查点 + 正向重放) 2779ms 55.6 ms/次(窗内的 7.3×)
detect_algorithms ×2000 246.8ms 61.7 μs/次(判据锚在函数体——写在 main 里合法零命中,实测首撞)
diagnostics 认知链 ×2000 87.0ms 43.5 μs/轮
analysis M14 trap ×200 1158ms traps=400 / hints=400(全触发,接线有效)

15.3 主轴结论

  1. wire 主导 time_travel 帧流:同一 fib(20) 的 284,591 帧——纯引擎 4.04s vs CLI 端到端 25.19s ⇒ gateway JSON wire 占 ~84%(引擎仅 16%)。与 §3「每步 CPU 是病灶」互补:那是引擎内每步 collect 的成本,此处是出口层每步 encode/往返的成本——教学帧流若经 CLI 批量消费,瓶颈在协议层不在引擎。
  2. S8 四面首次有 mb 侧实测数字:time_travel(unified 跑完 / 逐步 / seek 越窗)、teaching(判据 ~62μs/次)、analysis(M14 400/400 全触发)、diagnostics(~44μs/轮)。
  3. 无回归:run 三程序与 §13.5 逐项吻合(nested 1.00×)。
  4. seek 越窗 55.6ms/次(= 最近检查点 + 正向重放到 trap 前一步,⑤-5.1 落地形态);窗内 7.57ms/次。

15.4 探针资产与复跑

资产 位置 复跑
CLI 套件(新) tmp/perf_probe/cli_bench.py 计划任务:-Execute <py> -Argument D:\code\Vitro\tmp\perf_probe\cli_bench.py;结果 tmp/perf_probe/cli_bench_out/<stamp>/results.json(会写 DONE.txt)
库级套件 tmp/perf_probe/s8_bench/(run_bench.py);计划任务包装 run_s8_task.py 包装会自动设 S8_EXE 指向 _build/.../s8_bench/src/src.exe(直接跑 run_bench.py 的自动发现会误选 dump_*.exe)

测量纪律:两臂都必须在计划任务/普通窗口跑(会话内进程创建 ~128ms 会污染快场景);测量期间勿构建——同批实测中一次 step 因并行构建把 vitro.exe 换掉而 rc=1,复跑即 rc=3 正常。

16. wasm-gc 出口全场景性能实测(2026-10-04 晚,Node 宿主 + gateway)

AS-OF:2026-10-04 21:45–21:55。触发 = 用户拍板「wasm-gc 是主出口(用户最多),必须全域测」——CLI(vitro)只服务少数高手/agent,且 10 个 cmd/* 全 supported_targets="native",CLI 测不了 wasm-gc。 口径:Node 宿主(system Node 25——js-string 必需,PATH 里的 22 报 illegal cast)+ gateway wasm-gc 产物(moonbit/_build/wasm-gc/release/build/gateway/wasm/wasm.wasm,867,318B),经 g.invoke(ndjson) 发与 native CLI 同一批协议请求(可直接对照)。探针 tmp/perf_probe/wasm_cli_bench.js;驱动 wasm_bench.py(外层 wall + 场景 0 校准;计划任务)。 boot(Node 启动 + wasm 实例化)= 45.5ms。

16.1 结果(14 场景,5 轮中位)

场景 wall 派生
boot 45.5ms
compile fib / bubble ×50 75.3 / 86.2ms 0.60 / 0.75 ms/次
run fib(20) / bubble(200) / nested(500) 99.4 / 243.3 / 442.9ms 11.1 / 38.9 / 132.2 ms/次
step fib(20) 全量 284,591 帧 6,145.6ms 21.4 μs/帧
step bubble 199,999 帧 8,060.6ms 41.9 μs/帧
seek 窗内 ×200(建流 12 万帧) 2784.2ms seek 11.3 μs/次
seek 越窗 ×50(检查点 + 正向重放) 4160.6ms seek 28.0 ms/次(窗内的 2477×)
diagnostics_probe ×200 206.4ms 0.79 ms/轮
teaching(compile 帧)×200 153.4ms 0.54 ms/轮
ast.dump ×200 140.7ms 0.46 ms/轮
memory.regions ×200 190.9ms 0.70 ms/轮

16.2 与 native CLI 臂对照(同请求序列,pure 口径——各扣自身启动:native 11.7ms / wasm 45.5ms)

⚠️ 口径注:不可用 wall 直接比——wasm 的 boot(Node 启动 + wasm 实例化 45.5ms)远大于 native CLI(11.7ms),wall 差会把 wasm 的启动税算进来。下表两侧均为 pure = wall − boot。

场景 native CLI pure wasm-gc pure 比值
compile fib 3.8ms 0.60ms 0.16×
compile bubble 1.2ms 0.81ms 0.68×
run fib(20) 21.1ms 10.8ms 0.51×
run bubble(200) 133.0ms 39.6ms 0.30×
run nested(500×500) 434.7ms 132.5ms 0.30×
step fib(20) 284,591 帧 25,182.6ms 6,100.1ms 0.24×
step bubble 199,999 帧 41,859.5ms 8,015.1ms 0.19×

⇒ wasm-gc 在全部七项上快 native CLI 1.5–6.3×(含 run 与 compile)。

16.3 结论

  1. wasm-gc 全面优于 native CLI(1.5–6.3×) ⇒ 印证「wasm-gc 是主出口」;native 出口最差的是帧流(step,wasm 快 4–5×)与编译(compile,wasm 快 6.3×)。
  2. wasm 的 wire 成本极低:wasm step fib(20) 6.15s(含 gateway 编解码 + Node 宿主)vs native 纯引擎 4.04s 仅 1.5×;而 native CLI 是 25.19s ⇒ native CLI 的 25s 主要来自 native 运行时壳层(同引擎在 V8 上只 6.1s)。与 §15.3「wire 占 84%」合读:那是 native 侧的壳层成本结构(协议层 74μs/帧),wasm 侧不成立(gateway 层仅 ~7μs/帧)。
  3. compile 面 wasm 亦优(0.60–0.81 ms/次 vs native 1.2–3.8ms)。
  4. seek 有效且成本随距离陡增:窗内 11.3μs vs 越窗 28.0ms(2477×)——越窗 = 最近检查点 + 正向重放(⑤-5.1 形态)。正确性已验证:seek 响应 payload.step_index == 目标步;seek 后 step.next 从目标继续(wasm_seek_verify.js)。

16.4 探针资产与坑

资产 位置
wasm 套件(新) tmp/perf_probe/wasm_cli_bench.js(14 场景)+ wasm_bench.py(驱动)
seek 正确性验证(新) tmp/perf_probe/wasm_seek_verify.js(判据 = payload.step_index == 目标)
出口形态 宿主 scripts/wasm_gateway/host.js(builtins:['js-string'] + g.invoke);产物 moonbit/_build/wasm-gc/release/build/gateway/wasm/wasm.wasm

坑(两条,均在探针侧):

  • Node 版本:wasm-gc 的 js-string 需 Node 25——PATH 里的 22.22.2 报 illegal cast(host.js 头注已记判定面在 25)。
  • step.next 首批可返 0 帧(延迟一帧):建流循环若在 0 帧 break ⇒ 建流失败。首版实测踩坑:seek 目标退化为 0 ⇒ 测出 3.8μs 的假数(修后为 11.3μs 窗内 / 28.0ms 越窗)。

17. 跨实现执行性能对照(2026-10-04 晚)——mb vs Clang / CPython / V8

AS-OF:2026-10-04 22:05。触发 = 用户问「和其他实现对比呢」。 口径:程序内计时(排除进程启动),三程序与 ext_cmp/ 同源(fib(20) / bubble 200 / nested 500×500);mb 侧 = run pure − compile pure(只比执行)。探针 tmp/perf_probe/xlang_cmp.py。

程序 Clang -O2 CPython 3.13 Node 25 / V8 mb-wasm(gc) mb-native
fib(20)(21,891 次调用) 0.011ms 0.515ms 0.163ms 10.2ms 17.3ms
bubble 200 0.008ms 2.460ms 0.429ms 38.8ms 131.8ms
nested 500×500 0.140ms 13.786ms 2.372ms 131.9ms 430.9ms

mb / 各基准(倍数;每格 = wasm / native):

程序 vs CPython vs V8(JIT) vs Clang -O2
fib(20) 19.8× / 33.6× 62.6× / 106× 927× / 1573×
bubble 200 15.8× / 53.6× 90× / 307× 4850× / 16475×
nested 500×500 9.6× / 31.3× 55.6× / 182× 942× / 3078×

17.1 结论

  1. mb 的 VM 全速执行远慢于 CPython(wasm 9.6–19.8×、native 31–54×)。CPython 是纯字节码解释器(无 JIT)——最公平的可比对象;V8 有 JIT、Clang 是静态优化,仅作上界。
  2. nested(纯算术、零内存访问)也慢 9.6×(wasm)/ 31.3×(native) ⇒ 不是内存安全检查或教学插桩的锅,是 VM 解释循环本身的效率。
  3. 执行层层级(nested 500×500,ms):Clang-O2 0.14 < V8 2.37 < CPython 13.79 < Rust VM 28.3(§13.5)< mb-wasm 131.9 < mb-native 430.9。

    注意:Rust oracle 的 VM 亦慢于 CPython(28.3 vs 13.8 = 2.05×)⇒ 该短板自 Rust 期继承,非 MoonBit 迁移引入。

  4. 与 §16 合读:mb 的采集 / 时间旅行层(每步 collect)与 Rust 打平甚至更快(§16.3),但全速执行层是根本短板 ⇒ 优化优先级 = VM 解释循环(§4.1 的 bytecode→wasm 生成器只给 2–2.8×,量级不足以补齐 10–30× 的差距,需单独评估)。已挂 issue #41(主项 + native CLI 壳层待评估次级项)。
  5. 口径注:Clang -O2 会对固定规模做常量折叠 / 向量化(bubble 0.008ms 系整段被优化),仅作上界不作等价比;CPython 数字经调用计数复核(fib(20)=6765 / calls=21891)。