10000 Update() calls

December 23, 2015 in Technology

Unity has so-called Messaging system which allows you to define a bunch of magic methods in your scripts which will be called at specific events while your game is running. This is a very simple and easy to understand concept especially good for new users. Just define an Update method like this and it will be called once a frame!

void Update() {
    transform.Translate(0, 0, Time.deltaTime);
}

For an experienced developer this code is a bit odd.

  1. It’s not clear how exactly this method is called.
  2. It’s not clear in what order these methods are called if you have several objects in a scene.
  3. This code style doesn’t work with intellisense.

How Update is called

No, Unity doesn’t use System.Reflection to find a magic method every time it needs to call one.

Instead, the first time a MonoBehaviour of a given type is accessed the underlying script is inspected through scripting runtime (either Mono or IL2CPP) whether it has any magic methods defined and this information is cached. If a MonoBehaviour has a specific method it is added to a proper list, for example if a script has Update method defined it is added to a list of scripts which need to be updated every frame.

During the game Unity just iterates through these lists and executes methods from it — that simple. Also, this is why it doesn’t matter if your Update method is public or private.

In what order Updates are executed

The order is specified by Script Execution Order Settings (menu: Edit > Project Settings > Script Execution Order). It might be not the best way to manually set the order of 1000 scripts but if you want one script to be executed after all other ones this way is acceptable. Of course, in the future we want to have a more convenient way to specify execution order, using an attribute in code for example.

It doesn’t work with intellisense

We all use an IDE of some sort to edit our C# scripts in Unity, most of them don’t like magic methods for which they can’t figure out where they are called, if at all. This leads to warnings and makes it harder to navigate the code.

Sometimes developers add an abstract class extending MonoBehaviour, call it BaseMonoBehaviour or alike and make every script in their project extend this class. They put some basic useful functionality in it along with a bunch of virtual magic methods like so:

public abstract class BaseMonobehaviour : MonoBehaviour {
    protected virtual void Awake() {}
    protected virtual void Start() {}
    protected virtual void OnEnable() {}
    protected virtual void OnDisable() {}
    protected virtual void Update() {}
    protected virtual void LateUpdate() {}
    protected virtual void FixedUpdate() {}
}

This structure makes using MonoBehaviours in your code more logical but has one little flaw. I bet you already figured it out…

All your MonoBehaviours will be in all update lists Unity uses internally, all these methods will be called each frame for all your scripts, mostly doing nothing at all!

One might ask why should anyone care about an empty method? The thing is that these are the calls from native C++ land to managed C# land, they have a cost. Let’s see what this cost is.

Calling 10000 Updates

For this post I created a small example project which is available on Github. It has 2 scenes which can be changed by tapping on a device or pressing any key in editor:

(1) In the first scene 10000 MonoBehaviours are created with this code inside:

private void Update() {
    i++;
}

(2) In the second scene another 10000 MonoBehaviours are created but instead of having an Update they have a custom UpdateMe method which is called by a manager script every frame like so:

private void Update() {
    var count = list.Count;
    for (var i = 0; i < count; i++) list[i].UpdateMe();
}

The test project was run on 2 iOS devices compiled to Mono and IL2CPP in non-Development mode in Release configuration. Time was measured as following:

  1. Set up a Stopwatch in the first Update called (configured in Script Execution Order),
  2. Stop the Stopwatch at LateUpdate,
  3. Average the timings over a few minutes.

Unity version: 5.2.2f1
iOS version: 9.0

Mono

WOW! This is a lot! There must be something wrong with the test!

Actually, I just forgot to set Script Call Optimization to Fast but no Exceptions, but now we can see what impact on performance this particular setting has… not that anyone cares anymore with IL2CPP.

Mono (fast but no exceptions)

OK, this is better. Let’s switch to IL2CPP.

IL2CPP

Here we see two things:

  1. This particular optimization still makes sense in IL2CPP.
  2. IL2CPP still has room for improvement and as I’m writing this post Scripting and IL2CPP teams are working hard to increase performance. For example the latest Scripting branch contains optimizations making the test run 35% faster.

I’ll explain what Unity is doing under the hood in a few moments. But right now let’s change our Manager code to make it 5 times faster!

Interface calls, virtual calls and array access

If you haven’t read this great series of posts about IL2CPP internals you should do it right after you finish reading this one!

It turns out that if you’d wanted to iterate through a list of 10000 elements every frame you’d better use an array instead of a List because in this case generated C++ code is simpler and array access is just faster.

In the next test I changed List<ManagedUpdateBehavior> to ManagedUpdateBehavior[].

This looks much better!

Update: I ran the test with array on Mono and got 0.23ms

Instruments to the rescue!

We figured out that calling functions from C++ to C# is not fast, but let’s find out what Unity is actually doing when calling Updates on all these objects. The easiest way to do this is to use Time Profiler from Apple Instruments.

Note that this is not a Mono vs. IL2CPP test — most of the things described further are also true for a Mono iOS build.

