Files
goodbuddy/docs/review/performance-phase-1-report-2026-10-04.md
T

97 lines
7.1 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.
# 桌面端性能改造(第一期,参照 VS Code 架构)结项报告
- **时间:** 2026-10-02 至 2026-10-04
- **范围:** Desktop 的 Electron Main、Preload、Renderer 及其后台线程。远程主机(Agent、SSH、远程 Runtime)的稳定性和性能不在本期范围,下一期单独审查。
- **结论:** 本期计划内的工作已完成。用户日常能感受到的卡顿(打字、流式输出、切换会话、滚动、启动、写库)都已测量并修复。剩下的工作是架构上的长期项(存储接口异步化、独立数据进程),风险高,已经写明理由,留到后续单独立项。
- **相关文档:**
- 性能原则和评审清单:`docs/architecture/performance-principles.md`
- 逐项测量记录:`docs/roadmap/product-performance-experience-improvement-plan.md` 第 7 节(PERF-11 至 PERF-17)
## 1. 结果
### 1.1 模拟低端机(Renderer CPU 降速 4 倍)
| 场景 | 改造前 | 改造后 |
| --- | --- | --- |
| 有 300 个会话时打字,按键延迟 p95 | 最高 4 秒 | 约 10–35 ms |
| 流式输出时打字,按键延迟 p95 | 最高 9.6 秒 | 约 30–60 ms |
| 流式输出期间卡住界面的总时长 | 16–21 秒 | 约 0.3–3 秒 |
| 切回刚看过的会话,点击延迟 p95 | 约 530 ms | 约 110–140 ms |
| 打开 2,000 条消息的会话 | 约 1.1–1.8 秒 | 约 0.27 秒 |
### 1.2 标准机
- `npm run perf:check` 的 60 项阈值全部通过。
- 流式输出、流式输出时打字,超过 50 ms 的长任务均为 0。
- 改造前,流式输出 40 KB 回答时约 47% 掉帧,帧间隔 p95 83 ms。
### 1.3 Main 进程
Main 卡顿的数据来自真实数据,以及 5 万个文本块的知识库。
| 场景 | 改造前 | 改造后 |
| --- | --- | --- |
| 5 万个文本块的知识库混合检索 | 490 ms | 19 ms(移到只读 worker) |
| 读取会话列表 | 25 ms | 0.8 ms |
| 活动记录:启动读取 | 14.2 MB,198 ms | 114 KB,0.6 ms |
| 活动记录:保存一条变化 | 114 ms | 6.9 ms |
| 导入大 PDF | 0.5–0.7 s | 约 16 ms(移到解析 worker) |
| 单次写库(真实数据) | 2.2–2.6 ms | 0.1–0.3 ms |
| 写入期间偶发卡顿(真实数据) | 最长 346 ms,超过 50 ms 共 37 次 | 最长 34 ms,0 次 |
### 1.4 启动
真实数据:2.4 GB 数据库,175 万条任务事件。
| 指标 | 改造前 | 改造后 |
| --- | --- | --- |
| 启动到输入框可用 | 3.70 s | 1.36 s |
| 侧栏出现会话 | 4.08 s | 1.75 s |
| 启动期间 Main 最长阻塞 | 2.5–2.8 s | 约 0.25 s |
| 空配置启动 | 1,044 ms | 962 ms |
## 2. 做了什么
按性能原则 P1–P10 归类,提交号见计划文档。
| 原则 | 改动 |
| --- | --- |
| P1 Main 只做调度 | 知识检索、Story Graph、会话列表、会话搜索、活动记录分页和汇总放到只读 worker;文档解析、分块、哈希放到解析 worker;WAL checkpoint 放到后台线程;远程事件按检查点批量写库;高频本地写入使用 `synchronous = NORMAL`;启动恢复改为按索引读取(schema 58) |
| P2 状态局部订阅 | 流式缓冲、输入草稿、会话、任务和产物、活动记录、弹出层都改为独立 store;拆出 Composer、侧栏和隐藏路由并加 memo;切换会话只渲染一遍;`App.tsx` 从 11,246 行降到约 7,900 行,lint 设了上限 |
| P3 高频数据按帧合并 | 流式文本按帧合并;终端输出在 Main 端按 8 ms 合并,界面每帧最多写一次;自动滚动每帧最多一次 |
| P4 只传变化部分 | 活动记录改为增量保存和分页,统计由 Main 汇总,覆盖全部记录;Markdown 只重新解析变化的段落,并缓存解析结果 |
| P5 工作量和可见内容成正比 | 消息时间线、会话侧栏、笔记、文件树、知识库文档表格都只渲染可见部分 |
| P6 启动只做首屏需要的工作 | 本地工具环境改为后台初始化;Canvas、终端、SSH、OpenCode SDK 等模块改为用到时再加载;启动恢复改为按索引读取 |
| P7 先测量,再修改 | 新增 `perf:app`(支持模拟低端机、内存、CPU 剖析)、`perf:main`、`perf:knowledge`、`perf:document-parse`、`perf:startup`(含 `real` 真实数据变体)、`perf:write`(真实数据回放) |
| P8 正确性优先于速度 | 分段渲染与整篇渲染对照测试,含随机语料;活动记录与改造前的整份列表逻辑逐步对照;数据库写入顺序和持久性边界有专门测试 |
| P9 用工具守住规则 | lint 规则:主进程禁止同步文件 API、限制 `DatabaseSync` 的使用范围、组件不得直接订阅 IPC、`App.tsx` 行数上限;`perf:check` 阈值 |
| P10 体验不倒退 | 修复了 8 处体验倒退:回到底部的平滑动画、滚出可见区后丢失状态、跨消息选择文本、侧栏插入时跳动、终端回显、远程流式输出一顿一顿、复制时缺内容、锚定冲突 |
## 3. 有意不做的部分
| 项目 | 理由 |
| --- | --- |
| 存储接口全部异步化,新增独立数据进程(PERF-15、16 的剩余部分) | 约 500 处同步调用,并且要保证“先写后读”的顺序,风险高。最重的读已经移出 Main,写入已降到每次 0.1–0.3 ms,收益已经不大 |
| Markdown 解析放到后台线程 | 需要重写渲染流程。标准机上流式输出已经不卡,只有低端机上的长回答还有余量 |
| 窗口提前加载,接口请求排队等待 | 可省 200–300 ms,但要改动所有接口的注册顺序和首次运行流程 |
| 会话队列移出 App | 和发送、恢���、中断联系太紧,拆出来的风险大于收益 |
| 性能阈值接入 CI | 仓库目前没有 CI 配置 |
## 4. 已知问题和下一步
### 4.1 本期遗留
- **打开最大的会话要等约 170 ms。** 这个会话有 407 条消息、42 MB 附加数据。读取在 worker 上,不卡界面,但切换时要等。根因是附加数据冗余:
- 子任务过程记录约 207 MB,主要是 `read`、`bash` 等工具的完整输出;
- 旧的 `tools` 和新的 `blocks` 重复保存,约 65 MB;
- 旧数据里有约 4 MB 内嵌图片。
建议去重,并把工具输出改为按需加载,单独立项。
- **持久性的变化。** 高频本地写入改为 `synchronous = NORMAL`:断电时最多丢失最近一段运行事件和会话保存,应用崩溃时不丢。远程事件、通道投递、任务状态仍然每次落盘。
- **没有在真实低配 Windows 机器上测过**,也没有用同一标准实测 VS Code 作为对照。
- **全量测试中 2 个监督者相关测试失败**,在本期之前就已失败,属于另一项正在进行的工作。
### 4.2 远程主机(下一期)
本期涉及远程路径的改动只有 3 处:
- `d859cbf`:远程事件按检查点批量写库;
- `805acc3`:远程流式合并间隔从 50 ms 改为 16 ms;
- `0dd4d1d`:远程事件仍然每次落盘,未降级。
用户报告的 `Agent refused the stable controller generation resume` 和 `Runtime stopped before the prompt reached a terminal state` 两个错误,还需要在下一期确认和这些改动有没有关系。确认方式:在改动前后的版本上复现,对照远程事件写入和确认(ACK)的顺序。