Minimizing internal distractions

The Unity Editor has its own little quirks and nuances, which can sometimes make it confusing to debug some kinds of problems.

Firstly, if a single frame takes a long time to process, such that our game noticeably freezes, then the Profiler may not be capable of picking up the results and recording them in the Profiler window. This can be especially annoying if we wish to catch data during application/scene initialization. The Custom CPU profiling, section later will offer some alternatives to explore with a view to solving this problem.

One common mistake (that I have admittedly fallen victim to multiple times during the writing of this book) is that if we are trying to initiate a test with a keystroke and have the Profiler window open, we should not forget to click back into the Editor's Game window before triggering the keystroke. If the Profiler is the most recently clicked window, then the Editor will send keystroke events to that, instead of the runtime application, and hence, no GameObject will catch the event for that keystroke. This can also apply to the GameView for rendering tasks and even coroutines using the WaitForEndOfFrame yield type. If the Game window is not visible and active in the Editor, then nothing is being rendered to that view, and therefore, no events that rely on Game window rendering will be triggered. Be warned!

Vertical sync (otherwise known as VSync) is used to match the application's frame rate to the frame rate of the device it is being displayed to; for example, a monitor may run at 60 Hertz (60 cycles per second, about 16 ms). If a rendering loop in our game is running faster than a monitor cycle – for instance, 10 ms – then the game will sit and wait for another 6 ms before outputting the rendered frame. This feature reduces screen tearing, which occurs when a new image is pushed to the monitor before the previous image was finished, and, for a brief moment, part of the new image overlaps the old image.

Executing the Profiler with VSync enabled will probably generate a lot of noisy spikes in the CPU Usage area under the WaitForTargetFPS heading, as the application intentionally slows itself down to match the frame rate of the display. These spikes often appear very large in Editor mode, since the Editor is typically rendering to a very small window, which doesn’t take a lot of CPU or GPU work to render.

This will generate unnecessary clutter, making it harder to spot the real issue(s). We should ensure that we disable the VSync checkbox under the CPU Usage area when we're on the lookout for CPU spikes during performance tests. We can disable the VSync feature entirely by navigating to Edit | Project Settings | Quality and then to the sub-page for the currently selected platform.

We should also ensure that a drop in performance isn't a direct result of a massive number of exceptions and error messages appearing in the Editor Console window. Unity's Debug.Log() and similar methods, such as Debug.LogError() and
Debug.LogWarning(), are notoriously expensive in terms of CPU Usage and heap memory consumption, which can then cause garbage collection to occur resulting in even more lost CPU cycles (refer to Chapter 8, Masterful Memory Management, for more information on these topics).

This overhead is usually unnoticeable to a human being looking at the project in Editor mode, where most errors come from the compiler or misconfigured objects. However, they can be problematic when used during any kind of runtime process, especially during profiling, where we wish to observe how the game runs in the absence of external disruptions. For example, if we are missing an object reference that we were supposed to assign through the Editor, and it is being used in an Update() callback, then a single MonoBehaviour instance could throw new exceptions every single update. This adds lots of unnecessary noise to our profiling data.

Note that we can hide different log level types with the buttons shown in the next screenshot. The extra logging still costs CPU and memory to execute, even though they are not being rendered, but it does allow us to filter out the junk we don't want. However, it is often good practice to keep all of these options enabled to verify that we're not missing anything important: