Profiling 101:帧预算、帧结构与测量方法
按Unity 6官方指南第8—18页复现官方单元 1,建立可测量、可反证、可回归的性能证据。
问题:怎样证明掌握的是官方单元 1,而不是记住几个工具名?
先预测:如果只看到最终帧率或一张截图,不知道设备、构建、场景、输入和采样方式,能否判断修改真的有效?不能。性能结果是测试上下文与程序行为共同产生的,脱离上下文的数字既不能复现,也不能指导下一步。
性能目标应写成毫秒预算,而不是平均FPS。CPU主线程、渲染线程与GPU像流水线处理不同帧,真正限制吞吐的是最慢阶段;VSync和等待样本必须作为同步信号解释。
官方目录边界
本页严格对应Unity Technologies的《Ultimate guide to profiling Unity games (Unity 6 edition)》第8—18页。以下目录项必须在实现、实验或证据中出现:
- Understanding frame budget
- Frames per second: A deceptive metric
- The anatomy of a frame
- Understanding if you are GPU or CPU bound
- What is VSync?
- Sample- vs instrumentation-based profiling
- Increase profiling detail with Profiler markers
- Profiler modules
本站以中文重新组织解释、代码和实验,不逐字复制原文。API示例以Unity 6思路为准;具体包版本和目标平台能力仍要在项目清单中固定。
核心模型与不可变条件
性能目标应写成毫秒预算,而不是平均FPS。CPU主线程、渲染线程与GPU像流水线处理不同帧,真正限制吞吐的是最慢阶段;VSync和等待样本必须作为同步信号解释。
本单元的不可变条件是:相同目标帧率必须换算为明确毫秒预算,CPU与GPU耗时须在目标设备构建中分开记录,插桩开销也要进入结论。 只要输入条件、观测边界或结果合同有一项改变,就不能把两次测量直接相减。先解释变化来源,再决定是否建立新的基线。
五个必须落到证据的术语
它在本单元中不是孤立名词,而要落到“目标FPS → 帧时间 → CPU准备 → 渲染线程 → GPU执行 → 显示同步”的数据链,并能由一次保存的采样或状态记录验证。
它在本单元中不是孤立名词,而要落到“目标FPS → 帧时间 → CPU准备 → 渲染线程 → GPU执行 → 显示同步”的数据链,并能由一次保存的采样或状态记录验证。
它在本单元中不是孤立名词,而要落到“目标FPS → 帧时间 → CPU准备 → 渲染线程 → GPU执行 → 显示同步”的数据链,并能由一次保存的采样或状态记录验证。
它在本单元中不是孤立名词,而要落到“目标FPS → 帧时间 → CPU准备 → 渲染线程 → GPU执行 → 显示同步”的数据链,并能由一次保存的采样或状态记录验证。
它在本单元中不是孤立名词,而要落到“目标FPS → 帧时间 → CPU准备 → 渲染线程 → GPU执行 → 显示同步”的数据链,并能由一次保存的采样或状态记录验证。
从输入到结论的诊断链
主链为:目标FPS → 帧时间 → CPU准备 → 渲染线程 → GPU执行 → 显示同步。每个节点保存构建提交、设备ID、场景检查点、帧号或快照ID、当前预算、实际值和首个异常。下一节点只消费上一节点已验证的事实,不能用“感觉更流畅”跨过中间归因。
目标帧率首先换算为单帧毫秒预算:
反过来,某一帧时间对应的瞬时帧率为:
CPU 与 GPU 流水并行时,稳态吞吐近似受较慢一侧限制,而不是把两者简单相加:
用于回归门的可用余量写成预算与长尾帧时间之差:
1. Understanding frame budget
30 FPS对应约33.33毫秒,60 FPS对应约16.67毫秒,90 FPS对应约11.11毫秒。单个超预算帧也会形成卡顿,因此平均值必须配合最长帧或高分位数。
复现时把这一项写成“输入条件—观测位置—判断阈值—下一动作”四列记录。输入条件决定数据是否可比,观测位置说明要看哪个线程、模块、对象或平台计数器;阈值来自本项目预算,下一动作必须能指向一次单变量实验。
2. Frames per second: A deceptive metric
FPS是帧时间的倒数,900降到450 FPS与60降到56.25 FPS都只增加约1.11毫秒。用百分比看FPS会夸大高帧率变化并掩盖目标附近的真实风险。
复现时把这一项写成“输入条件—观测位置—判断阈值—下一动作”四列记录。输入条件决定数据是否可比,观测位置说明要看哪个线程、模块、对象或平台计数器;阈值来自本项目预算,下一动作必须能指向一次单变量实验。
3. The anatomy of a frame
CPU先执行引擎代码和游戏脚本,再由渲染线程把命令转成图形API调用;GPU通常同时处理上一帧。CPU和GPU时间不是简单相加,吞吐取决于最长链和同步点。
复现时把这一项写成“输入条件—观测位置—判断阈值—下一动作”四列记录。输入条件决定数据是否可比,观测位置说明要看哪个线程、模块、对象或平台计数器;阈值来自本项目预算,下一动作必须能指向一次单变量实验。
4. Understanding if you are GPU or CPU bound
CPU受限时优化分辨率通常无效,GPU受限时减少C#循环也不会改善帧率。先用CPU与GPU总时间、等待标记和目标平台工具建立因果方向。
复现时把这一项写成“输入条件—观测位置—判断阈值—下一动作”四列记录。输入条件决定数据是否可比,观测位置说明要看哪个线程、模块、对象或平台计数器;阈值来自本项目预算,下一动作必须能指向一次单变量实验。
5. What is VSync?
VSync把提交节奏限制到显示刷新,可能让CPU或GPU出现等待。关闭VSync用于测量上限时,要记录设置变化;最终体验验证仍需恢复发布配置。
复现时把这一项写成“输入条件—观测位置—判断阈值—下一动作”四列记录。输入条件决定数据是否可比,观测位置说明要看哪个线程、模块、对象或平台计数器;阈值来自本项目预算,下一动作必须能指向一次单变量实验。
6. Sample- vs instrumentation-based profiling
采样式工具定期抓调用栈,开销低但可能漏掉短函数;插桩式工具给已标记区域精确层级,却会改变执行成本。两者结论不能脱离采样频率和标记密度。
复现时把这一项写成“输入条件—观测位置—判断阈值—下一动作”四列记录。输入条件决定数据是否可比,观测位置说明要看哪个线程、模块、对象或平台计数器;阈值来自本项目预算,下一动作必须能指向一次单变量实验。
7. Increase profiling detail with Profiler markers
ProfilerMarker适合围住业务阶段并携带稳定命名。标记应对应可行动的系统边界,例如AI感知、路径请求和结果应用,而不是给每行代码制造噪声。
复现时把这一项写成“输入条件—观测位置—判断阈值—下一动作”四列记录。输入条件决定数据是否可比,观测位置说明要看哪个线程、模块、对象或平台计数器;阈值来自本项目预算,下一动作必须能指向一次单变量实验。
8. Profiler modules
CPU、GPU、Rendering、Memory、Physics等模块回答不同问题。只启用当前假设需要的模块,并保存模块配置,才能让前后采样具有可比性。
复现时把这一项写成“输入条件—观测位置—判断阈值—下一动作”四列记录。输入条件决定数据是否可比,观测位置说明要看哪个线程、模块、对象或平台计数器;阈值来自本项目预算,下一动作必须能指向一次单变量实验。
三步复现与分步观察
可执行实现骨架
下面的代码只承担本单元的数据所有权或测量边界。真正项目应把阈值放入版本化配置,并让证据文件引用同一个配置哈希。
using Unity.Profiling;
static readonly ProfilerMarker SimulateMarker =
new("Gameplay.Simulate");
void Update()
{
using (SimulateMarker.Auto())
Simulate(Time.deltaTime);
}
double FrameBudget(int targetFps) => 1000.0 / targetFps;每次采集都保存结构化元数据,避免报告与原始文件失联:
{
"chapter": "prof-01-profiling-101",
"officialPages": "第8—18页",
"chain": ["目标FPS", "帧时间", "CPU准备", "渲染线程", "GPU执行", "显示同步"],
"device": "target-low-tier-01",
"build": "commit-and-unity-version",
"scenario": "fixed-checkpoint",
"baseline": "capture-before.data",
"candidate": "capture-after.data",
"normal": true,
"boundary": true,
"failureReplay": true
}自动门输出必须同时保留通过值和拒绝原因,而不是只给一个绿色图标:
PASS context=device+build+scene+quality+input
PASS chain=目标FPS -> 帧时间 -> CPU准备 -> 渲染线程 -> GPU执行 -> 显示同步
PASS invariant=相同目标帧率必须换算为明确毫秒预算,CPU与GPU耗时须在目标设备构建中分开记录,插桩开销也要进入结论。
REJECT missing-raw-data | changed-context | hidden-quality-loss | unreplayed-failure两个必须主动制造的失败样本
证据矩阵与签发标准
| 维度 | 正常样本 | 边界样本 | 失败样本 | 签发条件 |
|---|---|---|---|---|
| 上下文 | 固定设备与构建 | 最低档或长时间运行 | 故意改变一项条件 | 差异可解释 |
| 主链 | 六节点均有记录 | 预算附近输入 | 在首个节点注入偏差 | 能定位首因 |
| 结果 | 达到性能合同 | 无长尾越界 | 主动制造回归 | 同输入可复验 |
| 副作用 | 画面玩法一致 | 生命周期完整 | 降质或转移成本 | 所有门同时通过 |
练习:把官方单元 1变成可审计交付
小结
- 是否能逐项指出本页覆盖的官方目录项,而没有用通用性能建议替代?
- 是否沿“目标FPS → 帧时间 → CPU准备 → 渲染线程 → GPU执行 → 显示同步”保存了可追溯中间证据?
- 是否区分定位工具的干扰与发布构建的真实预算?
- 是否主动制造失败,并在相同输入下证明修复没有转移成本?