quest-perf
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseQuest performance: the budget, the lie, and the capture
Quest 性能:帧预算、误导性指标与捕获分析
Performance work on Horizon OS fails in one of two ways: optimising without a
capture, or reading the capture wrong. This skill fixes the second first, because
the most-quoted number on the platform — — is misleading exactly when it
matters.
GPU%For a whole-product roadmap or stage audit, use ; a single technical task stays with this owner. If absent, identify the current stage, its evidence and the next prerequisite inline.
quest-lifecycleRead when choosing the render pipeline or investigating tile, render-pass, geometry, overdraw and asset costs.
references/mobile-rendering.mdHorizon OS 上的性能工作往往败在两种方式之一:未捕获数据就进行优化,或错误解读捕获数据。本 skill 优先解决第二种问题,因为平台上最常被引用的数字————恰恰在最关键的时候具有误导性。
GPU%若需要制定完整的产品路线图或进行阶段审计,请使用 ;单个技术任务仍由本 skill 负责。如果该 skill 不存在,请直接在此处说明当前阶段、对应证据和下一项前置条件。
quest-lifecycle选择渲染管线,或排查 tile、render-pass、geometry、overdraw 和 asset 成本时,请阅读 。
references/mobile-rendering.mdThe budget is a deadline, not a target
帧预算是截止时间,而不是目标
| Refresh rate | Time per frame |
|---|---|
| 72 Hz | 13.9 ms |
| 90 Hz | 11.1 ms |
| 120 Hz | 8.3 ms |
CPU, render-thread, GPU and compositor work form a pipeline and can overlap
across frames. Compare the critical path and synchronization against the
deadline; do not add independent CPU/GPU samples as a universal frame-time
formula. Missed submissions may invoke reprojection, with visible artifacts
that depend on motion, depth and the selected runtime path.
| 刷新率 | 每帧时间 |
|---|---|
| 72 Hz | 13.9 ms |
| 90 Hz | 11.1 ms |
| 120 Hz | 8.3 ms |
CPU、render thread、GPU 和 compositor 工作构成一条 pipeline,并且可以跨帧重叠执行。请将 critical path 和同步情况与截止时间进行比较;不要把相互独立的 CPU/GPU 采样值相加,当作通用的帧时间计算公式。提交超时可能触发 reprojection,并产生可见伪影;这些伪影取决于运动、深度以及所选的 runtime path。
The GPU% lie, and the 50% threshold
GPU% 的误导性,以及 50% 阈值
When an app drops to half rate the GPU finishes early and idles, so utilisation
falls while the app is firmly GPU-bound.
text
FPS=36/72 Stale=36 GPU%=0.65 App=18.05ms- — half rate: every frame shown twice.
FPS=36/72 - — the real per-frame GPU time, against a 13.9 ms budget.
App=18.05ms - — measured across the doubled 27.8 ms interval, which is why it reads 65% while the app needs a 23% cut, not the 35% "headroom" it implies.
GPU%=0.65
Rule: read in milliseconds against the refresh-rate budget. Only trust
near saturation. To climb back out of half rate, GPU work must fit one
refresh interval — i.e. utilisation must fall below ~50% while at half rate.
AppGPU%If is inside budget and remains non-zero, inspect CPU submission,
synchronization and compositor timing in a trace. That symptom alone does not
prove a CPU bottleneck. The worked half-rate example above assumes the stated
metric definitions and no intentional SpaceWarp mode; verify both first.
AppStale当应用降至一半刷新率时,GPU 会提前完成并闲置,因此即使应用明确处于 GPU-bound 状态,GPU 利用率反而会下降。
text
FPS=36/72 Stale=36 GPU%=0.65 App=18.05ms- ——一半刷新率:每一帧显示两次。
FPS=36/72 - ——实际的单帧 GPU 时间,对应 13.9 ms 的预算。
App=18.05ms - ——在翻倍后的 27.8 ms 区间内测得,因此读数为 65%,但应用实际需要削减 23%,而不是它看似所暗示的 35%“余量”。
GPU%=0.65
**规则:读取 的毫秒值,并将其与刷新率对应的帧预算比较。只有在 GPU 接近饱和时,才应信任 。要从一半刷新率恢复到完整刷新率,GPU 工作必须能在一个刷新间隔内完成——也就是说,在一半刷新率下,利用率必须降至 低于约 50%。
AppGPU%如果 处于预算内,但 仍非零,应在 trace 中检查 CPU 提交、同步和 compositor 时序。该症状本身不能证明存在 CPU 瓶颈。上述一半刷新率示例假设采用文中所述的指标定义,并且未有意启用 SpaceWarp 模式;请先验证这两点。
AppStaleSelect a lever from the measured bottleneck
根据实测瓶颈选择优化手段
Read when choosing multiview, render scale,
foveation, layers, assets, shaders or reprojection. It links each experiment to
its prerequisites, visual failure cases and target-device evidence.
references/rendering-playbook.md- Dynamic Resolution — tune render scale through the engine/SDK's supported control path; verify actual behavior rather than assuming the OS enables it.
- Foveation — distinguish fixed from eye-tracked; test supported levels and quality. A simple shader can cost more with FFR than without it.
- Refresh rate — request a rate the representative workload sustains; observe actual runtime and thermal behavior rather than promising an automatic rate change.
- Application SpaceWarp — a supported depth/motion-vector integration with artifact and latency tests, not an automatic rescue or guaranteed percentage gain.
选择 multiview、render scale、foveation、layers、assets、shaders 或 reprojection 时,请阅读 。它将每项实验与前置条件、视觉失效场景和目标设备证据关联起来。
references/rendering-playbook.md- Dynamic Resolution——通过 engine/SDK 支持的 control path 调整 render scale;应验证实际行为,而不是假定 OS 会启用它。
- Foveation——区分 fixed 与 eye-tracked;测试受支持的级别和质量。简单的 shader 在启用 FFR 时可能比未启用时成本更高。
- 刷新率——请求 representative workload 能够持续维持的刷新率;观察实际 runtime 和 thermal 表现,而不是承诺自动切换刷新率。
- Application SpaceWarp——对受支持的 depth/motion-vector 集成进行 artifact 和 latency 测试;它不是自动补救措施,也不保证固定百分比的性能提升。
Capture chain — what each tool answers
捕获链路——每个工具能回答什么问题
| Question | Tool | How |
|---|---|---|
| Am I missing frames at all, and where | logcat VrApi stats ( | |
| Live numbers inside the headset | OVR Metrics Tool ( | |
| CPU vs GPU, thread timeline, stalls | Perfetto | |
| Which C/C++ functions burn the CPU | simpleperf | Android NDK's simpleperf against the running package |
| Which draw call, shader or render stage burns the GPU | RenderDoc Meta fork | |
Meta ships task skills for two of these — and
, plus for general on-device debugging. When
they are installed, this skill decides what to measure and they drive the tool.
hz-perfetto-debughz-simpleperf-debughz-vr-debugreferences/capture-playbook.md| 问题 | 工具 | 使用方式 |
|---|---|---|
| 是否确实存在丢帧,以及丢在哪里 | logcat VrApi stats( | |
| 头显内的实时数据 | OVR Metrics Tool( | |
| CPU 与 GPU 对比、线程时间线、停顿 | Perfetto | |
| 哪些 C/C++ 函数消耗 CPU | simpleperf | 针对运行中的 package 使用 Android NDK 的 simpleperf |
| 哪个 draw call、shader 或 render stage 消耗 GPU | RenderDoc Meta fork | |
Meta 为其中两种工具提供 task skill—— 和 ——此外还有 ,用于常规的设备端调试。安装这些 skill 后,本 skill 负责决定测量什么,再由它们驱动具体工具。
hz-perfetto-debughz-simpleperf-debughz-vr-debugreferences/capture-playbook.mdMethod, so a second capture means something
方法:让第二次捕获真正有意义
- Reproduce on a release build on a real headset. A simulator run
(,
xrsim) checks supported simulated behavior, not headset performance.spatialsim - Note refresh rate and the resulting budget before looking at anything else.
- Capture with the app in the worst scene, not the menu.
- Change one thing; re-capture; compare ms, not impressions.
App - Record the pair (before/after ,
App, scene, build id) in the project's own notes — a performance claim with no capture is an opinion.Stale
- 使用 真实头显上的 release build 复现问题。模拟器运行(、
xrsim)只能验证受支持的模拟行为,不能反映头显性能。spatialsim - 查看任何其他内容之前,先记录刷新率及其对应的预算。
- 在应用处于最差场景时捕获,不要在菜单界面捕获。
- 每次只更改一项;重新捕获;比较 的毫秒值,而不是凭印象判断。
App - 将前后对比数据(、
App、场景、build id)记录到项目自己的笔记中——没有捕获数据的性能结论只是主观看法。Stale
Gotchas that cost a debugging round
容易导致调试返工的陷阱
- A thermally throttled headset invalidates the comparison. Long sessions drift; let it cool or state the temperature state with the number.
- Dev-mode overlays and logging cost frames. Measure with them off, then turn them on only to read the numbers you cannot get otherwise.
- Counter semantics depend on capture/runtime mode. Inspect timestamps and reprojection state before interpreting a stale-frame count as dropped work or pipeline latency.
- Draw calls are a CPU cost and fill is a GPU cost. Cutting draw calls on a fill-bound frame moves nothing, which is why the capture comes first.
- WebXR has its own counters — draw-call metrics in the browser docs; see
before applying native advice to a web build.
quest-webxr
Frame budgets, the 65%/18.05 ms worked example and the recovery mechanisms were
read from on 2026-09-20;
re-verify with .
documentation/native/android/os-missed-frames.mdmetavr docs search "missed frames"- 发生热降频的头显会使对比结果失效。 长时间运行期间会发生温度漂移;应让头显冷却,或在记录数据时注明温度状态及具体数值。
- 开发者模式的 overlay 和日志记录会消耗帧时间。 测量时应将其关闭,只在需要读取其他方式无法获得的数字时再开启。
- 计数器的语义取决于 capture/runtime 模式。 在把 stale-frame 计数解读为工作未完成或 pipeline latency 之前,应检查时间戳和 reprojection 状态。
- Draw call 属于 CPU 成本,fill 属于 GPU 成本。 在 fill-bound 帧上减少 draw call 不会带来任何改善,这正是必须先进行 capture 的原因。
- WebXR 拥有自己的计数器——浏览器文档中的 draw-call 指标;在将 native 建议应用于 Web 构建之前,请先查看 。
quest-webxr
帧预算、65%/18.05 ms 示例及恢复机制依据 (2026-09-20)整理;请使用 重新验证。
documentation/native/android/os-missed-frames.mdmetavr docs search "missed frames"Triggers
触发词
More phrases that route here: "profile the headset" / "профилировать шлем", "app is hot" /
"шлем греется", "judder" / "джаддер", "GPU bound" / "упёрлись в GPU", "perfetto trace" /
"трейс perfetto", "simpleperf", "RenderDoc", "OVR Metrics", "stale frames", "SpaceWarp",
"foveated rendering" / "фовеальный рендеринг", "72 vs 90 Hz".
更多会路由到这里的短语:“分析头显”/“профилировать шлем”、“应用过热”/“шлем греется”、“卡顿”/“джаддер”、“受 GPU 限制”/“упёрлись в GPU”、“Perfetto trace”/“трейс perfetto”、“simpleperf”、“RenderDoc”、“OVR Metrics”、“stale frames”、“SpaceWarp”、“foveated rendering”/“фовеальный рендеринг”、“72 vs 90 Hz”。