Files
gopeed/experiments/moejs/RESOURCES.md
T

87 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CPU 与内存补充测量
日期:2026-11-14。沿用 [主报告](REPORT.md) 的引擎版本、三个固定扩展包、回放输入和 M1 / Go 1.26.0 环境。
**建议维持 goja,暂不投入完整替换。** 在当前每次事件新建引擎、重新编译加载的方式下,B 站/YouTube 的 CPU 只减少约 12% / 15%,没有一致的内存优势;连续解析时峰值 RSS 更高。Twitter 的 CPU 降幅较大,但每次只省约 5 ms。这些收益不足以抵消完整宿主桥接、兼容性和维护成本。
## 测量方式
- 每个样本使用新的独立 OS 进程,两个引擎交替先后顺序,5 轮重复,报告中位数;最终数据共 120 个进程样本。测量时未与本次其他构建或测试并发。
- `GOMAXPROCS=1 GOGC=100 GOMEMLIMIT=off`,不使用 PGO。CPU 是 `getrusage(RUSAGE_SELF)` 的 **user + system 时间**,除以完成次数;包含 GC 和编译开销,不使用瞬时 CPU 占用百分比,也不把墙钟耗时直接当 CPU 时间。
- `cold`:一次进程内先预热一次全局初始化,再连续完成 20 次“新建环境、克隆 bundle 输入字符串、编译加载、解析、关闭”。接近当前反复触发扩展事件的方式。每次使用独立 bundle 字符串,模拟生产文件读取后的输入所有权。
- `warm`:环境已加载,连续解析 200 次。仅用于确认复用环境时的 CPU 上限;当前生产事件路径没有这样复用。
- 内存组不预建引擎,从相同测量程序基线开始,分别建立并保留 1 / 8 个完整环境,每个环境执行一次解析后保持存活。8 个环境是同时保留,不是同时并行执行;不模拟实际 Blob/FFmpeg 媒体数据。
- 存活堆:`runtime.MemStats.HeapAlloc` 相对建引擎前的增量。连续 GC 并给异步清理调度机会,至少 3 轮、最多 8 轮,直到相邻值差异小于 64 KiB;不稳定则测量失败。保留源字符串并用 `runtime.KeepAlive` 保证环境仍存活,避免编译器提前释放。
- RSS:通过 `ps` 记录当前物理驻留快照,通过 `getrusage` 记录进程历史峰值;macOS 的峰值单位为字节,Linux 转换为字节。`ps`、稳定 GC 和内存快照都在计时区间外,`RUSAGE_SELF` 不包括 sampler 子进程 CPU。
- 两个引擎链接在相同测量 worker 中,RSS 含公共 Go/测试框架/代码页和 allocator 保留页,**不是完整 Gopeed 应用或最终单引擎产品的内存预测**。存活堆增量用来区分扩展保留对象和进程历史峰值。
- 全部输出按 SHA-256 比较一致,没有通过减少文件或请求处理量获得更好的数字。宿主 mock、HTTP fixture、未移植能力及真实下载尚未验证等限制与主报告相同。
## 冷路径 CPU 与连续解析峰值
| 扩展 | goja CPU (ms/次) | moejs CPU (ms/次) | CPU 减少 | goja 峰值 RSS (MiB) | moejs 峰值 RSS (MiB) |
| --- | ---: | ---: | ---: | ---: | ---: |
| bilibili | 118.962 | 104.081 | 12.5% | 154.7 | 172.3 |
| youtube | 278.476 | 237.330 | 14.8% | 283.8 | 358.9 |
| twitter | 15.555 | 10.594 | 31.9% | 79.7 | 96.8 |
峰值是连续 20 次冷解析期间**整个 worker 的进程峰值**,不是单个 runtime 的堆大小。峰值会受 Go GC/allocator 与异步清理时机影响;不能将它当作关闭后仍存活的对象。原始数据保留每轮值,汇总文件也提供 min/max。
| 扩展 | goja 累计分配 (MiB/次) | moejs 累计分配 (MiB/次) | 分配减少 |
| --- | ---: | ---: | ---: |
| bilibili | 73.69 | 60.17 | 18.3% |
| youtube | 159.91 | 146.82 | 8.2% |
| twitter | 10.96 | 7.73 | 29.5% |
moejs 的累计分配量确实较少,但这没有转化为更低的连续解析峰值 RSS。`B/op`、GC 后存活堆、RSS 是不同指标,不能互相替代。
## 保留环境时的内存
| 扩展 | 保留环境数 | goja 存活堆增量 (MiB) | moejs 存活堆增量 (MiB) | goja RSS 快照 (MiB) | moejs RSS 快照 (MiB) |
| --- | ---: | ---: | ---: | ---: | ---: |
| bilibili | 1 | 15.87 | 15.66 | 114.2 | 111.2 |
| bilibili | 8 | 126.72 | 120.60 | 362.0 | 302.6 |
| youtube | 1 | 32.48 | 41.22 | 203.7 | 192.2 |
| youtube | 8 | 259.64 | 320.54 | 627.8 | 680.1 |
| twitter | 1 | 2.53 | 2.63 | 75.6 | 74.7 |
| twitter | 8 | 20.06 | 19.48 | 106.9 | 93.5 |
B 站一个环境的存活堆几乎没有变化;YouTube 反而更高。多环境情况下也没有稳定、普遍的显著节省。RSS 快照包含 allocator 页面,因此与存活堆的变化比例不同。
最初单次 GC 的 YouTube 堆快照约为 32.5 → 42.2 MiB。考虑 moejs 异步清理编译缓存后,已重测驻留组,表中使用稳定 GC 的结果,不能将初始 42.2 MiB 当成最终驻留值。CPU 和冷路径峰值取自第一次进程资源测量;这些计时和峰值发生在强制 GC 之前,不受驻留测量修正影响。
关闭全部环境并等稳定 GC 后,额外存活 Go 堆回落到 goja 约 0.03–0.05 MiB、moejs 约 0.18–0.97 MiB。这包含一次性进程缓存;本实验没有据此认定泄漏。RSS 不一定同步回落,不能只看关闭后的 RSS 判断对象是否已释放。
## 热路径 CPU
| 扩展 | goja CPU (ms/次) | moejs CPU (ms/次) | CPU 减少 |
| --- | ---: | ---: | ---: |
| bilibili | 19.688 | 3.173 | 83.9% |
| youtube | 2.905 | 0.215 | 92.6% |
| twitter | 3.265 | 0.453 | 86.1% |
热路径的大幅 CPU 节省再次成立。但它要求持有并复用已加载的环境;对当前每个事件重建环境的实现,应该采用上面的 cold 结果评估迁移。
## 决策
按当前扩展和架构,CPU/内存补测没有提供足够的替换依据。尤其 B 站和 YouTube 的 CPU 节省有限,内存没有一致改善,加上主报告里压缩体积几乎不变,应先维持 goja,把本 PR 留作调研记录。
未来若出现长时间执行计算、反复复用环境的真实扩展,再重新评估;若独立研究编译缓存或环境复用,必须同时在 goja 和 moejs 上比较收益,不能把架构优化全部归给引擎替换。
## 复现和证据
```sh
cd experiments/moejs
python3 fetch_sources.py
python3 measure_resources.py > results/resources-run.txt
# 只重新汇总已保存的原始样本,不启动新测量
python3 measure_resources.py --summarize-only
# 必要时只重测驻留组,保留之前的 CPU 样本
python3 measure_resources.py --memory-only > results/resources-memory-run.txt
```
原始样本:[resources.json](results/resources.json);汇总:[resources-summary.json](results/resources-summary.json)。首次资源运行日志:[resources-run.txt](results/resources-run.txt);稳定 GC 后重测驻留组日志:[resources-memory-run.txt](results/resources-memory-run.txt)。首次日志中的驻留组已被后者替代。当前 worker:[resource_worker_test.go](resource_worker_test.go);驱动:[measure_resources.py](measure_resources.py);功能检查:[resources-tests.txt](results/resources-tests.txt)。CPU/warm 组中单次 GC 的快照保留作原始记录,内存结论只使用重新测得的 `retained` 组。