I launched the test on iPhone 6 with Time Profiler, recorded a few minutes of data and selected a one minute interval to inspect. We are interested in everything starting from this line:
void BaseBehaviourManager::CommonUpdate<BehaviourManager>()

If you haven’t used Instruments before, on the right you see functions sorted by execution time and other functions they call. The most left column is CPU time in ms and % of these functions and functions they call combined, second left column is self execution time of the function. Note that since CPU wasn’t fully used by Unity during this experiment we see 10 seconds of CPU time spent on our Updates in a 60 seconds interval. Obviously we are interested in functions taking most time to execute.

I used my mad Photoshop skills and color coded a few areas for you to better understand what’s going on.

UpdateBehavior.Update()

In the middle you see our Update method or how IL2CPP calls it — UpdateBehavior_Update_m18. But before getting there Unity does a lot of other things.

Iterate over all Behaviours

Unity goes over all Behaviours to update them. Special iterator class, SafeIterator, ensures that nothing breaks if someone decides to delete the next item on the list. Just iterating over all registered Behaviours takes 1517ms out of total 9979ms.

Check if the call is valid

Next, Unity does a bunch of checks to make sure that it is calling a valid existing method on an active GameObject which has been initialized and its Start method called. You don’t want your game to crash if you destroy a GameObject during Update, do you? These checks take another 2188ms out of total 9979ms.

Prepare to invoke the method

Unity creates an instance of ScriptingInvocationNoArgs (which represents a call from native side to managed side) together with ScriptingArguments and orders IL2CPP virtual machine to invoke the method (scripting_method_invoke function). This step takes 2061ms out of total 9979ms.

Call the method

scripting_method_invoke function checks that passed arguments are valid (900ms) and then calls Runtime::Invoke method of IL2CPP virtual machine (1520ms). First, Runtime::Invoke checks if such method exists (1018ms). Next, it calls a generated RuntimeInvoker function for method signature (283ms). It in turn calls our Update function which according to Time Profiler takes 42ms to execute.

And a nice colorful table.

Managed Updates

Now let’s use Time Profiler with the manager test. You can see on the screenshot that there are the same methods (some of them take less than 1ms total so they are not even shown) but most of the execution time is actually going to UpdateMe function (or how IL2CPP calls it — ManagedUpdateBehavior_UpdateMe_m14). Plus, there’s a null check inserted by IL2CPP to make sure that the array we are iterating over is not null.

The next image uses the same colors.

So, what do you think now, should one care about a little method call?

A few words about the test

To be honest, this test is not completely fair. Unity does a great job guarding you and your game from unintended behavior and crashes: Is this GameObject active? Wasn’t it destroyed during this update loop? Does Update method exist on the object? What to do with a MonoBehaviour created during this update loop? — my manager script doesn’t handle anything of that, it just iterates through a list of objects to update.

In real world manager script probably would have been more complicated and slower to execute. But in this case I am the developer — I know what my code is supposed to do and I architect my manager class knowing what behavior is possible and what isn’t in my game. Unity unfortunately doesn’t possess such knowledge.

What should you do?

Of course it all depends on your project, but in the field it’s not rare to see a game using a large number of GameObjects in the scene each executing some logic every frame. Usually it’s a little bit of code which doesn’t seem to affect anything, but when the number grows very large the overhead of calling thousands of Update methods starts to be noticeable. At this point it might already be too late to change the game’s architecture and refactor all these objects into manager pattern.

You have the data now, think about it at the beginning of your next project.

Comments (76)

