架构优化实现与同批性能对照
结论与范围
生产基线为 214de5fec5ea796a047024510566168e1fa81d08,优化侧是当前未提交补丁,不是另一个提交。普通 release 二进制在同一批次重新测量前后两侧,没有套用上一轮基线秒数。
输出不变的完整重建:四种正文/模块负载加速 1.53–4.60 倍;XIV 加速 1.30 倍。
XIV 强制整站替换:1.01 倍,基本持平,不能据此声称稳定改善真实变更构建。
XIV 首次构建:1.11 倍;四核无变化重建为独立补充,不混入单核结果。
主批次共 213 次完整成功构建,核对 3,080,809 个文件指纹,包括 3,080,057 份 HTML;各次最终输出均与原始完整清单一致。这些数字包含多轮重复验收,不是唯一页面数。
另有 12 次优化后专用发布检查探针,核对 416,048 个文件指纹;它们仅用于定位新检查成本,不加入前后加速比。两批合计 225 次、3,496,857 个文件指纹,均保持输出一致。
完整真实 XIV DB、页面枚举、所有正文、消费者、
site.data结构及依赖锁均未改变。SSG 输入请求及 Data 缓存预算的既有政策也未改变,不算作本次优化。
实施边界
已实施
树所有权:绑定/capture 只复制正在重建的节点边界,不先深拷贝马上替换的 children/pending;内部 present 消费已经拥有的森林;唯一持有的 Runtime Content 直接取得所有权。Analysis 保持不变,重复挂载继续隔离。
共享调用计划:CheckedProgram 与 InstanceRecord 使用 Arc/写时复制,调用共享 checked body;按扩展映射后的实际目标决定是否构造 Code Scope,原生调用避免无用的词法输入与 children 副本。
宿主批处理:共享 UTF-8 源码、批次配置解析与成功模块装配缓存;DocumentHandle 绑定 Vault 配置身份、路径、源码快照和 Environment,贯穿 SSG 求值及 HTML 绑定。模块图命中仍按原 DFS 顺序请求源码并计费。
有界检查计划复用:仅复用从空程序开始、无诊断且无 Data retention 的完整成功 Code 计划;每个 Context 基础最多 32 个计划/8192 个记录。安装模块或改写 Code 作用域时分离缓存,不合并多余实例绕过限制。
路径与产物:借用序列化站点扩展请求;消费扩展验证得到的 Route;生成输出先预留槽位、再一次填入字节;建立按输出路径和目录别名查询的链接索引,保持源身份优先。
发布与模板:暂存时去重创建父目录;实际有界比较全部旧输出字节及精确目录项,完全一致才跳过替换。至少 1024 页时,仅已准备的不可变模板工作可并行,最多 8 worker,按顺序合并产物与首个错误。
未实施,不能算作已完成
参数槽位与实例 ID:求值器仍使用现有命名 Scope 和实例键,没有重写 IR 调用表示。
产物 spool/staging sink:BuildOutput 仍拥有完整产物字节,未改变输出 API 与 IO 职责,也未测得内存下降。
逐文件增量发布:当前只优化整站输出完全相同的情况;任意差异、额外目录项、symlink 或比较失败仍执行整站暂存、替换和同步清旧。
全管线并行:输入、文档 hooks、分析、求值和发布保持既定顺序;只有模板任务并行。没有异步清理、移出计时的清旧或并行 Vault。
因此本轮完成了 P0、P1 和上述明确范围的 P2,不能概括为所有 P2 设想均已落地。
普通 CLI:单核同批中位数
单位为秒;CPU 固定为 8,文件系统缓存预热,每轮使用新的 CLI 进程。前后顺序交错,频率未锁定,不主张统计显著性。加速比为前侧中位数/后侧中位数。
已有输出完全一致,5 轮
完整负载 | HTML 页 | 优化前 | 优化后 | 加速比 | 耗时减少 |
|---|---|---|---|---|---|
XIV | 51,739 | 4.003808 | 3.087857 | 1.297× | 22.9% |
无模块正文 | 521 | 0.537173 | 0.274984 | 1.953× | 48.8% |
共享模块图 | 521 | 0.919440 | 0.238308 | 3.858× | 74.1% |
私有模块图 | 521 | 1.180939 | 0.769616 | 1.534× | 34.8% |
宽导出 | 521 | 1.641726 | 0.356587 | 4.604× | 78.3% |
强制完整替换,3 轮
计时外仅篡改本工具生成的旧输出 index.html,使发布必须替换;源输入不变。这是发布路径的控制实验,不是任意源文件修改的增量构建成本。暂存、替换和旧目录清理全部在计时内。
完整负载 | 优化前 | 优化后 | 加速比 |
|---|---|---|---|
XIV | 3.822845 | 3.776232 | 1.012× |
无模块正文 | 0.548684 | 0.288133 | 1.904× |
共享模块图 | 0.920354 | 0.253182 | 3.635× |
私有模块图 | 1.187984 | 0.819536 | 1.450× |
宽导出 | 1.683181 | 0.375889 | 4.478× |
无旧目录的首次构建,3 轮
只在此队列的计时外移除工具自身的输出;它不包含清旧工作,因此不与重建混算。
完整负载 | 优化前 | 优化后 | 加速比 |
|---|---|---|---|
XIV | 3.663020 | 3.305422 | 1.108× |
无模块正文 | 0.522393 | 0.270078 | 1.934× |
共享模块图 | 0.903822 | 0.239237 | 3.778× |
私有模块图 | 1.183650 | 0.772430 | 1.532× |
宽导出 | 1.655242 | 0.356581 | 4.642× |
波动与 CPU 时间
XIV 的无变化重建 wall 范围为前侧 3.962453–4.380826 s、后侧 3.011147–4.404894 s;后侧一个慢样本没有删除。强制替换范围为前侧 3.792995–4.030399 s、后侧 3.571661–3.780130 s。不同发布状态分时段运行,不能将各队列基线差异解释成某种发布模式固有成本。
无变化重建的 user/system 中位数如下;二者分别取中位数,不要求相加等于 wall 中位数。
完整负载 | 前 user | 后 user | 前 system | 后 system |
|---|---|---|---|---|
XIV | 2.842782 | 2.702122 | 1.081328 | 0.375909 |
无模块正文 | 0.507117 | 0.253673 | 0.028889 | 0.017966 |
共享模块图 | 0.869984 | 0.211164 | 0.043838 | 0.026969 |
私有模块图 | 1.099564 | 0.682766 | 0.076751 | 0.087610 |
宽导出 | 1.577304 | 0.308455 | 0.055599 | 0.041867 |
完整的每种负载/模式 min、max、mean、median 及每次样本保留在 summary.json 和 samples.json。
独立探针:收益位置与回退
以下为独立插桩二进制、无变化重建三轮均值,单位 ms。不可与普通 CLI 秒数直接相减。前后细粒度插桩范围并不完全相同,只比较具有相同边界的阶段,不将合并优化包的收益拆成未经隔离验证的单项收益。
完整负载 | 分析前 | 分析后 | 求值前 | 求值后 |
|---|---|---|---|---|
XIV | 783.150 | 752.328 | 130.990 | 77.966 |
无模块正文 | 142.000 | 145.553 | 316.615 | 71.725 |
共享模块图 | 234.929 | 55.831 | 591.276 | 109.780 |
私有模块图 | 484.526 | 479.731 | 613.113 | 142.704 |
宽导出 | 361.912 | 53.320 | 1162.869 | 189.338 |
内容树与调用
无模块的 eval.bind_content 从 87.181 降至 26.725;eval.present 从 213.987 降至 44.565。纯正文也改善,不能把全部收益归于模块图缓存。
共享图的 eval.present 从 506.562 降至 104.455;私有图从 524.353 降至 135.873;宽导出从 1018.319 降至 183.786。树所有权、checked body 共享和原生调用装配共同作用于这些区间,未分别作消融实验。
XIV 的底层 eval.run 是 38.913 → 43.856,并未改善;外层求值阶段的下降包含宿主环境查找/句柄路径变化。不能把 130.990 → 77.966 全称为解释器加速。
无模块分析略增,私有模块分析基本不变;这些值和新增细粒度探针的开销一并保留,不声称所有阶段都变快。
装配、检查与来源
模块工作 | 共享图 前→后 | 私有图 前→后 | 宽导出 前→后 |
|---|---|---|---|
compile 调用 | 5192→89 | 5120→5120 | 3072→6 |
实际 compile 工作 | 18→18 | 5120→5120 | 6→6 |
bind 调用 | 5713→610 | 5641→5641 | 3593→527 |
实际 bind 工作 | 139→139 | 5632→5632 | 11→11 |
link/install 调用,各自 | 5192→89 | 5120→5120 | 3072→6 |
模块图 visit 调用 | 5712→5712 | 5632→5632 | 3072→3072 |
表内模块计数取每侧一个正式探针样本;实际工作数可受计算缓存保留影响,完整逐次计数仍在 samples.json。图装配复用减少重复进入已缓存计算、link 和 install,没有取消私有模块的真实编译,也没有跳过依赖源码请求。
配置解析从每页一次降为每批一次。共享图有 520 次检查计划查询、9 次成功计划登记,宽导出分别为 512/8;查询次数不是命中次数。私有图为 512/512,不能通过相同源码将不同模块身份混为共享计划。
保留缓存也有成本:私有图的 drop.vault 从 5.585 增至 36.553;共享图从 3.570 增至 13.829。没有测量 RSS 或分配量,不能由耗时推断内存改善。
路径预规划不能只看后移阶段
XIV 的逐页模板阶段为 519.645 → 345.077,但新实现把已知页面的路径冲突检测提前到了资源准备/预留阶段,后者为 0.751 → 140.733。连同 finish 的相关阶段合计为 520.400 → 491.278,而不是节省了全部 174.568 ms。优化后的 template.render_all 为 314.262 ms,包含当前页上下文设置;不能与旧实现只围住 engine.render 的子计时直接比较。
共享模板上下文为 215.839 → 209.858;site.data 仍转换一次,未改成懒加载、远程请求或新的消费者结构。
发布:no-op 的收益与真实替换的限制
无变化 XIV 探针:完整 publish 为 884.743 → 328.573 ms。旧侧写暂存 473.074、清旧 411.455;新侧完整字节/目录比较为 223.974,除此之外的发布检查成本也计入 publish,不能仅用 compare 代表全部发布成本。
强制替换 XIV 探针:publish 为 930.274 → 1052.572 ms;写暂存为 494.213 → 449.990,清旧为 435.859 → 479.590,优化侧还承担了 11.481 的失败 no-op 比较。目录去重确实删除了冗余系统调用,但没有消除逐文件写出与旧目录删除,也没有得到稳定的端到端替换加速。
独立 strace 控制如下;均包含 CLI 及扩展子进程,不能当作仅发布函数的精确调用数。trace wall 不参与性能结论。
syscall | 前 same | 后 same | 前 replace | 后 replace |
|---|---|---|---|---|
mkdir | 51749 | 0 | 51749 | 10 |
write | 51748 | 4 | 51748 | 51748 |
unlinkat | 51751 | 0 | 51751 | 51751 |
rename | 2 | 0 | 2 | 2 |
read | 3272 | 433369 | 3272 | 3295 |
所选 syscall 总计 | 315630 | 642243 | 315630 | 212208 |
无变化路径用实际读取换掉写出和清旧,系统调用总数反而增加;它不是零成本跳过。插桩调用边确认新增的 51,744 次有界后端读取来自 publish.compare;语言输入的 input.load → io.bounded_read 仍只有 1 次,不是语言 Data 读取增长。strace 下大量短 read 的额外拦截开销也使 no-op 的 trace wall 更慢,不能据此推翻普通二进制测量或用 trace 秒数计算加速。
优化后专用检查补充
为定位主批中 publish 剩余 Self,另建独立临时探针,未修改生产补丁或主批源快照。每组一次预热、三次正式测量,仍使用完整输入和逐文件验收;以下只描述优化侧该队列的三轮均值,单位 ms,不跨队列相减或用于加速比。
完整负载/状态 | 输出归属检查 | 相对路径校验 | 全字节比较 | 完整 publish |
|---|---|---|---|---|
XIV/same | 108.237 | 1.361 | 254.861 | 364.494 |
私有图/same | 6.066 | 0.028 | 6.468 | 12.589 |
XIV/replace | 106.084 | 1.149 | 11.405 | 1313.330 |
XIV 的额外百毫秒主要定位在输出归属检查区间,而非提前的相对路径循环;该区间包含 metadata、目录是否为空及现有 manifest 读取/解析,没有继续分离到底层调用或分配器。私有图的发布剩余成本、替换时的写出成本在两种插桩队列中也有明显差异,因此不拿本补充替换主批数值,不宣称已经解释或消除了全部回退。
补充证据保留在 publication-checks/manifest.json、samples.json、summary.json 和 integrity.json;入口为 tools/profile_publication_checks.py。最初一次补充脚本准备因重复锚点被安全拒绝,修正并通过语法测试后才开始计时,失败目录及日志保留。
四核补充
仅普通二进制、XIV 无变化重建,固定 CPU 8–11,独立预热后各三轮:前侧中位数 4.020495 s,后侧 2.891784 s,加速 1.390 倍。前侧范围为 3.913935–5.612445,后侧为 2.867420–2.913240;前侧一个慢样本保留。
优化后四核与优化后单核无变化队列中位数之比为 1.068,但两队列分时段运行,不是隔离模板并行开关的严格 A/B。不能将 1.390 倍全算为并行收益,也不报告线程局部探针的跨 worker 总计。
验收与复现
工作区 all-features 串行测试:734 项通过。
顶层 no-default-features 串行测试:370 项通过,与前项有重叠,不能相加当作独立测试数。
Python 工具测试:26 项通过。
更新后的项目文档构建:49 页成功,输出位于
/tmp/opencode/notist-optimization-docs-20261103/,不计入性能样本。交互报告通过手机/桌面视口的页面数据与三种发布状态、探针负载切换检查。应用浏览器的截图 capture 超时,同时记录宿主 preload 文件缺失;未将其描述为截图验收成功。
Clippy 通过,仅保留 context.rs 的 bool::then/filter_map 和 profiling.rs 的 thread_local const 两条既有警告。
新增或保留 Analysis 不变、重复挂载、扩展执行映射、空值/未选分支、累计预算、来源/相对 Path、NeedResources、句柄跨 Vault/配置/源码隔离、模块图请求额度、UTF-8/授权、预留槽位、并行模板顺序/首个错误、发布 stale/symlink 等回归。
Data 正向控制为 4 次语言读取、2 次实际解析;无变化输出比较不会冒充 Data 输入。
主批次 213 次由 140 次普通单核(含各自预热)、48 次探针(含预热)、8 次四核(含预热)、5 次 seed、3 次 Data 控制、4 次 strace 及 5 次预检组成。逐文件校验在每个子进程退出后、计时外进行;生产补丁、源快照、输入和二进制在批次前后验证一致。
复现入口为 tools/profile_optimizations.py,规则见 tools/OPTIMIZATION_PROFILE.md。交互图模板为 tools/optimization_profile_chart.html。原始证据位于 /tmp/opencode/notist-optimized-profile-20261103/,包含 manifest.json、optimization.patch、regression-tests.patch、sources、bin、samples.json、summary.json、strace.json、integrity.json、logs 和 inventories。
冻结的生产补丁 SHA-256 为 1998c01a1b9279bb4c00ca7ada382ede1ec39b82cf3f771dc15b0f8446651cd2,Cargo.lock 未变化。最初两次临时探针 release 构建分别因 RHS 误匹配 worker 局部变量、计时器遮蔽 links 迭代器失败,修正与日志均保留;它们发生在计时前,没有修改生产实现或删除慢样本。
最初未设置 NO_COLOR 的 CLI watcher 测试因终端转义失败;一次并行模块测试的 Arc 指针相等断言失败,隔离串行及最终完整串行均通过。没有修改这些既有断言掩盖失败。
本轮生产代码、回归、文档与工具仍未提交或推送;此前的历史分析和测量证据保留原貌。