7.1 KiB
7.1 KiB
桌面端性能改造(第一期,参照 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 内嵌图片。
建议去重,并把工具输出改为按需加载,单独立项。
- 子任务过程记录约 207 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)的顺序。