By request, today’s article follows up on my Unity Function Performance article from a year and a half ago using Unity 5.0. It adds on GameObject.SendMessage and virtual functions to get a more complete picture of how various function calls in Unity perform. Of course it runs these tests using Unity 5.4 to see if there have been any changes in the engine. Read on for the results!

Today’s contenders are:

  • Non-Virtual Instance Functions
  • Virtual Instance Functions
  • Static Functions
  • Lambdas (i.e. () => {})
  • Delegates (i.e. delegate(){})
  • GameObject.SendMessage

Here’s the script that runs the test:

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 virtualFunctionTime = RunTest(
			stopwatch,
			() => {
				for (var i = 0; i < reps; ++i)
				{
					VirtualFunction();
				}
			}
		);
 
		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();
				}
			}
		);
 
		var sendMessageTime = RunTest(
			stopwatch,
			() => {
				for (var i = 0; i < reps; ++i)
				{
					SendMessage("InstanceFunction");
				}
			}
		);
 
		report = "Test,Time\n" +
			"Static Function," + staticFunctionTime + "\n" +
			"Instance Function," + instanceFunctionTime + "\n" +
			"Virtual Function," + virtualFunctionTime + "\n" +
			"Lambda," + lambdaTime + "\n" +
			"Delegate," + delegateTime + "\n" +
			"SendMessage," + sendMessageTime;
	}
 
	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);
	}
 
	public static void StaticFunction() {}
	public void InstanceFunction() {}
	public virtual void VirtualFunction() {}
}

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.11.5
  • Unity 5.4.1f1, Mac OS X Standalone, x86_64, non-development
  • 640×480, Fastest, Windowed

Notice that this is the same computer that the previous test was run on, aside from the software differences between Mac OS X and Unity.

Here are the results I got:

Test Time
Static Function 40
Instance Function 32
Virtual Function 242
Lambda 308
Delegate 304
SendMessage 61539

Unity Function Performance

Unity Function Performance (No SendMessage)

It turns out that GameObject.SendMessage is ludicrously slow. It’s about 200x slower than the next-slowest type of function. That said, each function type was called 100 million times, so it’s not so slow that you should never use it. Each call was only 6/10,000 of a millisecond, so feel free to make a few of these calls without worrying that it’ll ruin your app’s performance.

Delegates and lambdas are essentially the same and perform essentially the same. They’re a bit slower than a virtual function call, but close enough that you can consider them about the same performance. As mentioned, all three types of functions are about 200x faster than SendMessage.

Finally there are the “fast” functions: non-virtual instance and static functions. These are again an order of magnitude faster than the virtual functions, lambdas, and delegates. In the previous article the instance functions were a bit slower than the static functions, but that’s been reversed somewhere between Unity 5.0 and Unity 5.4. Regardless, these functions are in the same ballpark performance-wise and blisteringly fast compared to their “virtual” competitors and SendMessage.

So go ahead and use non-virtual functions to your heart’s content, provided you’re not calling them in huge numbers such as one million per frame. The overhead is really tiny for almost all tasks. Virtual functions, lambdas, and delegates are probably also fine for most tasks. You can certainly make thousands of calls per frame without causing any issues. Just make sure to be careful with garbage creation when using lambdas. Finally there is GameObject.SendMessage that you should use extremely sparingly. A few per frame is OK, but never use them heavily or you’ll quickly run into performance problems.

Do you ever use SendMessage? Do you avoid virtual functions, lambdas, or delegates? Let me know how it’s worked out for you in the comments!