Subscribe to comments
  1. boris

    February 11, 2016 at 4:06 am / 

    Hey i don’t understand this managed update concept.

    If i have 50 gameobjects with a script component that has update() function and inside the update it accesses gameobject position for example.

    In this case the gameobject position is unique to each gameobject.

    I need to have 50 update() calls, 1 for each gameobject.

    How do I implement an approach where i have only 1 update() in some manager and can access gameobject position of all objects??? i don’t understand how i would do this properly? Would i have to keep all 50 gameobjects in an array and access their positions in a loop and then pass data back into the gameobject?

    Is this better than having 50 update() funtions?

    1. Valentin Simonov

      February 11, 2016 at 3:14 pm / 

      I think you are mixing two tasks together:
      1. A manager script which has an array of your script components on gameobjects which calls UpdateMe() function on each component every frame (as it was done in the example from the post).
      2. A manager script which has an array of gameobjects which does some logic (involving transforms) on all gameobjects in turn.
      The difference is that in (1) each script component does the work and accesses its own transform, while in (2) the manager does something with each transform it gets from array. In both cases every transform belongs to individual gameobject and is unique.

  2. Jonney Shih

    January 31, 2016 at 10:24 pm / 

    Why not implement an in-house callback manager, that’s what a game engine is supposed to do!

  3. Johan M

    January 24, 2016 at 2:46 pm / 

    As an old-style developer I highly prefer to have my own handled managers, and only have one Update() on the top-level manager, that I then cascade down to the other classes as needed, only when needed. This blog post proves that this is a sane choice to make, and not implement Update() in each and every class, and have guard-clauses to return for every case when we don’t want it to actually run for that instance etc.

    1. David

      January 27, 2016 at 5:58 am / 

      This ^^^

      I’ve been building games this way for something around 20 years. It’s the correct approach for any game, not just unity games. This whole ‘attach every script to an object and use its Update()’ method really strikes me as the wrong way to do things.

  4. Aaron

    January 12, 2016 at 9:40 pm / 

    Just please make sure to provide plenty of tutorials and update the old ones accordingly to demonstrate.
    I promise you there are plenty of newer “developers” like myself that haven’t made it that far into UNITY yet that we wont have to re-train ourselves to this new approach.
    I don’t have a horse in this race yet so it doesn’t effect my interests yet.

    However I am all for improving Unity and making it better.

    Re-emphasizing – update old tutorials (re do them, please take the time to do this without simply adding annotations as Unity progresses (it only helps old tutorials so much before it isn’t anything like the original version) / this wont scare off potential new developers when something breaks from an old tutorial.

    I may be putting too much stock into what changes / approach the scripting team is doing though.

  5. Imi

    January 7, 2016 at 5:19 pm / 

    So, after this article… Is Unity finally going to change the default Script template that ships to remove the empty Start() and Update() functions? Please?

    (I know that the templates can be changed, but srsly… why?)

    1. FrkTheMantis

      January 7, 2016 at 8:38 pm / 

      Still useful for newcomers ;)

      1. adsamcik

        January 11, 2016 at 12:20 pm / 

        I agree, it really helped me when I started with Unity because there are lots of things/functions you still need to know. It doesn’t take that much time to remove them and also, how often do you create a script? Every hour? I doubt it.

        1. Adam Tuliper

          January 15, 2016 at 11:30 pm / 

          Aren’t empty methods typically optimized out by any compiler though?

  6. Rodrigo

    January 4, 2016 at 2:00 pm / 

    Has anyone tried this on PC? Is it normal that I’m getting 12ish ms on an i7 4770k, for the Update scene?

  7. focus

    January 3, 2016 at 12:16 am / 

    Thanks for your article, Valentin! =)
    Going to bookmark it for colleagues who likes to leave empty Start() and Update() methods from the new C# script template even if they don’t need them.

  8. Mahan Moghaddam

    January 2, 2016 at 7:10 pm / 

    Unity is a very good tool, I don’t know why some people complain. Compared to other tools created in the past decade, Unity is one of the best ones. Go ahead and run Unreal 3, it’s like you’re working with something from the 90’s. Unity has issues, but not that big, plus it’s a good practice for engine developers to follow Unity’s architecture, it worked fine for me.

  9. Name

    January 1, 2016 at 5:43 am / 

    Interesting that unity posts things like this on their blog.

    The post basically says “the framework is old, bad, and slow, the new framework is even slower, here’s a half finished hack you can use instead”.

    1. Robert

      January 5, 2016 at 9:21 am / 

      +1

  10. Manny

    December 29, 2015 at 10:42 pm / 

    First of all — great article. I’m always thrilled to learn something new, especially when its something that has a potentially huge impact.

    Second, has this “Managed Update” concept been some sort of Open Secret? This is the first I’ve read about it. All the articles I’ve read about Unity Performance Optimizations did not mention this, and I’ve read quite a few… or did I just miss it? I’ve just tried to search for more articles on the topic but there appears to be very little. I guess better late to the party than never.

    And last, (this is the part where I put on my fireproof pants), does this hold true if we’re developing using Javascript/Unityscript? My guess would be “yes” since for the final device build, I’m using IL2CPP. Just confirming.

    Cheers,
    Manny

    1. Valentin Simonov

      December 30, 2015 at 12:53 pm / 

      Correct. C# and UnityScript are compiled to the same bytecode.
      Also it is worth mentioning that we’d like everyone to use C# instead of UnityScript.

      1. Pogo

        January 6, 2016 at 9:38 am / 

        Stop writing documentation examples in Uscript and you’ll see newcomers using c# by default.

      2. Vincent

        January 13, 2016 at 9:56 pm / 

        Hi Valentin,

        While it look like you will drop support for UnityScript, do you have a plan in the future to support newer version of javascript instead? (es2015 and more) Or you just want a single language used to build a game with Unity?

        Kind Regards.

  11. BlackCyrax

    December 26, 2015 at 3:46 pm / 

    I try to always use unity ‘tools’ instead of my customized ones … so, I don’t need to face problems because of my “scapes” LOL. Actually, I found messaging system really useful and clear to understand.

  12. SomeDude

    December 25, 2015 at 4:58 am / 

    “The scripting team are designing a whole new approach”
    Unity team: don’t change anything. Implementing managers in managed code – that’s what many developers already doing. In our case we have whole framework on top of unity api implemented in managed code: for fsm, messaging, etc.
    Unity is already great! Most important – it’s currently free!

    1. Bob

      December 25, 2015 at 9:06 am / 

      Collision events are completely out of our control. So yes, they DO have to fix this

      1. SomeDude

        December 25, 2015 at 9:57 am / 

        Collision detection already performed by physics engine. You want to perform polling yourself (in managed code)? To avoid undesired collision/trigger events – just disable that object/component when you don’t need it.

        1. Bob

          December 25, 2015 at 6:09 pm / 

          I mean collision events also suffer a severe performance loss due to being called by the messaging system. And we can’t make a “manager” for that like we can with Update calls. This is something only unity can fix.

          (Also sorry for accidental double post)

    2. Bob

      December 25, 2015 at 9:12 am / 

      We have no control over OnCollisionStay events, for example. So they DO have to fix this

  13. Bob

    December 24, 2015 at 10:13 pm / 

    This is extremely depressing. Depressing enough to make me want to switch to another game engine and tell all my acquaintances to avoid Unity.

    Completely replacing this atrocious messaging system should be Unity’s #1 priority right now, even if it pushes back everything everything else and/or isn’t backwards compatible. Can you at least reassure us that the team is working on a fix?

    1. Richard Fine

      December 25, 2015 at 3:08 am / 

      The scripting team are designing a whole new approach that will (amongst other things) allow for faster scripting invocations, yes.

      1. Pablo

        December 25, 2015 at 3:45 am / 

        Can i say something? This is not so bad…think about it…when you profile an application you see it…if you had profile some of your games, you already know that the Update call’s isn’t a bottleneck or something that decreases the performance deeply. It’s just consuming a little bit of time of the proccesor. So, it’s not so chaotical.

      2. Christian

        December 25, 2015 at 9:13 am / 

        Please, if you make such core change make it optional!
        For many people who already work smartly the current version is perfectly fine and the new version will for sure introduce new issues.
        So please if you do make such a big change make it completely separated from the main code like IL2CPP so that it won’t break existing systems.
        I couldn’t stand to wait god know how many version for a stable version because of a feature I don’t need.

      3. Trigve

        January 5, 2016 at 7:17 pm / 

        I know that folks here wouldn’t agree with me but I would really like to have a C API (not C++ but pure C) exposed, too. We’re using unity but only as “backend” and all the game core (90%) is done in C++ (as a native plugin) using mono embedded API. Another advantage of C API would be one can implement their own scripting subsystem. I don’t/can’t/want to use Unreal 4 because of some missing features/complications.

      4. David

        January 10, 2016 at 4:43 am / 

        Please don’t do that. Seriously. Don’t. All you’re going to do is introduce bugs and other issues into games that are already working just perfectly fine with the existing infrustructre just to accomodate a very small minority.

        If you want to do something, redesign Unity’s device input system. That needs a massvie overhaul. How about adding the ability to call gameObject.Find() on objects that are inactive? Lots of things that need improving, but the core architecture of your system works just fine. While I obviously can’t speak for everyone, I personally have no interest in rewriting my whole game to accomodate a massive change that isn’t being asked for.

    2. SomeDude

      December 25, 2015 at 4:48 am / 

      You can use single MonoBehavior for game logic (not talking about triggers/collision detection). Treat it’s Update() like WinMain(). Manually update your subsystems, like:
      //not a real code, just example
      void Update()
      {
      FSM.update();
      EntityManager.update();

      }

      1. David

        January 10, 2016 at 4:35 am / 

        This is what I’m doing. I have 1 monobehaviour script attached to 1 empty game object in the scene. That passes its Update() call to the various loaded managers and tasks the characters have to perform. Only the loaded classes get the calls. So there’s never a problem with 10000 update calls. There’s 1, and it calls the methods it needs to.

        I’m getting outstanding performance even at the highest rendering settings (I never drop below Unity’s capped 60 frames a second).

        There is **zero** reason to completely rewrite the core of Unity. It would very likely do nothing but break many millions of lines of code.

    3. Kumo

      December 29, 2015 at 9:54 am / 

      Don’t forget that a lot of game studios made successful games even with these “awful” limitations. Unity is already pretty good as it is, any improvements will just make it better, not “more acceptable”.

  14. Pete

    December 24, 2015 at 6:05 pm / 

    Thanks a lot for this post since it clarifies a lot of things.

    Having said that, I don’t think the comparison is fair with Mono, for the following reasons:

    1. The version of Mono that Unity is using is rather old. The newest one 4.2.1 has lots of improvements:

    http://www.mono-project.com/docs/about-mono/releases/4.0.0/
    http://www.mono-project.com/docs/about-mono/releases/4.2.1/

    These include, inter ália: better implementations of GC, optimizations in AOT compilation, SIMD and the inclusion of MSFT’s open sourced .NET code.

    2. Any interop call -either from .NET to Native or viceversa- has a penalty, due to, for example, the overhead of mapping unmanaged datatypes to managed ones. So, it’s not a surprise that updating behaviors from within a managed handler turns out to be faster than an interop call between the native part of the engine and behaviors.

    3. C# it-self, as a language, has been and still is improved over time, what in turn means that its methods are periodically reviewed and refactored to increase performance. What is more, the current trend is to go “Universal” with .NET Native so that, marginally, perf diferences between “pure” native code and “converted” one tend to zero. Something similar to what you’re doing with IL2CPP (and as said before, Mono has AOT compilation).

    4. Let me remind you that Unity also has its own version of .NET assemblies (based on C# 3.5) which, compared to .NET’s and Mono’s, could introduce unwanted overhead, specially in comparison to the latest version of the language: C# 6.

    5. UnityEngine was conceived and developed to do interop with other languages than C# (that is, UnityScript and Boo) -I don’t know whether the fact that the first versions of the Unity Editor were meant for MacOSX strongly influenced that decision or not, but its architecture wasn’t tailored to fit C# practices. As a matter of fact, in the attempt of avoiding deep hierarchies in favor of an entity-component-system approach, it does not fully comply with OOP. The fact that you have to query behavior in search of certain operations (like Update) as well as approaches like SendMessage/BroadcastMessage seem like a hack that had to be used as a result of that, which in turn doesn’t bring the best UX out-of-the-box on any IDE.

    6. A corolary of 5 above is how Unity handles events. Not only doesn’t it use C# approach to events but also it avoid the use of the Observable pattern at all. In fact, it goes the other way around: in the editor, for an event like button pressed, you have to specify not only the objects but the operations of those objects to call, instead of just registering as an observer and sending the same customized event args to all observers when the event happens. The result? A cumbersome way of handling events on the editor, in particular, when classes and operations change during game development, and finally,

    7. Lookups on arrays and lists shouldn’t differ in a way that using lists over arrays lead to overheads when traversing lists since the only moment when such penalties should exist is when adding elements obliges the list to expand its inner array. If they differ, then you should check up the version of the Mono compiler you are using, since lookups are optimized in .NET for lists to avoid such thing (and I guess that also in current versions of Mono).

    Again, this post is valuable since it help us deal with perf with Unity, but it also exposes some issues that could be considered design flaws. I don’t want to offend anyone with this. On the contrary, I want it to become a better engine. In this sense, imvho, performance of the UnityEngine not only could be improved with native compilation (IL2CPP) but also by a full redesign so that on the behaviors side it fully complies with OOP and C# standards avoiding interop calls as much as possible. In short: a) get rid of SendMessage approach, b) implement a managed handlers for calls to Update, LateUpdate, and so on so forth, c) either include Update (and other) methods where appropriate in Monobehaviors or create interfaces for them, d) re-implement how you handle events, e) support c# 6, f) upgrade your Mono backend to 4.x, and g) try not to use you own versions of .NET assemblies unless really necessary and optimized.

    I hope you guys consider/are considering this. Thanks again.

  15. Brendan

    December 24, 2015 at 4:47 pm / 

    Valentin I know back at one of the Unite roadmap sessions this year they had mentioned that there was work being started on a MonoBehaviour replacement/alternative where they might move away from magic methods and make some new choices, do you think that we will here more about it in the near future?

    1. Valentin Simonov

      December 25, 2015 at 7:04 am / 

      Sure, as Richard said one comment above the scripting team are designing a whole new approach to MonoBehaviours. Expect to hear about it soon.

  16. haim

    December 24, 2015 at 11:22 am / 

    OK, i read about this somewhere else, so in my current project instead of using Update() as the main loop for my characters i start coroutine in Start(), the coroutine stops when the characters is dead.
    should this improve performance?

    1. Seneral

      December 24, 2015 at 12:09 pm / 

      I took a look at StartCoroutine, it’s actually a call into the native code. That means it’s handled on the unmanaged side so it should be about the same system as Update, only temporarily. Maybe Overhead is a bit lower, as it does not need to fetch Update from your MonoBehaviour explicitly, but idk. I wouldn’t count on it, but you could actually perform a similar test;)

      1. Valentin Simonov

        December 24, 2015 at 12:55 pm / 

        I updated the test on GitHub and it looks that this Coroutines approach is 5 times slower than using Updates. Logically it should be slower at least because the engine has to make 2 calls to the returned enumerator: moveNext and current.

        1. Teal Rogers

          January 3, 2016 at 9:24 pm / 

          There’s also the fact that co-routines have a per frame GC alloc, whereas Update does not.

  17. Seb

    December 24, 2015 at 10:54 am / 

    I wouldn’t expect this kind of articles on the unity blog. It’s like to admit that the framework is old and inefficient, but instead to do something about it, let you know that there are alternatives. Luckily there are alternatives.

    1. Valentin Simonov

      December 25, 2015 at 7:20 am / 

      Developers want to make beautiful and successful games, we help them providing the tools and support services so they’d use the tool right. Meanwhile we are working on improving various subsystems of the engine.

    1. Kailas Dierk

      December 24, 2015 at 4:36 am / 

      Screwed up the formatting on that.

      Of course, in the future we want to have a more convenient way to specify execution order, using an attribute in code for example.

      I made an asset which does just that.

      It would be pretty cool if the attribute they implement can be used on individual methods. So you could have a script Awake before everything else, but Update after.

  18. JMellow

    December 24, 2015 at 3:06 am / 

    Nice. These are the types of posts I’d like to see more of.

  19. Pablo

    December 24, 2015 at 12:30 am / 

    What happens with the Update methods from built in scripts that we cannot edit (Camera component, Collider component, MeshRenderer, etc) ?

    1. Richard Fine

      December 24, 2015 at 3:50 am / 

      They’re not scripts, so they don’t work like MonoScripts do. Instead, all components of a particular type are added to a ‘manager’ when they’re enabled, and the manager is called directly at the appropriate point in the main game loop; it then does the work for the components in the most efficient way possible (looping through them one at a time, dispatching them to worker threads, or whatever makes sense for the subsystem in question).

      1. Pablo

        December 24, 2015 at 4:27 am / 

        And what about other functions that are Mono Behaviour called repeatedly like LateUpdate (We must manage them too?)?

        Thank you Richard.

        1. Valentin Simonov

          December 24, 2015 at 9:03 am / 

          Yes. Update, LateUpdate, FixedUpdate — these go through the same code path.

  20. Tristan

    December 24, 2015 at 12:09 am / 

    Wow! Thanks for the tip!

  21. Tomer Barkan

    December 23, 2015 at 10:35 pm / 

    Unless I’m missing something, it seems that having a manager in managed code that calls all the update functions is significantly more efficient than letting the engine call them all from c++ code.

    In that case, I ask myself, why not create this manager, in managed code, as part of Unity’s engine, and have it always be the one that calls update? It sounds to me like this should be an architecture decision by Unity, that update calls (and other calls that happen a lot) should be handled from a central part of the engine that runs in managed code to start with.

    Is this something you guys in Unity are thinking about?

    1. Valentin Simonov

      December 25, 2015 at 7:13 am / 

      See the previous reply.

  22. Lior Tal

    December 23, 2015 at 10:15 pm / 

    Nice article, although I personally still hadn’t hit this limit myself.

    A couple of questions:

    1. You mention that you cache the method reference and then invoke it from a list; in case of an empty method – can’t you discard the method so it won’t even be considered for execution? (you’re already using mono.cecil for a bunch of internal tools, you could use it to check if the method body is empty).

    2. Did you consider creating a managed-side Update manager that will avoid most of these costs of native-to-managed calls? (or are those checks expensive for other reasons too?)

    3. The title for one of the sections is “INTERFACE CALLS, VIRTUAL CALLS AND ARRAY ACCESS”, but nothing is mentioned regarding those topics… how do interface/virtual calls affect the performance ?

    Again, nice post and keep ’em coming.

    1. Valentin Simonov

      December 25, 2015 at 7:11 am / 

      1. I suspect that nobody did this because why would you have an empty Update method in the first place?! o.O But this seems to be a good candidate for the next Hack Week.

      2. I don’t know all the details but it’s not that simple to make it easy and fast. The scripting team is designing the whole new approach as we speak.

      3. This was meant to be the reference to http://blogs.unity3d.com/2015/06/03/il2cpp-internals-method-calls/ since list[i] is an interface call.

      1. Florian

        December 28, 2015 at 5:43 pm / 

        Regarding #1, I added that in the base ruleset in “Unity Gendarme” (a fork of the fantastic Gendarme analysis tool). I did that was a while ago while between jobs, so the code is probably a bit crap, but apparently relevant to the discussion.
        https://github.com/fderudder/unity-gendarme/tree/master/gendarme/rules/Unity.Rules.Performance

        Funnily enough, empty methods are mode widespread that you might think at first. Like having a “create new script” template with all the methods by default, so you don’t have to look them up.

        One of the projects I worked on had several empty methods, and I regularly check some released Unity games to check that. You’d be surprised.

      2. Cameron Bonde

        January 7, 2016 at 4:05 am / 

        If you did detect empty functions, you could actually do the virtual methods interface without punishment.

      3. anonymized to prevent reprisals

        January 19, 2016 at 11:24 am / 

        There might be an empty Update() method because every single Unity-generated script contains Start() and Update() definitions by default; this was actually mentioned previously in the thread.

        Not to be rude, but your question seems nonsensical, condescending, asinine, and a bit obtuse. Unity3D might do well to reconsider having you in a customer-facing position, or at least moderate your comments to make sure you aren’t alienating new developers with your inconsiderate and thoughtless remarks.

  23. Pablo

    December 23, 2015 at 9:39 pm / 

    Very interesting article. Am i wrong of concluding that if we have a lot of Update calls on MonoBehaviours it is better to use our own implementation of the Update Calls (Iterates trough monobehaviours with simple arrays and call UpdateMe and so on). I am about to check the project that Valentin uploaded but first i have this doubt.

    And in the other hand, i think that this is something that Unity has to solve as fast as possible.

    Thank you and happy holidays.

  24. Adam

    December 23, 2015 at 8:15 pm / 

    I realize this post isn’t meant to compare Mono and IL2CPP, but man, it sure does make IL2CPP look bad. It’s supposed to be innately faster than Mono, yet months into its existence it’s 100% slower in this scenario? Calling MonoBehaviour methods isn’t exactly an edge case.

    1. Valentin Simonov

      December 24, 2015 at 9:54 am / 

      Well, IL2CPP is faster than Mono in a lot of things:
      http://blogs.unity3d.com/2015/01/29/unity-4-6-2-ios-64-bit-support/
      In this particular case it might not be very well optimized yet. I ran the test with array on Mono and got 0.23ms vs. 0.22ms in IL2CPP. But once again, the post is not to compare virtual machines.

  25. Arthur Brussee

    December 23, 2015 at 6:45 pm / 

    Great to see unity taking a look at this – I’ve been reporting the issue of slow callbacks through bugs, feedback site and talking directly to Unity devs.

    The Update calls are bad enough, but everything using SendMessages (OnEnable etc.) are even worse to a point where we had to seriously re-engineer stuff to make streaming not hickup on unity calling OnEnable. Not the code in of OnEnable, them, just _calling_ them. This was for about 2000 objects on PC level hardware, and ~10 ms was spent on calling those. Yikes.

    The last paragraph slighty concers me. Are we really expected to avoid using Unity callbacks for performance? 10K is not a lot, 2k OnEnable’s is nothing. We can do some special case handling but it feels like it really shouldn’t be a concern to use these callbacks.

    It feels like Unity really needs to take a hard look on how to improve the performance on these callbacks. Looking at the numbers there’s a lot of stuff in there that seems duplicate (checking if the call is valid, then if it exists, then if the arguments are valid….), redundant (lots of time spent in argument handling – when there’ll never be arguments to Update) or cachable (whether method exists etc.).

    It’s good to hear that the IL2CPP runtime is being optimized for this case but it seems that generally it needs to be considered how to structure the engine to make this faster.

    And good to see it’s at least on the radar that it’s slow now :)

    1. Valentin Simonov

      December 24, 2015 at 9:19 am / 

      OnEnable actually uses the same mechanism as Update. Have you profiled the code and witnessed that it was really just calling this method and not awaking other components on your game objects? Physics component, Animator and other components are pretty costly to create, enable and disable.

      > Are we really expected to avoid using Unity callbacks for performance?
      No, you need to think about this limitation when architecting your game and vigorously profile. If this particular issue affects your game you know what to do.

      Also, as I said recent scripting optimizations remove some of the overhead you mentioned.

  26. Nico

    December 23, 2015 at 5:38 pm / 

    It turns out that if you’d wanted to iterate through a list of 10000 elements every frame you’d better use an array instead of a List because in this case generated C++ code is simpler and array access is just faster.

    This kind of comment irks me to no end. On the one hand, Unity is saying “hey, you can program your game with C#, which is an easy-to-use, safe, productive and powerful language!”. But then it’s like “oh yeah, all those features that make the language so easy and productive, yeah, you shouldn’t use those because they’re slow”. It sends a conflicting message and leads to a lot of unnecessary arguments about what ‘good’ code is. At this point everyone would be better off if we could just write our games directly in C++.

    Not only that, but a List in C# is nothing more than a wrapper around an array with automatic array resizing features. If the IL2CPP compiler had a special case to recognize and deal with Lists specifically (which is what a lot of Microsoft’s .NET compiler tools do too), then there’s no reason why iterating over a List should be any slower than iterating over an array.

    1. Arthur Brussee

      December 23, 2015 at 6:56 pm / 

      I’m guessing it’s because indexing a list is technically a member function, which means il2cpp will do a null check before each call, and maybe not properly inlining this call etc.

      However, I agree that it’s really bad that we have to worry about that. Unity mentioned they’d like to special case optimize IL2CPP for unity code. Seems list access should definitely be one of them.

      1. Nico

        December 23, 2015 at 7:59 pm / 

        Yes, indexing a List invokes a call to the getter of the Item property, which in turn indexes the _items array field inside the List object. And since the Item property is an implementation of the IList interface, that call is a virtual method call too, bringing with it all sorts of overhead. Null checks don’t even make the difference here; C# being a safe language will also null-check a plain array when indexing it.

        This is precisely why you would want the IL2CPP compiler to know about Lists and create a shortcut for the indexing operator that accesses the internal array directly. From a puristic standpoint, it’s not nice to give a compiler knowledge about classes inside the framework, but it does open up a lot of possibilities for optimization. And the .NET compiler does it too, e.g. by translating large switch statements into a Dictionary-based lookup table.

        My bigger issue however is that with all these edge cases, people end up writing C# code for Unity as if it is plain old C, which basically means throwing out everything that makes C# worthwhile as a language in the first place. Writing idiomatic C# code (using LINQ, foreach statements, relying on the GC for memory management, etc) in Unity is considered by many as ‘wrong’, leading to a lot of micro-optimization work, and you kind of end up with the worst of both worlds. It makes you wonder why we’re still using Mono at all.

        1. Valentin Simonov

          December 24, 2015 at 9:33 am / 

          Nico, I understand your concerns and I am the person usually talking to customers explaining the things you mentioned advising them to “make their code dumber”. There’s nothing inherently bad in Lists, Lambdas, LINQ, foreach and other .NET features, but considering mobile devices limitations one have to use the most CPU and GC efficient code they can write. This is how mobile devices and Unity as a platform work right now and developers need to know that.

          Not to mention that to write efficient and error-prone code in C++ you need to have a lot of knowledge and experience as well.

          We are working on improving current situation, on Mono/.NET upgrade, implementing various scripting and IL2CPP optimizations. But scripting is only a small part of the engine, we also have a lot of other really important things to do and unfortunately not enough people. Patience, my friend (8

    2. Valentin Simonov

      December 24, 2015 at 9:57 am / 

      Another thing is that Lists are just slower or more precisely our Mono compiler generates slower code for them. I ran the test with array on Mono and got 0.23ms (was 0.52ms with List) vs. 0.22ms in IL2CPP.

  27. Chris Sinclair

    December 23, 2015 at 5:29 pm / 

    Instead of using an abstract “BaseMonobehaviour” class which implements all these methods, I recommend creating granular, individual interfaces for the particular behaviours you want your objects to implement. For example:


    public interface IUpdate
    {
    void Update();
    }

    public interface IAwake
    {
    void Awake();
    }

    Any “MonoBehaviour” you create implements only the interfaces you intend for it to do:


    public class MyBehaviour : MonoBehaviour, IUpdate
    {
    public void IUpdate()
    {
    //do something
    }
    }

    Of course at this point, you have compile-time safety to catch those nasty typo’d case sensitive names (Anyone out there spend too much time trying to figure out and fix a “void update()”?)

    Regarding intellisense/tooling, with Visual Studio (I can’t speak for the other IDEs), you can auto-implement the interface to deposit the placeholder method automatically. Furthermore, this also gives you a maintenance benefit in that it becomes trivial to find all objects that are “Updating” or “Awaking” or have “FixedUpdate” (just “Find All References” to the particular interface)

    Finally, if you find you keep implementing the same combination of interfaces, you can always combine them to a common interface:


    public interface IStandardBehaviour : IAwake, IStart, IUpdate, IOnEnable
    {

    }

    public class MyBehaviour : MonoBehaviour, IStandardBehaviour
    {
    //implement all 4 interfaces inherited by IStandardBehaviour
    }

    (Sorry if the code formatting above got botched)

    1. Chris Sinclair

      December 23, 2015 at 5:31 pm / 

      Woops, typo’d my first “MyBehaviour” class implementation’s “Update” method name. It should read:


      public class MyBehaviour : MonoBehaviour, IUpdate
      {
      public void Update()
      {
      //do something
      }
      }

  28. John

    December 23, 2015 at 5:20 pm / 

    Very interesting. Is there anyway to increase performance for OnCollision events? I have a project with a large number (10000+) of GameObjects that have no Update() but all have OnCollisionEnter() and a performance boost would be amazing.

    1. Valentin Simonov

      December 23, 2015 at 5:47 pm / 

      OnCollisionEnter and its friends are implemented through SendMessage so it should be even worse*. Of course Unity doesn’t try to send these messages to scripts which don’t have such callbacks, also one rarely has 10000 objects colliding with each other EVERY frame.

      When working with 2D and 3D physics you should look at other things which reduce performance like not moving static colliders or 2D colliders inside a Rigidbody2D.

      1. Robert Cummings

        December 23, 2015 at 6:53 pm / 

        Very interesting article. But regarding physics OnCollision/OnStay – especially stay, needs optimising Unity’s side. It is grotesquely inefficient to the point where we had to change the gameplay and there wasn’t alternatives for it (think physical interactions between characters). We really needed stay but it crapped out with just 30 characters on an i7.

        So going forward, if you’re using Sendmessage internally for collision, I don’t think that’s very optimal, do you? Perhaps a better pattern can be achieved?

        Thanks for hard work, regardless :)

        1. Morten Skaaning

          December 24, 2015 at 12:51 pm / 

          Hi,

          Can you open a bug with a test scene in it, when we can get to work on it. Also post the bug Id here.

          Regards,
          Morten

      2. Nick Clark

        December 24, 2015 at 1:29 am / 

        “2D colliders inside a Rigidbody2D”

        Can you elaborate on this? Don’t colliders need to have a rigidbody to register collisions?

        1. Valentin Simonov

          December 24, 2015 at 9:37 am / 

          Right, dynamic 2D colliders must be children of a Rigidbody2D. And if you move objects with 2D colliders make sure that you move the objects with Rigidbody2D components and not colliders inside Ribidbody2D themselves. If you move a collider manually Box2D has to destroy it and create again every time since there’s no way to move colliders (or fixtures as they are called) in Box2D. This will give you a very noticeable overhead in Profiler if done every frame.

Comments are closed.