Introducing the Editor Iteration Profiler

Editor Iteration Profiler (EIP)
Before diving into the details, I will start by defining what an iteration is. An iteration is a process that contains instructions that are repeated until a condition is met. Unity relies on different types of iterations.

The Editor Iteration Profiler monitors iterations that are related to the scripting side of Unity, specifically entering and exiting playmode, assembly compilation, and assembly reload.

The tool is an attempt to empower you, our users, to understand and help you solve the common question “Why does it take so long to compile my scripts/enter playmode?”. EIP accomplishes this by monitoring profiler frames and saving them in a window where you can more easily navigate through the data the profiler produces. Additionally, the data persists for the whole lifetime of the Editor (or until it’s cleared), as opposed to the Profiler, which has a limit to the number of previously stored frames.

Disclaimer: This tool is still under development and anything could change on the API side.

High-level features summary

  • Monitor and capture profiling data from assembly reload, assembly compilation, and enter playmode.

  • Export captured data or Profiler data to a number of formats such as HTML, JSON (for chrome://tracing, which is a fast flame-graph style data visualizer), CSV, and Plaintext.

  • Export to a special type of HTML (HTML Performance Report), which attempts to minimize the number of clicks needed to get to the important areas of the profiled data, as well as aggregate possible areas of interest which could be optimized (e.g. OnEnable calls)

How to use
Compatible with 2019.3 and later. It might work with earlier versions, but it is not tested.

The basics
To enable the tool, you just need to click the Enable button in the window. The window doesn’t need to be open afterward: it will run in the background.

After an iteration happens, it will show up in the window as follows:

UI
Please note that the UI might change/have changed slightly, however, the functionality should be the same.

  • Enable - enables the Profiler and sets it to run in Editor mode.

  • Deep Profile - useful to get all information about managed calls. (Unity - Manual: The Profiler window)

  • Flattening - attempts to reduce the number of clicks needed to get to the place that is of interest. Works by ‘collapsing’ levels which contain multiple parented items with 1 child. Useful for GUI code and Deep Profiling.

  • User Code - is an attempt to filter out engine code and only show code the User might be interested in.

  • Clear - removes recorded events and events which the EIP is looking for.

  • Collapse All - recursively collapses every item.

  • Print to Console - logs the captured data into plaintext into the console/log file.

  • Export… - dropdown to export captured data in various formats.

  • Export Profiler Data… - dropdown to choose between exporting the selected frame in the Profiler Window or exporting multiple frames, frame by frame, between 2 ranges. It will automatically export the data to a selected folder.

  • Search Bar - works as you would expect. Selecting an item and either pressing the F key or clearing the search will automatically expand the tree view to that item.

Exporters

After you have captured some data, you might want to export it. You can do this by clicking the Export… dropdown and choosing a format.

Here you can get the samples exported above for you to test out.

The Formats

Opening the HTML, you will see something similar to this:

It mostly contains the same data as the EIP Window, with the addition of the percentages. Items in square brackets “” are leaf items without any children.

The JSON format is meant to be used within Google Chrome’s chrome://tracing, which works on chromium-based browsers like Google Chrome, Microsoft Edge Chromium (edge://tracing - chrome://tracing will be replaced by it if typed), Opera, etc… It is a fast, lightweight and Editor-agnostic way to view the captured data in the flame-graph style. In this gif, we show how to load and use the file into chrome://tracing.

CSV can be used to load the data into other programs, for example. It is pretty difficult for humans to make sense of it. Also, please be aware of the ‘header’ which contains environment information in case you plan to do further processing.

Exporting Plaintext is the same as the one it is printed in the console with the “Print to Console” button. Using this, you have the option to isolate the data and not have other information which is in the Editor.log file.

The HTML Performance Report is based on the same structure as the regular HTML report, however, functionally it is different. The purpose of it is to distill the information into something humans would more easily understand. It basically does this by reducing the number of levels you have to click through to get to the areas of interest, where code diverges more.

The items in curly brackets “{ }” represent items that have more children, which were hidden due to the parents being under the minimum set threshold (currently a hard-coded value of 1%).

The colored items represent ‘buckets’ of similar data, which is grouped in one place for convenience. The total time of these items is not added to the original time, it’s only there to give an estimate for that iteration.

Known Bugs/Limitations (must read this before using it)

  • After a Domain reload, items under ScriptCompilation->AssemblyReload get reparented to AssetImport

  • Data might overlap on chrome://tracing because timestamp mismatches between the EIP’s timestamp and the Profiler timestamp (to be fixed in the future)

  • Sorting data doesn’t work in-window

  • In order to get the most accurate data (especially with DeepProfile enabled), close as many Editor Windows as possible, including the EIP Window itself (it will keep working even when closed if it’s Enabled). The reason is that rebuilding the Tree Hierarchy view and repainting the GUI takes time, and it will “pollute” the data you might be looking for. The more data, the more it will be polluted (Deep Profile will naturally lead to this faster). This has been mostly mitigated in 0.1.2-preview (cost is still there, just delayed so it doesn’t pollute the data).

  • When clicking the Profiler Window after clicking Enable in the EIP Window, the EIP’s state will be overridden to whatever the original setting in the Profiler was

  • May cause unity to crash when closing it while the EIP is Enabled

Feedback
In terms of feedback, we’re especially looking for:

  • Are there any useful use-cases not covered?

  • Are there any workflows that are unclear or missing?

  • Is there anything that is unclear or that you don’t understand?

  • Are there any issues or unclear parts in the documentation or this post?

Please feel free to post any feedback in this sub-forum.

How to report bugs
Please open bugs/suggestions at Issues ¡ Unity-Technologies/com.unity.editoriterationprofiler ¡ GitHub.
Please describe the steps as well as include any relevant files necessary for reproduction.

Troubleshooting
If you encounter any problems, the simplest fix is usually to use the Clear button for the window. Another option you can try is through Window → Analysis → Editor Iteration Profiler → Purge Caches.

22 Likes

“Place the contents in a folder in your Project’s Packages folder”

doesn’t this miss the part where we should change the manifest.json too?

"dependencies": {
    "com.unity.editoriterationprofiler": "com.unity.editoriterationprofiler-master",

That is not necessary. You can either embed a package in your Package folder or reference it in a local folder

 "com.unity.editoriterationprofiler": "file:../path/to/com.unity.editoriterationprofiler-master"

You can of course also do the local reference using the Package Manager UI.

2 Likes

I am confused, is this available in the package manager? If not (as I don’t think it is), how else can be used outside the Asset Folder without changing the manifest? I am not aware of other ways.

If you choose to reference the package as a local reference. It is correct that the manifest needs to change. This is described here: Unity - Manual: Install a UPM package from a local folder
However there is also the option of adding the package inside the Packages folder. That is called an embedded package. That is what is described as the suggestion in this guide. The documentation for that is here: Unity - Manual: Embedded dependencies

2 Likes

I added it with the GitHub repo link, like so:

"com.unity.editoriterationprofiler": "https://github.com/Unity-Technologies/com.unity.editoriterationprofiler.git"

Works like a charm; installs exactly as it should.

7 Likes

I’m using this both privately and in a 13 person studio team.

It’s a godsent, especially when trying to discern what part of the time spent is in the domain reload etc, and what time is actually some loading of the game itself. (profiling profane wait states of async calls is always a bit of a pain)

3 Likes

On the latest commit (fdfcf97) on Unity 2019.4.0f1 on Ubuntu 19.10, the “AssemblyReload” seems to always report a duration of zero.

1 Like

I am not aware of this, sounds like a bug I don’t know of. Mind sharing more info?

There is a bug mentioned under Known Issues where the frame responsible for Assembly Reload gets reparented to AssetImport (see image below, red) when the tree is rebuilt.

5989979--644198--upload_2020-6-17_8-47-18.png

Sure, what info would help? I don’t know what to look for.

How often it reproduces? Is it a Script Compilation event? If it’s often what are the steps? Do you have Deep Profiling enabled?

Can you try going to Window → Analysis → Editor Iteration Profiler → Purge Caches and then Clear in the EIP Window? What about restarting the Editor?

It seems that the package isn’t actually compatible with 2019.2. After embedding the package into my project, I see the following errors:

In checking the Unity C# reference source, functionality like EditorUtility.RequestScriptReload and EditorUtility.enterPlayModeOptionsEnabled are only available in 2019.3+.

Was the 2019.2 reference in the description a typo or did I miss something?

My bad, changed it to 2019.3+

The issue is simply that those API’s aren’t available in 2019.2.

I’m getting NUnit missing compile errors. Maybe put some #ifdefs around the using NUnit.Framework; and the asserts?

1 Like

Thanks for the heads up! I replaced them with UnityEngine.Assertions :slight_smile:

Hi guys, I run into this bug. At first install, everything works fine. Then I duplicate my project (in afraid of messing s.t up) and open duplicated project’s Iteration Editor Window show no texts at all, just like attachment. Then I remove duplicated project and open original project. Now Iteration Editor Window also show no texts. Removing and reinstalling, even reseting computer does not fix it. Any ideas what I should do?
Also, other functions like Print to console still works and texts in console show fine.

I tried to run it while doing a project export, and it worked - kind of. It captured all the script compilation iteration events which is what I wanted. But at the end of the build, it started to spam these errors temporarily before coming back to life. Then I could look inside the profiler details. Not sure if these are important.

NullReferenceException: Object reference not set to an instance of an object
UnityEditor.EditorIterationProfiler.DataCollector.EditorEvent (UnityEditor.EditorIterationProfiler.UnityEditorEvents+Event evt, System.String data) (at Packages/com.unity.editoriterationprofiler/Editor/DataCollector.cs:70)
UnityEditor.EditorIterationProfiler.UnityEditorEvents.AssemblyCompilationStarted (System.String assembly) (at Packages/com.unity.editoriterationprofiler/Editor/UnityEditorEvents.cs:64)
UnityEditor.Compilation.CompilationPipeline+<>c.<SubscribeToEvents>b__16_2 (System.String assemblyPath) (at <0a2a5ea3c8ab4e3394576dd407a984f6>:0)
UnityEditor.BuildPipeline:BuildPlayer(String[], String, BuildTarget, BuildOptions)
BuildTools:BuildPlayer(BuildSettings, String, String, String) (at Assets/Scripts/Build/Editor/BuildTools.cs:144)
BuildWindow:smile:oBuild(StartInfo, Boolean, Boolean, Boolean, Boolean, Boolean) (at Assets/Scripts/Build/Editor/BuildWindow_BuildTools.cs:319)
BuildWindow:smile:rawBuildTools() (at Assets/Scripts/Build/Editor/BuildWindow_BuildTools.cs:182)
BuildWindow:OnGUI() (at Assets/Scripts/Build/Editor/BuildWindow.cs:169)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

Looks like you’re already aware that sorting the columns doesn’t work which is unfortunate. But also, how about sorting them on export? The HTML report is thankfully nice enough to have a % breakdown on each level (god send), but would be cool if it auto descending or ascending.

Looks like you are running on OSX? Can you tell me which version of Unity and OSX you are running? There are a few bugs in OSX apparently that I am becoming aware of because I developed this tool on Windows mostly. It might be a bug with IMGUI potentially

Hi, thanks for the feedback!

The errors you are seeing are probably because the Editor Iteration Profiler is looking for Domain Reloads (they happen while Building), but then it tries to add it to a root which is not there, as it’s created in another code path. I will try to fix this if it’s quick but I also have some time planned to also add the ability for the EIP to capture information about building the Players, so awareness EIP might have about Domain Reloads during Building Players might be the right thing to do instead of going around it :).

I am aware the sorting is broken and was suggested I should sort before exporting as well. The idea is if I implement sorting for the UI I can also do sorting when exporting. I do have a few days set aside for this quarter for EIP improvements, I think I will focus on this as it is an important feature :slight_smile:

Stay tuned!

1 Like

hi @rarepop99 , glad you’re taking care of this. I even tried to create new project but except the first time, I’ve never managed to make the text appears again.
I’m running macOS Catalina 10.15.5 and Unity 2019.4.3f1