内容执行内核重构与性能验收
范围与表示
公开 Node/Expr 分离版本先提交为 efec73e。本轮移除过渡执行模型:
删除 notist-eval/src/frame.rs、EvaluationState、PresentCheckpoint 与捕获代换函数。
内容值保存不可变构造计划;不透明调用与循环持有共享检查代码和 COW 词法环境快照。绑定计算内容插值,挂载直接生成最终 Node。
重复挂载共享代码和环境,不缓存最终挂载结果;后续绑定通过 COW 保持词法遮蔽与各次循环捕获独立。
聚合预算溢出只截去当前输出后缀,从不可变源码边界构造 Error,不备份或回滚已修改的调用字段。
无映射、无表达式且结构有效的具体内容可直接共享孩子存储。来源展开链在输出时附加,空原链共享同一展开后缀。
core 删除 PendingEvaluation;RExpr.expression 直接保存 TypedExpr。Node 表达式、内容孩子、Call、Content 森林和循环模板使用共享 COW 存储。serde 的共享容器透明编码。
EvaluationContext.has_mappings 为自定义宿主保守返回 true;pipeline 和 benchmark 宿主声明实际映射情况。
is_evaluated_interpolation 更名为 is_group,不再用执行历史描述普通内容。
逻辑预算继续计入会溶解的挂载;不按最终节点数重新定义配额。循环、资源请求、未准备输入、局部失败恢复、非空属性分组和实际构造身份规则保留。已知失败在检查树中统一表现为 Error,来源孩子保留供检查,执行不访问这些孩子。
验证
cargo test --workspace --all-features --locked --offline --no-fail-fast -- --test-threads=1:780 项通过,88 个测试/文档测试目标,无警告。
python3 -m unittest discover -s tools -p 'test_*.py':53 项通过。
benchmark:58 个场景通过语义和完整结果自校验。
git diff --check:通过。
新增直接验证代码存储共享、词法环境快照、未使用循环不执行 subject、具体内容共享后修改隔离、错误源码孩子不执行,以及来源链的共享、顺序与独立修改。原有预算测试改为验证生产内核的重复执行、源码不变性和独立构造计数,不保留失去意义的 checkpoint 对照执行器。
历史源码插桩探针属于固定版本实验:SSG 探针测试固定在 18f893a;字段/checkpoint/来源探针固定在 e5c65a3。字段探针对闭包内核明确拒绝运行,避免把其它操作的开销冒充已经删除的旧字段成本。新内核使用维护中的 eval-bench 驱动测量。
测量方法
原始证据目录:/tmp/opencode/notist-execution-kernel-final
当前代码、构建环境、二进制和哈希冻结在 manifest.json、workspace.patch、source/ 与 bin/;完整源冻结成功完成。比较使用三个冻结版本:原始基线、efec73e 对应的适配层实现、新闭包内核。
三轮重新计时,每个版本每轮一个新进程、每个场景五次采样、目标每次 20 ms;顺序为「原始/新内核/适配层」「适配层/新内核/原始」「原始/新内核/适配层」。采用进程内采样中位数,再取三个进程中位数。相同 rustc 1.97.1 和 release 构建环境。分配统计由独立插桩二进制采集;同一场景的模块与文档源代码在三个版本间完全相同。
时间包含求值及结果销毁,不含解析、检查、HTML 或磁盘 IO。未固定 CPU 频率、未隔离后台负载;这是初步暖态合成场景对照,不是整站构建速度或 RSS 预测。旧结果保留调用外壳,新结果按属性溶解,因此原始基线与新内核不是完整结果树相同的纯实现 A/B。每个版本各自进行完整结果校验。
结果
场景 | 原始 µs | 适配层 µs | 新内核 µs | 新/原始耗时 | 原始/新分配次数 |
|---|---|---|---|---|---|
ready_text/128 | 12.69 | 31.90 | 3.22 | 0.25 | 11/6 |
native_text/128 | 77.05 | 126.52 | 74.29 | 0.96 | 3088/2842 |
code_calls/128 | 203.70 | 297.22 | 130.68 | 0.64 | 7982/5296 |
capture_uses/128 | 90.95 | 135.38 | 79.07 | 0.87 | 3508/2865 |
replay_call/128 | 183.87 | 248.87 | 118.52 | 0.64 | 7096/4669 |
loop/128 | 145.60 | 196.51 | 116.18 | 0.80 | 6611/5054 |
capture_dead_branch/128 | 14.94 | 26.57 | 1.77 | 0.12 | 736/74 |
many_parameters/128 | 49.07 | 100.75 | 35.55 | 0.72 | 903/494 |
read_text/128 | 267.02 | 372.99 | 192.29 | 0.72 | 11443/8629 |
json_cached/128 | 389.34 | 493.06 | 311.55 | 0.80 | 16073/13259 |
nested_expansion/16 | 15.87 | 20.19 | 10.68 | 0.67 | 535/356 |
新内核在本次 58 个场景中均快于适配层;56 个快于原始基线。剩余 native_text/1 约慢 15%,strict_lets/128 约慢 3%;前者是单个小调用的固定开销回退,后者需要更受控的测量区分小差异与噪声。不能宣称所有负载均加速。
code_calls/128 的瞬时增量请求堆峰值从 189047 降至 126565 字节,结果存活增量从 160106 降至 79560 字节。ready_text/128 的结果存活增量很小,主要因为结果复用基准已持有的输入孩子;输入存储并未凭空消失。这些计数排除预先保留的输入、程序和暖缓存,不是总堆或 RSS。
paired-comparison.json 保存三版全部逐场景事实、时间、分配与运行顺序;paired-*.json 和 logs/ 保存重新计时的原始结果。不要把最初因源快照在测量中变化而未通过完整性验证的 notist-execution-kernel-performance 目录当作最终证据。
边界
此内核不再有旧执行树适配或捕获代换。环境仍按名称查询,COW 保存整个当前词法映射,不是最小自由变量槽位布局;构造计划仍有绑定与挂载遍历,不是字节码 VM。后续可据 profiling 优化这些独立成本,不应把它们误称为尚未清除的旧 Frame 桥接。