OVR Metrics Tool allows developers to track a variety of performance statistics on apps running on Oculus mobile devices. OVR Metrics Tool can give developers an overview of app performance and be used to verify expectations.
When using OVR Metrics Tool, developers must select which statistics to track. This can be done by using the Basic and Advanced buttons on the main page of the app to select a collection of statistics, or by manually selecting them on the Stats tab.
This guide defines all of the OVR Metrics Tool statistics and offers guidance and additional information where possible. Statistics are listed by their name in the Stats tab along with their overlay abbreviation.
The following statistics were introduced in OVR Metrics Tool 1.5. These statistics are not enabled with either the Basic or Advanced buttons.
|Guardian GPU Time||Displays the Guardian GPU time, which is the amount of GPU time used by the Guardian rendering.|
|CPU Utilization Core 0-7||Displays the individual CPU core utilization. Applications are limited to cores 5, 6, and 7.|
|Application VSS, RSS, and Dalvik PSS||Memory statistics to give additional insight into memory usage.|
The following statistics are not enabled with either the Basic or Advanced buttons, and require that ovrgpuprofiler has been enabled from a connected shell.
|Average Vertices Per Frame||Shows the approximate number of vertices shaded per frame. Note that Guardian and system overlays will affect this number.|
|Average Fill Percentage per Eye||An estimate for the average amount of overdraw, based on the number of fragments shaded per frame divided by the eye buffer resolution. 100 represents touching every pixel in the eye buffer only once. Note that Guardian and system overlays will affect this number.|
|Average Instructions per Fragment||Shows the average number of instructions for every shaded fragment.|
|Average Instructions per Vertex||Shows the average number of instructions for every shaded vertex|
|Average Textures per Fragment||Shows the average number of textures for each fragment.|
|Percentage Time Shading Fragments||Shows the percentage of GPU time spent shading fragments.|
|Percentage Time Shading Vertices||Shows the percentage of GPU time spent shading vertices.|
|Vertex Fetch Stall Percentage||Percentage of clock cycles where the GPU cannot make any more requests for vertex data.|
|Texture Fetch Stall Percentage||Percentage of clock cycles where the shader processors cannot make any more requests for texture data.|
|L1 Texture Miss Percentage||Percentage of texture requests to L1 cache that miss the cache.|
|L2 Texture Miss Percentage||Percentage of texture requests to L2 cache that miss the cache.|
|Texture Sample Percentage Using Nearest Filtering||Percent of texture fetches that use the nearest sampling method.|
|Texture Sample Percentage Using Linear Filtering||Percent of texture fetches that use the linear sampling method.|
|Texture Sample Percentage Using Anisotropic Filtering||Percent of texture fetches that use the anisotropic sampling method.|
This section contains statistics that are tracked when the Basic button is selected. These contain most of the important info that developers should track in regards to performance.
|Stale Frame Count (||Shows the number of stale frames. This indicates the number of times a frame wasn’t delivered on time, and the previous frame was used instead.|
Because the CPU and GPU are working in parallel, sometimes rendering a frame takes longer than a single frame’s total time length, but neither the CPU or GPU take longer than a frame individually themselves. Therefore, it is possible for an app to run at 72 FPS, but have 72 stale frames per second. In such situations, the latency between rendering and display time will be higher, but the release tempo of frames will be steady.
Stale frames become an issue when the value is greater than 0 and less than the refresh rate. At this point, some frames are displayed twice in a row, some frames are skipped, and the user will have a poor experience. Extra latency mode can be used in such situations. This feature, which is on by default in Unity and Unreal Engine) tells ATW to always wait an extra frame, and not to consider frames stale unless they aren’t ready after the second frame. If the app does render quickly, the frame will be considered early, but everything will look smooth.
For further reading on how stale frames work, read the blog post Understanding Gameplay Latency for Oculus Quest, Oculus Go and Gear VR.
|App GPU Time (||Displays the app GPU time (in μs, 1/1000th ms), which is the amount of time the application spends rendering a single frame.|
This value is one of the most useful numbers to monitor when optimizing an application. If the length of time shown is longer than a single frame’s length (13.88ms for 72 frames per second), the app is GPU bound. If the length is less than a frame’s length, the app is probably CPU bound.
In addition to using this metric to determine if an app is GPU or CPU bound, it’s also useful to monitor it as you change shaders, add textures, change meshes, and make other changes. This can allow insight into how much headroom remains on the GPU, and if debug logic is used to turn on and off specific objects, you can tell how performance-intensive those objects are.
|GPU Utilization (||Displays the GPU utilization percentage. If this value is maxed 100%, the app is GPU bound. Performance issues due to scheduling may occur if this number is over 90%.|
|CPU Utilization (||Displays the CPU utilization percentage. However, this metric represents the worst performing core, and since most apps are multithreaded, and the scheduler assigns threads as they are available, the main thread of the app may not be represented in this metric.|
|CPU Level (|
GPU Level (
|These metrics specify the CPU and GPU clock levels set by the app. While these levels can be set manually, use of dynamic clock throttling, which increases these numbers if the app is not hitting frame rate at a requested level, is recommended.|
If an app is not making frame rate, reviewing the clock levels can help quickly indicate if performance is CPU or GPU bound, providing a target area for optimization. For example, if an app with performance issues is at CPU 4 and GPU 2, the app must be CPU bound since there is still available GPU overhead. However, if both levels are 4 and the app has issues, this number is not as useful, and other metrics should be used to find potential areas for optimization, such as stale frames, app GPU time, and CPU/GPU utilization.
For more information on the CPU and GPU clock levels, see Power Management.
|Average FPS (||Displays the frame rate in frames per second. A well-performing app should target the refresh rate of the display. See Set Display Refresh Rates for more information.|
|Available Memory (||Indicates the available memory in MB as reported by Android. On Android, memory is handled in a somewhat opaque way, which makes this value useful for only general guidance. For example, if an app goes to the background, the newly foregrounded app and OS operations will pull a lot of memory, and it may crash your app even if Free is reporting that there is memory available.|
This value is most useful as a way to monitor whether memory is being allocated faster than expected, or if memory isn’t being released when expected.
This section contains statistics that are tracked when the Advanced button is selected. When selected, all Basic metrics are tracked as well. These metrics are mainly useful to verify that behavior conforms to expectations based on choices during development.
|Foveation Level (||Indicates the level of Fixed Foveated Rendering (FFR) intensity. This feature can be used to render the edges of your eye textures at a lower resolution than the center, lowering the fidelity of the scene in the viewer’s peripheral vision while reducing the GPU load. This number has direct GPU performance implications, and there will be noticeable visible artifacts on the edge of the screen at higher levels. Pick the most visually acceptable level for the performance increase needed.|
For more information and recommendations, see Fixed Foveated Rendering (FFR).
|Eye Buffer Width (|
Eye Buffer Height (
|This is the resolution of the texture to which the app is rendering. The default for Oculus Quest is 1216x1344. This is useful to verify expectations and to confirm the aspect ratio is correct for the field of view. Resolution has a direct impact on GPU rendering time, where more pixels means more time in fragment shaders.|
|Early Frame Count (||Shows the number of early frames. This indicates the number of frames delivered before they were needed. Early frames are possible when extra latency mode is being used.|
When a few early frames can be ignored, but if this number is persistently high, make sure the CPU and GPU levels aren’t set higher than necessary. If the number of early frames matches the FPS, it’s recommended to either turn off extra latency mode, or take advantage of the headroom by increasing the resolution or shader complexity.
|Used Memory (||Indicates the memory used in MB as reported by Android. Because apps can share memory in Android, this number reports proportional set size (PSS) memory, meaning that this value adds all the unique memory used by the app, and a fractional part of shared memory based on how many apps are sharing it. This makes the number useful in tracking relative memory allocation for your app, but not very useful in showing true memory footprint.|
|Extra Latency Mode (||Indicates whether extra latency mode is enabled. This feature tells ATW to always wait an extra frame and use the previously submitted frame. This allows usage of the whole frame for CPU and GPU, making it easier to hit frame targets with the downside of the loss of one frame of latency. Extra latency mode can make hitting performance targets easier, and its use is highly recommended.|
Extra latency mode is enabled by default when developing with Unity and Unreal Engine. For native mobile development, enable extra latency mode with vrapi_SetExtraLatencyMode.
|Average Prediction (||Shows the prediction time. This is the absolute time between when an app queries the pose before rendering and the time the frame is displayed on the HMD screen.|
This should almost always be a fixed number between 45ms and 50ms. If this number is much higher than expected, the app likely has latency issues when rendering.
|TimeWarp GPU Time (||Displays the ATW GPU time (in μs, 1/1000th ms), which is the amount of time ATW takes to render. This time directly correlates to the number of layers used and their complexity, with equirect and cylinder layers being more expensive on the GPU than quad and projection layers. |
This value may be useful to video apps because ATW taking too long can result in screen tearing in playback.
In addition to those tracked by the Basic and Advanced buttons, the statistics in this section may also provide utility to developers.
|Screen Tear Count (||Shows the number of screen tears. This reports when Asynchronous TimeWarp (ATW) takes too long and experiences a screen tear.|
Screen tears should not happen on Oculus apps unless too many layers are being used. This might occur if quad or cylinder layers are being used to display UI elements, or if multiple overlapping equirect video layers are displayed.
|Swap Interval (||Shows the swap interval, which tells the app how many frames to skip before rendering the next frame. This will almost always be 1, as a value of 2 can cause the app to render at half frame rate, which can be uncomfortable with 6DOF movement.|
This may be set to 2 for debugging purposes, but this setting should never be used in a published app because it’s noticeable whenever the user turns their head.
|Display Refresh Rate (||Shows what the refresh rate of the display is currently set to. This value can be 60 or 72. See Refresh Rate for more information,|
|Battery Level (||Shows the remaining battery level percentage.|
This section contains statistics that were relevant to older hardware, and should not be a concern for Oculus Quest.
|Sensor Temperature (||Shows the sensor temperature in Celsius. This was specifically important for phone-based VR development. For temperature concerns on current headsets, Power Level can be used as an indicator of when temperature is affecting the device’s performance.|
|Power Level (||Indicates the current power level of the device. The reported levels are 0 (NORMAL), 1 (SAVE), and 2 (DANGER). As the device heats up, the power level will automatically change from NORMAL, to SAVE, and eventually to DANGER. Once DANGER is reached, an overheat dialog is displayed.|
Applications should monitor the power level and change their behavior to reduce rendering costs when it enters power save mode. For more information on this topic, see Power Management.
|CPU Frequency (|
GPU Frequency (
Mem Frequency (
|These metrics display the clock speeds of the CPU, GPU, and memory. The CPU and GPU speeds change whenever their CPU Level and GPU Level change, which makes them more useful to monitor since they can be directly adjusted and changed. The clock speeds tied to those levels vary with different SoC’s, and the frequencies cannot be changed.|
|Battery Temperature (||Shows the battery temperature in Celsius. This was specifically important for phone-based VR development. For temperature concerns on current headsets, Power Level can be used as an indicator of when temperature is affecting the device’s performance.|
|Battery Current Now (||Shows the current coming from the battery in milliamps. Developers should optimize against the CPU and GPU levels rather than attempt to use this metric to determine battery drain.|
|Power Voltage (||Indicates the power voltage in milliamps.|
|Power Current (||Shows the power current of the device in milliamps. Developers should optimize against the CPU and GPU levels rather than attempt to use this metric to determine power drain.|
|Left Controller Temperature (|
Right Controller Temperature (
|These metrics display the temperatures of the left and right controllers.|
|Maximum Rotational Speed (||Specifies the fastest speed the headset has rotated.|