From 91edcf5e8b4b497a02989c6bb29a00902d4de4ab Mon Sep 17 00:00:00 2001 From: mesalogo Date: Sun, 4 Oct 2026 09:26:31 +0800 Subject: [PATCH] docs: add the desktop performance phase 1 report and refresh the principle gaps --- docs/architecture/performance-principles.md | 6 +- .../performance-phase-1-report-2026-10-04.md | 96 +++++++++++++++++++ 2 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 docs/review/performance-phase-1-report-2026-10-04.md diff --git a/docs/architecture/performance-principles.md b/docs/architecture/performance-principles.md index 53d47f42..82182f6c 100644 --- a/docs/architecture/performance-principles.md +++ b/docs/architecture/performance-principles.md @@ -128,14 +128,14 @@ Main 负责窗口、生命周期、权限和消息转发。数据库查询、文 ## 4. 当前差距 -截至 2026-10-03,按原则对照的主要差距: +截至 2026-10-04(第一期结项,见 `docs/review/performance-phase-1-report-2026-10-04.md`),按原则对照的主要差距: | 原则 | 差距 | | --- | --- | -| P1 | 写入和大量同步数据库调用仍在 Main;没有独立数据进程。文档解析、分块和大文件哈希已移到 worker | +| P1 | 同步数据库调用仍在 Main,没有独立数据进程;但热点读已在 worker,高频写单次 0.1–0.3 ms,WAL checkpoint 在后台线程,启动恢复按索引读取。文档解析、分块和大文件哈希已移到 worker。消息附加数据冗余(子任务工具输出、`tools` 与 `blocks` 重复),大会话读取约 170 ms | | P2 | `App.tsx` 约 7,900 行。输入区、隐藏路由、任务和结果事件、切换会话已不再整体重渲染 App;当前会话的流式吸收(每 250 ms)、队列和活动记录仍经过 App | | P3 | 已基本满足:流式输出和终端输出都已按帧合并 | | P4 | 活动记录已改为增量保存、按页读取(界面只保留已加载的页,计数和分组来自 Main 的汇总);部分 `*Changed` 通知之后还会重新查全量 | | P5 | 已基本满足:消息、会话、笔记、文件树、知识库文档表格都只渲染可见部分 | -| P6 | 已有基线(`npm run perf:startup`):启动到输入框可用约 1.0 秒,Main 模块加载约 415 ms、本地工具环境初始化约 155 ms,还没有优化 | +| P6 | 空配置启动到输入框可用约 0.96 秒;真实数据(2.4 GB)约 1.36 秒。本地工具环境已后台初始化,低频模块按需加载 | | P9 | 性能阈值还没有接入 CI,也没有真实低端机的基线 | diff --git a/docs/review/performance-phase-1-report-2026-10-04.md b/docs/review/performance-phase-1-report-2026-10-04.md new file mode 100644 index 00000000..007ed156 --- /dev/null +++ b/docs/review/performance-phase-1-report-2026-10-04.md @@ -0,0 +1,96 @@ +# 桌面端性能改造(第一期,参照 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)的顺序。