Unity’s code is instrumented with a large number of ProfilerA window that helps you to optimize your game. It shows how much time is spent in the various areas of your game. For example, it can report the percentage of time spent rendering, animating or in your game logic. More info
See in Glossary markers that give you insight into what is taking up time in your application. The following tables explain what some of the common markers do:
The main thread base markers provide a clear separation between the time spent on your application and time spent on the Editor and Profiler activities. The ProfilerRecorder can also use these markers to get the timing of a frame on the main thread.
Marker | Function |
---|---|
PlayerLoop | Contains any samples that originate from your application’s main loop. If you target the Editor instead of Play mode while the Player is running within the Editor in active Play mode, PlayerLoop samples nest under the EditorLoop. |
EditorLoop (Editor only marker) |
Contains any samples that originate from the Editor’s main loop. This is only present while you profile a player in the Editor. When you target Play mode with the Profiler, EditorLoop samples show the amount of time spent rendering and running the Editor that contains the Player. The Profiler does not record any further detailed data under the EditorLoop marker. This is because the samples that Editor code emits while the Profiler is profiling Play mode create a large profiling overhead. Unity categorizes any samples from the EditorLoop marker as Others in the CPU Profiler module charts. As a result, EditorLoop samples are usually the biggest contributor to that category. If you want to see what the Editor does in this time and also get a more detailed breakdown of what else contributes to the Others category, change the Profiler target to the Editor instead. Switching the Profiler’s target to Editor changes what the Profiler displays in the CPU Profiler module’s detail pane, as well as the Category breakdown in the CPU Profiler module’s charts. This is because the samples that were previously hidden under the EditorLoop sample then contribute towards their respective categories. |
Profiler.CollectEditorStats (Editor only marker) |
Contains any samples that relate to collecting statistics for different active Profiler modules. Samples that are nested under the Profiler.CollectGlobalStats marker indicate how much overhead the Player incurs when it collects the statistics of a particular module. All other child samples only reflect their effect in the Editor. To remove the overhead that a particular module incurs, close the module’s chart, or call Profiler.SetAreaEnabled. Note: Custom Profiler modules that use built-in counters enable the built-in counter’s area, even if the module it belongs to has been disabled. To prevent the Profiler from collecting these statistics and creating collection overhead, make sure that both the built-in Profiler module and your custom Profiler module are disabled. |
There are certain markers that only appear when you profile in the Unity Editor. These markers do not appear in Player-related activity, and only relate to Editor activity. Editor-only markers include security checks like the GetComponentNullErrorWrapper, which helps to identify a null component usage; CheckConsistency, which validates object setup; CheckAllowDestructionRecursive, which is a destruction check; and Prefab-related activities.
By default, in the CPU Profiler module’s Hierarchy view, sample stacks with Editor-only markers are collapsed and are named EditorOnly [SampleName]
. While these sample stacks or their child samples might cause managed allocations that can lead to garbage collection getting triggered, they do not contribute to the GC.Alloc value of their parent sample if they are collapsed.
To change the default behavior, in the top right of the module details pane, select the context menu and disable the Collapse EditorOnly Samples setting. When you do this, you can expand the sample and contribute its GC.Alloc value to the enclosing marker.
This option does not affect the Timeline view, and the samples and their children appear expanded. You can usually ignore the samples with these markers, because they relate to Editor-only activity and don’t have any impact on reducing managed allocations. However, they can be useful to investigate if you are having serious issues with the performance impact they have on Play mode.
Unless you are using the Job System, most of your scripting code is nested underneath the following markers. For information on Job System samples, see the Multi threading markers section of this page.
For further details on Unity’s Update Loop, see the documentation on Order of Execution of Event Functions. If you have inserted your own callbacks into the Player Loop via PlayerLoop.SetPlayerLoop, your script update samples appear under the respective main PlayerLoopSystem marker, if entered as a subsystem, or on their own, if entered directly into the main loop.
Marker | Function |
---|---|
BehaviourUpdate | Contains all samples of MonoBehaviour.Update methods. |
CoroutinesDelayedCalls | Contains all samples of Coroutines after their first yield. |
FixedBehaviourUpdate | Contains all samples of Monobehaviour.FixedUpdate methods. |
PreLateUpdate.ScriptRunBehaviourLateUpdate | Contains all samples of Monobehaviour.LateUpdate methods. |
Update.ScriptRunBehaviourUpdate | Contains all samples of MonoBehaviour.Update and Coroutines. |
These markers contain the samples where the CPU spends time processing data for the GPU, or where it might be waiting for the GPU to finish. If the GPU Profiler module is not available, or it adds too much overhead, the toolbarA row of buttons and basic controls at the top of the Unity Editor that allows you to interact with the Editor in various ways (e.g. scaling, translation). More info
See in Glossary in the Profiler module details pane does not show this information. The samples under these markers can give you a good idea of whether your application is CPU-bound or GPU-bound.
Marker | Function |
---|---|
WaitForTargetFPS | Indicates how much time your application spent waiting for the targeted FPS that Application.targetFrameRate specifies. If the sample is a subsample of Gfx.WaitForPresentOnGfxThread, it represents the amount of time that your application spent waiting for the GPU. For example, this could be time that the GPU spent waiting for the next VSync, if that is configured in QualitySettings.vSyncCount, or if vSync is enforced on your target platform. However, samples with this marker are also emitted if the GPU hasn’t finished computing the frame. To determine what is causing samples with this marker to use a lot of time, switch to the Timeline view in the CPU Profiler module. In this view, you can check what happened on the render thread and how much time passed between this sample ending in the current frame and the same sample ending in surrounding frames. If the duration is larger than your application’s frame time should be (based on the targeted frame rate or vSync) your frames are taking too long to render or compute. If that’s the case, investigate the render thread and see how much time it spent on Gfx.PresentFrame over other work it did to prepare and issue commands to the GPU. If the render thread spent a large amount of time in Gfx.PresentFrame, your rendering work is GPU-bound. If the render thread’s time was spent preparing commands, your application is CPU-bound. To find out what to focus on, if your application is GPU bound, profile the GPU work with the Unity Profiler or a platform profiler. For more information, see the User manual documentation on how to optimize graphics performance. Note: The Editor doesn’t VSync on the GPU and instead uses WaitForTargetFPS to simulate the delay for VSync. Some platforms, in particular Android and iOS, enforce VSync or have a default frame rate cap of 30 or 60. |
Gfx.PresentFrame | Represents the time your application spent waiting for the GPU to render and present the frame, which includes waiting for VSync. Samples with the WaitForTargetFPS marker on the main thread show how much time is spent waiting for VSync. |
Gfx.ProcessCommands | Contains all processing of the renderingThe process of drawing graphics to the screen (or to a render texture). By default, the main camera in Unity renders its view to the screen. More info See in Glossary commands on the render thread. Your application might have spent some of this processing time waiting for VSyncVertical synchronization (VSync) is a display setting that caps a game’s frame rate to match the refresh rate of a monitor, to prevent image tearing. More info See in Glossary or new commands from the main thread, which you can see from its child sample Gfx.WaitForPresentOnGfxThread. |
Gfx.WaitForCommands | Indicates that the render thread was ready for new commands. If you see this marker, it might indicate a bottleneck on the main thread. |
<GraphicsAPIName>.WaitForLastPresent e.g.GfxDeviceD3D11.WaitForLastPresent GfxDeviceD3D12.WaitForLastPresent GfxDeviceMetal.WaitForLastPresent |
Samples with this marker appear when the main thread waited for the GPU to flip the frame number to the screen (Time.frameCount - QualitySettings.maxQueuedFrames + 1 ). This means that if QualitySettings.maxQueuedFrames is greater than one, this time is spent waiting for the GPU to flip a frame that your application requested to render in a previous main thread frame.For more details on this sample and an overview of Unity’s Frame Pipeline, see Unity’s blog post on fixing Delta Time. |
Gfx.WaitForPresentOnGfxThread | Indicates that the main thread was ready to start rendering the next frame, but the render thread did not finish waiting for the GPU to present the frame. This might indicate that your application is GPU-bound. To see what the render thread is simultaneously spending time on, check the CPU Profiler module’s Timeline view. If the render thread spends time in Camera.Render, your application is CPU-bound and might be spending too much time sending draw calls or textures to the GPU. If the render thread spends time in Gfx.PresentFrame, your application is GPU-bound, or it might be waiting for VSync on the GPU. A WaitForTargetFPS sub-sample of Gfx.WaitForPresentOnGfxThread represents the portion of the Present phase that your application spent waiting for VSync. The Present phase is the portion of time between Unity instructing the graphics API to swap the buffers, to the time that this operation completed. |
Gfx.WaitForRenderThread | Indicates that the main thread was waiting for the render thread to process all the commands in its command stream. Samples with this marker only appear in multithreaded rendering. |
The samples highlight Mono or IL2CPPA Unity-developed scripting back-end which you can use as an alternative to Mono when building projects for some platforms. More info
See in Glossary scripting backendA framework that powers scripting in Unity. Unity supports three different scripting backends depending on target platform: Mono, .NET and IL2CPP. Universal Windows Platform, however, supports only two: .NET and IL2CPP. More info
See in Glossary activities and are useful for troubleshooting issues with garbage collection and allocation.
Marker | Function |
---|---|
GC.Alloc | Represents an allocation in the managed heap that contains managed allocations that are subject to automatic garbage collection. To reduce the time your application spends on automatic garbage collection, you should minimize these types of samples. |
GC.Collect | Represents samples that relate to garbage collection. Whenever Unity needs to perform garbage collection, it stops running your program code and only resumes normal execution when the garbage collector has finished all its work. Note: If you have enabled Incremental Garbage Collection the garbage collector might not finish its work in a single frame. This interruption might cause delays in the execution of your application that last anywhere from less than one millisecond to hundreds of milliseconds. This depends on how much memory the garbage collector needs to process and the platform your application is running on. For more information, see the documentation on Understanding automatic memory management. |
Mono.JIT Mono-only |
Contains samples that relate to just-in-time compilation of a scripting method. When a function is executed for the first time, Mono compiles it and Mono.JIT represents this compilation overhead. |
UnsafeUtility.Malloc | Contains samples that call UnsafeUtility.Malloc to allocate unmanaged memory. While the Garbage Collector does not track this memory, allocating memory might have a significant performance impact which is shown with this sample. To investigate the source of this call, you can enable Call Stack recording for this marker in the Profiler window. |
These markers contain samples that do not measure the CPU cycles consumed, but instead highlight information that relates to thread synchronization and the Job System. When you see these samples, use the CPU Profiler module’s Timeline view to check what’s happening on other threads at the same time.
Marker | Function |
---|---|
Idle | Contains samples that indicate the length of time that a Worker Thread is inactive for. A worker thread is inactive any time that the Job System does not utilize it, and it goes into wait mode, where it waits on the semaphore. Small gaps between Idle samples usually happen when the Job System wakes them up, for example, to schedule new jobs. Longer gaps might indicate that a native job that has not been instrumented is running on the thread. |
JobHandle.Complete | Contains samples that indicate when a sync point on a job happened. Sync points might have a performance impact on your application and might interfere with the execution of multi-threaded job code. To make it easier to find where exactly the sync point happened, enable Call Stack recording for this sample. In the CPU Profiler module’s Timeline view you can enable Flow Events to see which jobs finished at this point. |
Semaphore.WaitForSignal | Contains a sample that depicts a synchronization point on a thread. To find the thread it is waiting for, check the Timeline view for samples that ended shortly before this one. |
WaitForJobGroupID | A Sync Fence on a JobHandle was triggered. This might lead to work stealing, which happens when a worker finishes its work and then looks at other workers’ jobs to complete. These show up as job samples executed under this marker. Jobs that were “stolen” are not necessarily the jobs that were being waited for. |
The following table outlines some of the high-level physics Profiler markers. FixedUpdate calls all of these measurements.
Marker | Function | |
---|---|---|
Physics.FetchResults | Contains samples that collect the results of the physics simulation from the physics engineA system that simulates aspects of physical systems so that objects can accelerate correctly and be affected by collisions, gravity and other forces. More info See in Glossary, such as contact streams, trigger overlaps, and jointA physics component allowing a dynamic connection between Rigidbody components, usually allowing some degree of movement such as a hinge. More info See in Glossary breakage events. |
|
Physics.Interpolation | Contains samples that measure the execution time of the Physics.Interpolation method. This method manages the interpolation of positions and rotations for all the physics objects in your application. | |
Physics.Processing | Contains samples that spent time waiting on the main thread until the physics simulation completed across all threads. If your application spends a lot of time in Physics.Processing but only has a few physics related GameObjectsThe fundamental object in Unity scenes, which can represent characters, props, scenery, cameras, waypoints, and more. A GameObject’s functionality is defined by the Components attached to it. More info See in Glossary in the SceneA Scene contains the environments and menus of your game. Think of each unique Scene file as a unique level. In each Scene, you place your environments, obstacles, and decorations, essentially designing and building your game in pieces. More info See in Glossary, it might indicate that worker threads picked up other systems tasks due to job stealing and reported as physics. This is because while waiting, the main thread picks up jobs from the high priority queue. |
|
Physics.ProcessingCloth | Contains samples that measure the execution time of the Physics.ProcessingCloth method. This method processes all cloth physics jobs. Expand this sample to show the low-level detail of the work done internally in the physics engine. | |
Physics.ProcessReports | Contains samples that correspond to time spent forwarding physics data to scripts via callbacks such as OnTriggerEnter. Note: These samples do not compute the data required because they have already been prepared during FetchResults. There are four distinct sub-stages: |
|
Physics.Contacts | Contains samples that measure the execution time of Physics.Contacts. This processes OnCollisionEnter, OnCollisionExit, and OnCollisionStay events. | |
Physics.JointBreaks | Contains samples that measure the execution time of Physics.JointBreaks. This processes updates and messages related to broken joints. | |
Physics.TriggerEnterExits | Contains samples that measure the execution time of Physics.TriggerEnterExits. This processes OnTriggerEnter and OnTriggerExit events. | |
Physics.TriggerStays | Contains samples that measure the execution time of Physics.TriggerStays. This processes OnTriggerStay events. | |
Physics.Simulate | Contains samples that measure the amount of time spent working on the pre-requisites for the Physics.Simulate method. This method instructs the physics engine to run its simulation, which updates the state of the current physics. | |
Physics.UpdateBodies | Contains samples that update all the physics bodies’ positions and rotations. For each gameObject that has a RigidbodyA component that allows a GameObject to be affected by simulated gravity and other forces. More info See in Glossary component, samples with this marker read the pose from the physics engine and write it to the Transform. |
|
Physics.UpdateCloth | Contains samples that measure the execution time of the Physics.UpdateCloth method. This method processes updates that relate to cloth and their Skinned Meshes. |
For more information about script life cycles and general samples within a script life cycle, see the documentation on Order of Execution for Event Functions.
The CPU Profiler detects some common performance issues and warns you about them. These appear in the Warning column of the CPU Profiler module’s Hierarchy view in the module details pane.
The Profiler detects some specific calls that you should avoid in performance-critical contexts. It displays the warnings with the reasons the operations are affecting performance as follows:
Warning | Description |
---|---|
Animation.DestroyAnimationClip Animation.AddClip Animation.RemoveClip Animation.Clone Animation.Deactivate |
Indicates that RebuildInternalState has been triggered. RebuildInternalState is an operation that goes through the list of curves for each clip in the Animation component, and then rebinds each curve to a value on a component, on a GameObject. This is a resource-intensive operation, so you should avoid calling these methods at runtime as much as possible. |
AssetBundle.asset/allAssets | Indicates that Unity called the AssetBundleRequest.assets/allAssets API while the AssetBundle loading was not complete (AssetBundleRequest.isDone is false). This causes a stall on the main thread and waits for the loading operation to complete. |
AsyncUploadManager.AsyncBufferResized AsyncUploadManager.AsyncBufferDelete |
Indicates that the internal buffer for uploading data to the GPU is resized because it’s not big enough. This resizing is slow and causes spikes in CPU activity. You can avoid this warning if you can spare the memory to allocate a larger size up front. You can use Async Upload Buffer Size setting in Quality Settings to set the default size. The AsyncUploadManager.AsyncBufferResized marker indicates the newly allocated size which you can use as a guide for the default buffer size. |
Rigidbody.SetKinematic | Recreate non-convex MeshCollider for Rigidbody. |