Files
endorphin-tessera-gui/docs/performance-study.md
T

64 lines
6.4 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.
# 场景交互性能研究
## 结论
性能问题有可验证的解决路径,但单改 Aster 字典不能让当前世界 UI 达到稳定 60 FPS。本 PR 交付可重复基准和研究记录;去除字符串键比较临时分配的改动仍在独立 Aster 分支,未随本 PR 集成;面板纹理缓存实验因当前示例收益不足而撤回。没有实现 GPU 后端或宣称完成性能目标。
## 方法
在 Apple M4 Pro、macOS 15.6 本机使用 release 构建,固定 1024×800 逻辑视口、1× / 2× 像素比例,分别加载 world-ui 和 scene3d 示例。每组执行 33 次真实 scene-orbit 运行时分发,前 3 次作为预热,统计后 30 次的均值、P50、P95。每次先测分发到文档更新,再测变化后的软件绘制,最后测相同显示列表的缓存绘制。没有运行 Console 编译来代替原生事件。
```sh
cargo test --release --locked scene_interaction_performance -- --ignored --nocapture --test-threads=1
```
这是无窗口的运行时与软件渲染基准,包含回调、快照、布局和运行时收尾,但不包含本地 HTTP、OS 事件排队、窗口呈现或输入到显示延迟。阶段耗时不能简单当作实测 FPS。时间是本机样本,不是跨设备保证;基准默认 ignored,普通回归不以绝对耗时断言通过。
## 对照结果
世界 UI、2× 像素比例,单位 ms:
| 条件 | 更新均值 | 更新 P95 | 变化绘制均值 | 变化绘制 P95 |
| --- | ---: | ---: | ---: | ---: |
| 原始 Aster | 8.456 | 8.843 | 18.704 | 20.742 |
| 借用字符串键比较 | 6.842 | 7.226 | 18.598 | 20.665 |
| 再加面板纹理缓存实验 | 6.823 | 7.053 | 18.410 | 20.482 |
去掉字符串键比较的分配后,本组更新均值减少约 19%,绘制基本不变。面板缓存的绘制收益约 1%,不足以证明值得在本次增加缓存与失效复杂度,因此撤回。
作为对照,普通 scene3d 示例在 2× 下更新约 0.94 ms、变化绘制约 6.15 ms;它的视口尺寸、覆盖像素和 UI 复杂度不同,不能据此把两个示例的全部差值都归给某一层。
## Aster 发现与保留的修改
`EndorDictObject` 用插入有序的数组存储,`dict_position` 逐项调用 `key_equal`。原实现每次比较都会把内联文本或托管 String 转成新的 String;查找名称时会重复分配和复制候选键。
本次只改为借用字符串切片比较。保留线性查找、原 key_equal 分支、对象检查、只读依赖观察、键的插入身份与顺序、写入验证和引用计数流程。新增测试覆盖空文本、普通文本、Unicode、托管 / 内联字符串等价替换、删除和引用释放。
没有把通用字典直接改成 HashMap,也没有绕过 heap.replace_payload 的事务性边验证。前者还需处理托管键相等 / 哈希与顺序语义;后者涉及 GC、失败原子性和只读保护。它们不属于本次已经证明安全的改动。
## 尚未解决的主要成本
1. 世界 UI 的摄像机变化后,当前统计仍为 measured=8、arranged=88;普通 3D 为 measured=0、arranged=14。数据证明相机更新没有彻底绕开排版。
2. 3D 变化帧仍在窗口线程逐像素进行 CPU 绘制。当前世界 UI 的绘制本身已超过 60 Hz 的 16.7 ms 预算,其他 CPU 优化不能消除这个事实。
3. 原生连续输入仍逐项经本地 HTTP 发送,有界队列不等于按显示帧合并;真实排队和呈现延迟需要另外测量。
## 后续实施顺序与条件
1. **相机更新专用路径。** 复用已有 Mount 几何、UI 排版和绘制结果,仅更新视图 / 投影、可见性和命中映射。必须检查源 measure / arrange / paint 的实际读取依赖;源函数若读取相机,应继续正确失效。不能无条件跳过所有布局或绘制。验收:不依赖相机的 UI 在旋转时零测量、零重新排版,依赖相机的源协议回归仍通过。
2. **按帧收集连续输入。** 原生操作直接进入进程内通道,连续手势按捕获会话 / 目标与顺序合并;点击、页面切换和运行时替换保持边界。外部 HTTP API 保留严格版本校验。验收包括缩放锚点、非交换手势顺序、嵌套捕获与过期会话,不能只检查最终数值。
3. **GPU 合成与独立渲染。** 现有不可变网格、变换、相机、深度和 UV 数据可以成为渲染输入;VM 对象留在运行时线程。GPU 应直接向窗口表面呈现,同时合成 2D / 3D 内容,避免每帧 GPU→CPU 回读后再交给 softbuffer。跨线程队列只保留最新可呈现快照;纹理、缓冲与缓存均需资源预算和正确失效。
建议验收目标:固定示例 2× 下相机更新 P95 ≤2 ms、GPU 绘制 P95 ≤8 ms,另外记录真实窗口的帧间隔和输入到呈现延迟。目标尚未达到,也没有用无窗口基准宣称原生 60 FPS。
## 检查说明
Aster 全工作区测试发现 compiler 的 classes 测试中两项解析失败(第三行 expected EOF),以及 core 的 managed_coroutine_hard_budget_accumulates_and_error_releases_frames 指令预算失败。将对象实现恢复为未优化的基线后,这三项失败均能复现,说明不是本次借用字符串比较引入;不把全工作区标为全绿。对象层测试通过,Aster 全工作区 Clippy / 格式通过;GUI 为 186 项通过、1 项默认忽略的基准,GUI Clippy / 格式通过。该基准已经另行在 release 模式实际执行。
本次没有修改用户指向的 builtins.rs 第 176 行(该处是函数对象定义)。实际热路径修改位于 Aster 的 store_builtins.rs。
## PR #6 主线兼容修复
2026-11-12:合入最新 GUI main,保留 main 的 Aster f3e1670,而非旧性能分支 fd247ac。旧引用缺少 GUI 目前使用的精确读取依赖接口,不能为性能实验回退。上文数值是原有实验记录,不代表当前主线已经采用借用键优化。本 PR 的最终差异仅包括本研究记录和默认 ignored 的基准;Aster 优化需单独更新其分支并审阅后再集成。PR 标题中的 WIP 将移除,交付范围为可运行基准,不承诺上述后续性能目标。
本次兼容修复检查:GUI `cargo test --locked` 为 186 passed / 1 ignored;Clippy(全部 target,警告视为错误)、格式和差异空白检查通过。最初沙箱内 9 项 HTTP 测试因不能监听本地端口失败;允许回环网络后全套重跑通过。本次未重跑历史 release 性能采样,也未修改 Aster。