Files
Workspace/Docs/Performance/2026-09-28.md
T
cneicy 08246ddb01
Validate ShrinkSDK Workspace / catalog (push) Successful in 5s
Validate ShrinkSDK Workspace / unity (push) Successful in 3m20s
feat: integrate performance upgrade and agent inspection tooling
2026-09-29 10:16:02 +08:00

81 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.
# 性能与跨宿主验收 — 2026-09-28 UTC
本次为本地工作区验收,不代表远程发布、生产容量承诺或所有后端的性能保证。原始测量时间保留在 JSON/XML 中;Windows 本地显示日期可能为 9 月 29 日。
## 方法与证据边界
- Windows x64;Unity 2022.3.62f3 的实际 Standalone Player,而非用 EditMode 冒充 Player;另有 .NET 8.0.31、.NET 10 和 Godot 4.6.3 Mono 的实际运行。
- 网络矩阵:64 B/1 KB/32 KB 负载参数,1/32/256 会话;RPC、广播、慢消费者、突发队列。Loopback 会话不是 OS socket;TCP 文件是实际本机 socket,且 RPC 采用串行往返采样,不等于高并发容量压测。
- Context:10/100/1000 组件依赖链,10,000 次创建退役;旧实现来自 Context 子模块提交 b93f3e61223e7572588b67c0d3935073817f0da6,不是重新编写的假想基线。
- 存档:100 KB/1 MB/10 MB,前台/后台编码;.NET 每组合 10 次并覆盖加密,Player 记录真实阶段耗时与采集线程。输入主要为字符串快照,不能推断复杂游戏对象的采集成本。
- 单机开发环境、有限样本,非隔离实验机;p99 易受 JIT、GC、系统调度影响。没有可靠的多轮置信区间,不将小幅波动称为普遍提升。
- Unity 的 GC.GetAllocatedBytesForCurrentThread 对已知分配返回零,已弃用该结果。Player 改用经已知数组分配校准的 GC.Alloc 事件计数;事件次数不是 B/op。独立 .NET 的字节计数与 Player 分开报告。
原始数据位于 [Data/2026-09-28](Data/2026-09-28/);Player 完整输出同时保存在 XML 与 player-output.txt。工具、测试源代码保留在 Tools/AgentSupport 与 Assets/AgentSupportTests。
## 已量化的核心变化
### Context(.NET 8)
| 组件数 | 旧诊断 p95 µs | 新诊断 p95 µs | 旧 B/op | 新 B/op |
|---:|---:|---:|---:|---:|
| 10 | 9.4 | 11.7 | 10,456 | 7,312 |
| 100 | 538.2 | 116.9 | 108,016 | 73,456 |
| 1000 | 7,426.4 | 548.3 | 1,083,616 | 735,328 |
大规模诊断通过按依赖键访问 provider 候选索引获益;10 个组件的 p95 本轮反而略高,不能宣称所有规模都更快。10,000 次退役后旧运行时持有 10,000 个 fiber,新运行时为 0,诊断历史有界 64。弱引用测试验证实例可回收;整进程 GC 差值可能为负,不将其解读为精确节省字节数。
深链生命周期改为迭代队列展开,避免 1000 层同步完成/撤回造成栈溢出;不改变依赖排空与效应撤回顺序。
### 网络封装(.NET 8)
| 负载参数 | 旧 JSON 外封装 B/op | 新 v2 外封装 B/op |
|---:|---:|---:|
| 64 B | 3,504 | 32 |
| 1 KB | 10,560 | 32 |
| 32 KB | 230,328 | 32 |
这里只比较已经编码的消息体如何封装,不是端到端零分配。新封装取消外层 JSON/Base64,消息直接写入池化 buffer;仍有 writer 对象、消息反序列化、排队和 transport 的独立成本。JSON 与生成式 MessagePack 的完整消息编码对照见原始 rows,不能套用此表的 32 B。
队列突发测试输入 10,000 个显式可替换状态,32 个 session 分区最终保留 32 项、32 KB,返回 9,968 次 Replaced;一次 4 KB budget 泵送完成 4 项。可靠操作不使用这种替换机制,满队列显式拒绝。
### 实际 TCP 与后端选择
256 个本机 TCP 连接、1 KB、256 次串行 RPC 往返:
| 运行时 | p50 µs | p95 µs | p99 µs | ops/s |
|---|---:|---:|---:|---:|
| .NET 8 | 99.3 | 258.9 | 355.1 | 6,911 |
| .NET 10 | 88.4 | 250.8 | 384.3 | 7,392 |
其他参数组合有升有降;本轮未证明目标场景稳定达到 15% 收益,因此不引入新的默认 .NET 10 专属服务端依赖。Pipelines 仅有内存 buffer roundtrip 微实验,未实现等价 socket 后端对照,不足以采纳。共享运行时继续 netstandard2.1。
TCP 慢消费者测试证明有界队列和拒绝反馈,不证明业务消费成功:该突发负载使用 RPC 消息的一次性发送路径,记录中存在 DispatchMissCount;不能将该行视为完整 handler 吞吐测试。可靠队列行为、会话隔离、取消和故障另由功能测试验证。KCP 未作独立吞吐结论。
### EventBus 与存档
.NET 8 同步 Post、同步完成的异步 Post 为 0 B/op;注册/撤回 224 B/op,按需绑定诊断 120 B/op。同步路径的捕获闭包已移出快路径;Unity 的结构体事件空值检查另外增加值类型短路,避免 Mono 装箱。
校准后的 Player 实测:独立 Bus 10,000 次同步发布为 0 次分配事件;当前默认 Bus 为 10,000 次分配事件。修复值类型空值检查前默认通道是 20,000 次,不能将早先字节 API 的零值作为基线。
默认全局 Bus 可能带网络桥或诊断观察器;接口观察器需要结构体装箱,不能把独立 Bus 的零分配结果扩大到所有配置。Player 同时测量默认与独立通道,并为引用类型空值保留异常检查。
存档采集仍在调用线程,后台开关仅移动脱离宿主对象的快照编码与加密。示例 .NET 8 的 10 MB 未加密平均编码为前台约 7.68 ms、后台约 8.21 ms;主要收益是主线程工作转移,而非宣称总保存时间必然缩短。Player 的冷启动与各阶段实测见 player-output.txt;未隐藏首轮高耗时。格式、原子落盘、取消时备份保留及损坏回退均有测试。
## 复现
在已还原依赖的仓库运行:
~~~powershell
pwsh Tools/AgentSupport/Benchmarks/Prepare-Baseline.ps1
dotnet run --project Tools/AgentSupport/Benchmarks -c Release -f net8.0 -- Artifacts/AgentSupport/benchmark-net8.json
dotnet run --project Tools/AgentSupport/Benchmarks -c Release -f net10.0 -- Artifacts/AgentSupport/benchmark-net10.json
dotnet run --project Tools/AgentSupport/Benchmarks -c Release -f net8.0 -- --tcp Artifacts/AgentSupport/tcp-net8.json
dotnet test Tools/AgentSupport/RuntimeTests
dotnet test Tools/AgentSupport/Shrink.Inspect.Tests
~~~
Unity 用 TestRunner 的 StandaloneWindows64 Player 运行 ShrinkSDK.AgentSupport.PlayerTests;Editor 辅助入口 PlayerAcceptance.Run() 将本次结果保存到 Artifacts/AgentSupport/unity-player-results.xml。基线脚本读取子模块 HEAD:以后 HEAD 前进时,应显式使用上述旧提交重建对照,不把新的 HEAD 当成本报告基线。
最终功能验收、消费工程已知失败和导航覆盖范围见 [AgentSupportAcceptance](../AgentSupportAcceptance.md);协议和回退见 [迁移说明](../NetworkV2Migration.md)。