FrameTimingManager
The FrameTimingManager enables you to capture and access frame timing data for multiple frames. Frame timing data includes timestamps for different phases of the frame and the duration of work done on the main and render threads. You can use this information to make adjustments to your application where performance is below your target level.
The FrameTimingManager isn’t enabled by default. To enable this feature, go to Edit > Project Settings > Player and enable the Frame Timing Stats checkbox.
Note: Enabling Frame Timing Manager has a noticeable performance impact.
Note that FrameTimingManager is a part of Dynamic Resolution feature and is required to be enabled for it to work.
What’s changed
- Added support for DirectX 11
- GPU time measurements now work in Editor too for most platforms
- Added Main Thread Central Processing Unit (CPU) Frame time
- Added Main Thread CPU Present Wait time
- Added Render Thread CPU Frame time
- Added First Submit timestamp
- Added Frame Start timestamp
- Exposed “CPU Total Frame Time” profiler counter
- Exposed “CPU Main Thread Frame Time” profiler counter
- Exposed “CPU Render Thread Frame Time” profiler counter
- Exposed “Graphics Processing Unit (GPU) Frame Time” profiler counter
More details on each added field are provided below in “Measurements” section.
Measurements
The FrameTimingManager measures a set of important time metrics of a frame, including the following:
- cpuFrameTime - the total CPU frame time calculated as the time between the ends of two frames, which includes all waiting time and overheads, in ms.
- cpuMainThreadFrameTime - the total time between the start of the frame and the time when the Main Thread finished the job, in ms.
- cpuRenderThreadFrameTime - The time between the start of the work on the Render Thread and when the Present() function was called, in ms.
- cpuMainThreadPresentWaitTime - The CPU time spent in waiting for Present() during the last frame, in ms
- gpuFrameTime - The GPU time for a given frame, in ms.
- frameStartTimestamp - The CPU clock time when the frame was started.
- firstSubmitTimestamp - The CPU clock time when the first job was submitted to the GPU.
- cpuTimePresentCalled - The CPU clock time at the point Present() was called for the current frame.
- cpuTimeFrameComplete - The CPU clock time at the point when the GPU finished rendering the frame and interrupted the CPU.
The following diagram explains how each measured time and timestamp maps to a frame.
Important notes:
- The FrameTimingManager produces results with a fixed delay of four frames because GPU timing results aren’t available immediately.
- Frame Timing Manager doesn’t guarantee that the GPU has time available. The GPU might fail to return results in time, or might fail to return any results at all. In these cases, the
gpuFrameTime
is reported as zero. - On platforms that don’t allow GPU timestamping, Unity computes the FrameCompleteTime value rather than measure it. Unity computes FrameCompleteTime as FirstSubmitTimestamp + GPU Time. If the GPU fails to provide GPU time, FrameCompleteTime is automatically set to be equal to Present Timestamp.
- On GPUs which use tile-based deferred rendering architecture (such as mobile platforms), results are less precise because GPU execution is deferred and the execution of rendering phases might be done separately. The FrameTimingManager can only measure overall duration.
Profiler Counters
Instead of the FrameTimingManager C# API, you can read FrameTimingManager values using the ProfilerRecorder API. The benefit of the ProfilerRecorder API is that the FrameTimingManager measurements are only taken when you attach a recorder to the counter and you have control over potential overhead.
using Unity.Profiling;
using UnityEngine;
public class ExampleScript : MonoBehaviour
{
string statsText;
ProfilerRecorder mainThreadTimeRecorder;
void OnEnable()
{
mainThreadTimeRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Rendering, "CPU Main Thread Frame Time");
}
void OnDisable()
{
mainThreadTimeRecorder.Dispose();
}
void Update()
{
var frameTime = mainThreadTimeRecorder.LastValue;
// Your code logic here
}
}
Setup
FrameTimingManager is available for Development and Release Unity players. In the Development player, the FrameTimingManager is always enabled.
In a Release player, you must enable the FrameTimingManager in the Player Settings. To do this, go to Edit > Project Settings > Player and enable the Frame Timing Stats checkbox.
Platform support
Metal
In some cases, under heavy load or GPU pipeline saturation, reported GPU Time might be bigger than the reported frame time while using the Metal API. For example, reported GPU time might be 40ms with stable 50fps with which you would expect GPU time can’t be higher than 20ms.
Why does it happen? The Metal API allows us to measure time at the beginning and end of command buffer execution, which in Unity case near matches frame boundaries. Since tile-based deferred rendering architecture GPUs execute rendering in phases (jobs) instead of doing it immediately, there might be a gap between the execution of different phases depending on GPU resource availability. For example, if the GPU is under a high load, there might be a gap when a job is passed from the Vertex queue to the Fragment queue inside the GPU. That results in the situation when jobs activity time (which defines the frame rate) and the total measured wall clock time are significantly different.