Introduction
If you are just looking for the project’s code, you can get it from here
Performance is a big topic. Especially in Unity where we want our game to run at certain fps, we have to take care of the code we write and gets executed.
The game loop is usually one of our biggest problems. This post is not about best practices. A lot has been written and a lot will be written about that. Also it is not about when we should care about performance. Obviously having our code readable and easily maintainable takes precedence but eventually everyone will be in a situation that has to make his program more performant.
One of my favorable phrases that I cannot remember where I first read it, is that performant code is a myth, our program has to be performant.
There is no point in making every single line of code as performant as possible. Performance is part of our requirements and it depends on many factors. We profile often, then if our program doesn’t meet those requirements, we try to find where the most CPU time was spent, then we try to find out which pieces of code are our bottleneck and refactor them accordingly.
Performance in context
Many times you will have heard or read about certain Unity methods that are expensive like FindObjectOfType
and GetComponent
.
Also I’m certain you have heard about the null checks of GameObjects, the context change between C# and C++ space for every update method, that the Update methods consume cpu time even if empty etc.
But how expensive are really all of those compared to each other?
How much do ten null checks hurt the performance of our code in the Update method, compared to one GetComponent, also inside the Update method.
How about calling our own methods from inside one Update method vs many Update methods, when the code that gets executed in those methods is somewhat expensive.
For this reason I made a small program, that allows at runtime to change which expensive Unity methods are being used and the amount of those calls, while allowing to change between normal Updates and C# updates.
The project
I have created the project with four different expensive calls. The null check of GameObjects, The GetComponent and FindObjectOfType methods and also a simple for loop.
When the tick box is checked you can see the change in performance in milliseconds at runtime, while allowing you to set the amount of each call.
The last bar is the number of Updates being run. This number takes effect only after the button is clicked, which also changes the type of the Update being used, between normal Unity updates and updates in C#. If you are not sure what I mean by Unity updates and C# updates, check my previous post How to improve performance of conditional execution in Update.
Obviously you can have any combination of calls. For example, you may want to check the performance of 1000 updates that each have 2 null checks and a for loop that gets executed 1000 times vs 5000 updates that get executed at the C# space but each has only one null check.
The performance of course will be different for every machine. It is better to build the project and run it, than to execute it inside the editor, as the editor skews the results.
A word of caution. If you decide to run inside the editor, make sure to have the root hierarchy object selected so that the inspector is empty before pressing play. Unity’s editor needs CPU power to refresh the inspector that shows a gameobject while running the project and your game engine may freeze.
Extensibility
The core of the program is really simple:
if (_calculateWithNullCheck)
{
for (var j = 0; j < _noOfNullChecks; j++)
if (gameObject != null) ;
}
if (_calculateWithFindObject)
{
for (var j = 0; j < _noOfFindObjects; j++)
FindObjectOfType<WithUpdate>();
}
if (_calculateWithGetComponent)
{
for (var j = 0; j < _noOfGetComponent; j++)
GetComponent<WithUpdate>();
}
if(_calculateWithForLoop)
{
for (var j = 0; j < _noOfForLoops * 1000; j++) ;
}
you can change any of those method calls inside the for loops with the method you want to test, in two different scripts:
- The
WithUpdate
script, which is responsible for running the normal Unity Updates and - The
WithMyUpdate
script that registers methods in an Update manager that has a single Update method.
You can get the code from my github
UPDATE 2024-02-06
The FindObjectOfType
is obsolete now, so I updated the project to have options for FindAnyObjectByType
and FindFirstObjectByType
instead, the Unity version is also updated, the project is now made with Unity version 2023.3.
Conclusion
I hope you find this project that displays the comparison between expensive calls relative to each other interesting.
As always thank you for reading and if you have any questions or comments you can use the comments section or contact me directly via the contact form or by email, also if you don’t want to miss any of the new blog posts, you can always subscribe to my newsletter or the RSS feed.