Unity Function Performance
Which is the fastest kind of C# function in Unity? There are several to choose from: regular old instance methods, static methods, delegates, and lambdas. Is there any performance reason to choose one over the other? Today’s article answers just these questions by putting each type of function to the test. Read on to see which is fastest and which is slowest!
Just like AS3 functions in Flash, there are several types to choose from. Here are the candidates for C#:
class MyCode { // Instance function void InstanceFunction() { } // Static function static void StaticFunction() { } // Definition of a function - not a function itself delegate void FunctionType(); // Delegate function FunctionType DelegateFunction = delegate() {}; // Lambda function FunctionType Lambda = () => {}; }
The first two are normal, but the latter two are a bit tricky. In order to be called they must be saved to a delegate-typed variable. The standard System.Action
and System.Func
are common options, but you can define your own like I did above.
Now let’s put each kind of function to the test by calling them a lot of times. Here’s the test script:
using System; using System.Diagnostics; using UnityEngine; public class TestScript : MonoBehaviour { private const int reps = 100000000; private string report; void Start() { var stopwatch = new Stopwatch(); var staticFunctionTime = RunTest( stopwatch, () => { for (var i = 0; i < reps; ++i) { StaticFunction(); } } ); var instanceFunctionTime = RunTest( stopwatch, () => { for (var i = 0; i < reps; ++i) { InstanceFunction(); } } ); var lambdaTime = RunTest( stopwatch, () => { Action lambda = () => {}; for (var i = 0; i < reps; ++i) { lambda(); } } ); var delegateTime = RunTest( stopwatch, () => { Action del = delegate(){}; for (var i = 0; i < reps; ++i) { del(); } } ); report = "Test,Time\n" + "Static Function," + staticFunctionTime + "\n" + "Instance Function," + instanceFunctionTime + "\n" + "Lambda," + lambdaTime + "\n" + "Delegate," + delegateTime + "\n"; } private long RunTest(Stopwatch stopwatch, Action test) { stopwatch.Reset(); stopwatch.Start(); test(); return stopwatch.ElapsedMilliseconds; } void OnGUI() { GUI.TextArea(new Rect(0, 0, Screen.width, Screen.height), report); } static void StaticFunction() {} void InstanceFunction() {} }
If you want to try out the test yourself, simply paste the above code into a TestScript.cs
file in your Unity project’s Assets
directory and attach it to the main camera game object in a new, empty project. Then build in non-development mode for 64-bit processors and run it windowed at 640×480 with fastest graphics. I ran it that way on this machine:
- 2.3 Ghz Intel Core i7-3615QM
- Mac OS X 10.10.2
- Unity 5.0.0f4, Mac OS X Standalone, x86_64, non-development
- 640×480, Fastest, Windowed
And got these results:
Test | Time |
---|---|
Static Function | 34 |
Instance Function | 30 |
Lambda | 278 |
Delegate | 276 |
The above data shows a distinct division between the first two types of functions and the last two. The instance and static functions run about 10x faster than the lambda and delegate functions. The instance and static functions seem to run at about the same speed, just like the lambda and delegate functions.
These functions don’t do anything, so these results just show the overhead of calling the function, not the time taken by the actual work the function should do.
The test app calls each type of function 100 million times. This shows that each function call, regardless of type, is really quite fast. The “slow” function types have a per-call cost of 0.000003 milliseconds. That means you could call them a third of a million times before you’d used up one millisecond of time in function call overhead. For the “fast” function types, you could call three million times.
So you’ll probably never see any slowdown due to lambdas or delegates, but if you happen to be calling them a lot then you can optimize by switching to instance functions or static functions.
If you know of any other types of functions I missed or have any experience with real-world slowdowns due to function call overhead, feel free to leave a comment!
#1 by Jorge Palacios (@pctroll) on March 25th, 2015 ·
Thank you for the useful information, Jackson. I arrived here by recommendation of a friend and I loved the experiment.
Keep the good work.
#2 by benjamin guihaire on October 10th, 2016 ·
do you get similar results if you do a simple operation in your functions , c#IL compiler might have(like the As3 compiler had) special optimizations to detect empty functions for static and or instance functions.
Note: and if you compile your code with il2cpp , good chance those optimizations will happen with the c++ compiler.
#3 by jackson on October 10th, 2016 ·
Yes, the results are very similar if I increment a static field in each type of function. You’re right that IL2CPP will probably give different results due to the optimizations being done by a C++ compiler like Clang/LLVM being totally different than the Mono compiler and VM. It’s just a bit much for these articles to test on both scripting environments.
By the way, today’s article is a followup to this one. You might like to check it out.
#4 by Gladyon on June 7th, 2019 ·
The results are off because of the fact that the methods will be inlined in the static and instance cases.
If the methods aren’t inlined then the differences aren’t that drastic.