Why is OnGUI called significantly more than Update and FixedUpdate?

Introduction:

I think it’s well known amongst the Unity community that OnGUI has very bad performance when making games, especially for mobile platforms.

In my personal experience it seems to be the highest CPU drain in my current project while running mobile profiling.

(Profiles taken july 17th)

I ran some profiling on my project back in July and found that GUI.repaint was the highest CPU drain on my PC at 3%.

However I’m much more concerned about the OnGUI performance for mobile platforms. And on my Samsung Galaxy Nexus the profiler break down was like this on average:

Camera.Render = 44%
GUI.Repaint = 17% (this was biggest one on PC at like 3%)
Physics.Simulate = 15%
MeshSkinning.Update = 6%

Camera render being so high is sort of to be expected since we are trying to really push the limits and innovate as much as possible for what newer devices are capable of. But GUI.Repaint at 17% the seconds biggest CPU drain? This seems unacceptable to me.

So OnGUI is either the highest CPU Drain or the second highest CPU drain on both PC and my phone last time I checked.

So I’ve been meaning to investigate this a little bit more since the Unity documentation always seems to be completely void of any useful information I’m wondering about. Finally got around to running a few tests today.

The Test:

All tests will be run in my current game project in the exact same location and camera angle where you start the first level. This area has a large smoke particle effect for the crash site, and I also added 15 armor pieces to the camera view which all have particle systems, so this test should be a little more stressful for mobile platforms.

Create 3 int variables to track how many times OnGUI, Update, and FixedUpdate are called by incrementing the individual counters for each of those function calls. Counters will be displayed in OnGUI.

Will be testing in the Unity Editor, PC, and 2 Android devices.

Each test will attempt to accurately measure the number of OnGUI calls in relation to the Update and FixedUpdate calls. Running each test twice for each platform and taking a screenshot when the OnGUI counter reaches 1000. Then converting all the counters to what they would be if OnGUI was exactly 1000 in the screenshot (hard to take screenshot exactly right since OnGUI is called an insane amount of times per second). Averaging results of the 2 tests per platform or device.

Will be running majority of tests with Application.framerate set to 30 to mimic a mobile build. Also doing a round of tests with Application.framerate of 10000 for PC, and Unity Editor. Using default Unity settings for FixedUpdate. Fixed Timestep = 0.02 and Time Scale = 1 (50 FixedUpdate calls per second).

Test Results:

Unity Editor with PC settings:

Test 1

  • Target Frame Rate = 30
  • Actual Frame Rate = 30
  • OnGUI = 1000
  • Update = 493
  • FixedUpdate = 816
  • Result = 61 OnGUI calls per second

Test 2

  • Target Frame Rate = 10,000
  • Actual Frame Rate = 304
  • OnGUI = 1000
  • Update = 499
  • FixedUpdate = 82
  • Result = 610 OnGUI calls per second

PC Build:

Test 1

  • Target Frame Rate = 30
  • Actual Frame Rate = 30
  • OnGUI = 1000
  • Update = 494
  • FixedUpdate = 818
  • Result = 61 OnGUI calls per second

Test 2

  • Target Frame Rate = 10,000
  • Actual Frame Rate = 950
  • OnGUI = 1000
  • Update = 494
  • FixedUpdate = 26
  • Result = 1923 OnGUI calls per second (had to take screenshots @ 10,000 OnGUI and convert values since so fast)

ANDROID TEST (Samsung Galaxy S4)

Test 1

  • Target Frame Rate = 30
  • Actual Frame Rate = 29
  • OnGUI = 1000
  • Update = 484
  • FixedUpdate = 842
  • Result = 59 OnGUI calls per second

ANDROID TEST (Samsung Galaxy Nexus)

Test 1

  • Target Frame Rate = 30
  • Actual Frame Rate = 26
  • OnGUI = 1000
  • Update = 488
  • FixedUpdate = 922
  • Result = 54 OnGUI calls per second

One final test to see what happens when adding the OnGUI counter to all the enemies in one of my scenes… (all previous test are just one script’s calls).

Final PC Tests:

Test 1

  • Target Frame Rate = 30
  • Actual Frame Rate = 30
  • OnGUI = 1000
  • Update = 8
  • FixedUpdate = 13
  • Result = 3943 OnGUI calls per second (had to take screenshots @ 100,000 OnGUI and convert values since so fast)

Test 2

  • Target Frame Rate = 10,000
  • Actual Frame Rate = 894
  • OnGUI = 1000
  • Update = 9
  • FixedUpdate = .48
  • Result = 105,144 OnGUI calls per second (had to take screenshots @ 1,000,000 OnGUI and convert values since so fast)**

Test 3 (same as Test 2 except adding OnGUI counter to my biggest OnGUI script in scene)

  • Target Frame Rate = 10,000
  • Actual Frame Rate = 902
  • OnGUI = 1000
  • Update = 8
  • FixedUpdate = .46
  • Result = 107,691 OnGUI calls per second (had to take screenshots @ 1,000,000 OnGUI and convert values since so fast)

Conclusion:

So it seems that OnGUI is called significantly more than either Update or FixedUpdate in all scenarios, even when only incrementing the OnGUI count on 1 single script.

The lowest OnGUI calls per second I was able to achieve was 54 with the Samsung Galaxy Nexus aiming for 30 frames per second. This still was slightly over 2 OnGUI calls for every Update.

When changing the target frame rate from 30 to 10,000 the results become much worst. With only one OnGUI script the PC recorded an astounding 1923 OnGUI calls per second. This was also over twice the amount of Update calls, and over 38 calls per FixedUpdate.

When adding the OnGUI counter to increment on the original script in addition to all the enemies in one of my scenes the results became quite frightening even at 30 FPS. 3949 OnGUI calls even at a measly 30 FPS. That is 125 calls per Update frame, and 77 calls per FixedUpdate.

When removing the FPS limit of 30 and letting the PC really fly OnGUI becomes total beast mode. In my final test while adding the OnGUI increment to one additional very large OnGUI script in my scene it recorded a ridiculous 107,691 OnGUI calls per second. Once again 125 calls per Update but a horrendous 2174 calls per Fixed Update.

Final Thoughts:

It is now clear to me why I’ve seen so many people warning others to never use OnGUI. If it is allowed even slight room to be free things can get extremely ugly.

It is unclear to me why OnGUI is called over 2 times as much as Update even in my best scenario.

It seems strange that OnGUI is called so many times when it seems like it should be called in sync with Update ideally. What is the point of it updating faster than the frame rate?
When using it on multiple enemies throughout a scene for things like floating combat text and their health bars it becomes quite ridiculous how many times it is called. I have seen suggestions to disable Game Objects to avoid OnGUI if they are out of range. That makes a whole lot of sense when I’m seeing 125 OnGUI calls per Update even at 30 FPS.

The scary thing is that I didn’t even add the OnGUI counter to many other objects in my scenes that include it! Many of my items like health potions include OnGUI for floating text when you pick it up. So the true OnGUI calls per Update and FixedUpdate are even worse than this report.

After looking at all this data it is no surprise that OnGUI is the biggest CPU hog on PC, and takes up over 17% on the Samsung Galaxy Nexus. That profiler test was taken in July so it’s hard to say how high it is now with many optimizations but also many additions to the project.

Even though OnGUI looks to be horribly inefficient compared to Update and FixedUpdate if used carefully and in moderation it seems that it is useable for even mobile devices.

It seems the people saying it was impossible to use OnGUI effectively probably did not do things to limit the frame rate to 30-60. I would also strongly advise people to use very efficient logic in OnGUI. For example if you are using a for loop in OnGUI you should be extra careful to make sure it only runs when absolutely necessary like once per user action not every OnGUI call. I know this is programming 101 but I’ve seen people struggling with questions while doing stuff like for loops every OnGUI call. Any inefficient code will be greatly multiplied in OnGUI due to it being called so many more times than Update or FixedUpdate!

The majority of the OnGUI logic should be preset you should have variables for all the positions, sizes, etc. Do not calculate these in OnGUI!

OnGUI is definitely an ugly beast of a performance hog, but if used carefully it is very convenient to set up certain displays. Really hoping the new GUI update in future Unity versions will greatly improve the performance though. It’s quite shocking how slow OnGUI is currently.

Maybe my GUI crashcourse will shed some light into your confusion?

The main problem with the GUI system, on mobile devices, is that each GUI element might have 0 to 3 independent drawcalls (3 only if you use a style with background image and a GUIContent with text and image). A normal Label has one draw call a usual Button has 2 (text and background image).

You shouldn’t judge OnGUI on the times it’s called. In the layout event the controls just doing some calculations. All controls from the GUI class completely ignore the layout event, so when they are called they just early-exit right at the top.

On mobile devices drawcalls are the real problem. Each drawcall is a seperate “command” sent to the GPU. That mainly drains CPU power. That’s why it’s better to havethings with more vertices / triangles and just one drawcall for the whole thing instead of hundreds of single drawcalls.

NGUI is a framework which builds a mesh out of all “widgets” in a panel and only needs one drawcall. Btw: afaik the person that made NGUI is curently working on the new GUI system of Unity, so hopefully we get some sort of hybrid system which is as flexible as OnGUI and as performant as NGUI.

ps: Can you tell us how many GUI elements you actually draw on screen? I’ve created a quite complex debugging system for mobile using the Unity GUI system and it doesn’t preform that bad. You can also check the drawcalls in the “stats window” in Unity, try disabling the script with GUI stuff at runtime and see how much the drawcalls change.

“So what do developers use then for that kind of stuff in Unity projects?”

Hey Ryan, for “sprites” in Unity, many teams use 2DToolkit. Just get it from the asset store. (It’s a shame to recommend some particular asset so often but, in practice, you can’t use Unity without it, or a competitor product.)

It’s basically impossible in practice to do a unity project without some “sprite” solution. So just get 2dToolkit or one of its competitors.

(Note that, indeed, next yr Unity is including their own “unity 2d” to handle sprites easily - presumably this will very much annoy the 2DToolkit guys and the other package makers like that!!)

By the way by “sprites” I simply mean when you have a flat plane (at worst you could just choose “make plane”) with an image (ie, a texture) on it.

You could say, it’s a 2.5D element – meaning you’re using a 3D thing (it’s really a flat plane, that just happens to be oriented towards a camera) as a 2D thing.

Note that sprites have a broad range of uses. of course, if you’re literally making a “2D” game (imagine mario, a sideways scroller arcade game) - then it’s not really 2D, it’s literally a 3D world but it just happens to look like 2D. So when you look over the shoulder of a developer making a 2D game, it’s actually - in full 3D - all these flat “sprites” in 3D, it just happens to look like 2D from the camera point of view.

(I have no idea what you do or don’t know, so I’m explaining all this.)

Again note that even in totally 3D games (eg, grand thefy auto etc) you will inevitably need 2d “sprites” for some reason or another (eg, for alerts, things floating in space, whatever).

So the first thing is, no matter what you will have 2DToolkit (or similar) in your project.

Now - the horrific question of how to show type on the screen. The one and only easy way to do this in practice that solves all problems:

explained at length in my comment there (with the two pictures)

For the simplest possible type needs (say during development, you need to bring up a value on the screen) to the most tricky “UI” uses of typography … that pipeline is by far the simplest and only way to do it.

To change the text seen, the code is just like “thing.text = “3.71”; thing.commit();” and that’s it.

[16309-screen+shot+2013-10-09+at+10.18.00.png|16309]

to put one in the scene you just click “add new text mesh” and you type in what you want it to say. You can have any typeface you want (see explanation in the link above).

So we have established:

(a) you have to have “sprites” (flat images) in all games. no matter what, you’ll have to have a sprite solutin on hand.

(b) inevitably you will use 2dtoolkit (or some competitor) to do this. (I suppose you could spend a year programming your own convenience routines to make using sprites easy.)

(c) for the critical question of typography in unity, the pipeline i show in the link above is the only working answer we have ever found

(d) and critically … everything in unity should be “2.5D”, anything that breaks that paradigm is crap.

Now you want to know about doing “UI” which is a sort of conceptual NON 3D layer “touching the viewer”

So the answer is trivial - you use your 2.5D workflow (ie very likely literally 2dtoolkit) and you simply make that a layer near the camera! (Or use a second camera if you prefer, just sit it to one side.)

Conveniently, the 2dtoolkit guys include a complete “Buttons” script and a complete “UI” script which gives you all functionality of these paradigms. (They are only short scripts - rather making a mockery of the whole “gui industry” if you ask me - I personally don’t use 'em coz we have our own buttons system (ie, oe or two short scripts) and I always feel UI is beneath a Real games programmer, who should spend his or her time making explosions, so I just roll my own “ui” as the need arises!)

The absolutely critical philosophical point:

If you make your UI using sprites then you are still in the 3D paradigm (ie, it’s “2.5D” if you wil – “2.5D” means you are actually using 3D elements but it just happens to look flat to the end-user.)

Whereas unity’s GUI system is a pretend 2D system, so it will never give any happiness in this universe. (Eric kindly explained to me the other day, if I did not misunderstand him, that the actual Unity editor is made using unity’s GUI system - so, that’s exactly the perfect job for it.)

Now as well as Unity’s GUI you have “better than unity GUI” products notably NGUI and EZGUI. These are absolutely admirable products and I’m sure I’ll meet the makers one day, and they are technically superb and very popular - you should definitely pay money for both to check them out. But for me they are utter non-starters because (“no, really”) they are big complicated APIs you have to learn and for me that’s (a) not possible as I’m not able to learn anything and (b) it’s just beyond human belief anyone would want to learn, become a specialist, in a system to make UI. (Because, you simply do it in “2.5D” with sprites … ie, … utterly exactly as you do anything else in Unity.) Thus, let’s say you are really good at making things move around in Unity - I mean tanks, soldiers, and the like. Thus, automatically, with no further effort, you are really good at making things (that happen to be flat sprites) move around in Unity; so indeed you can instantly program any and all UI (ie “things which happen to be flat things, which move around, just like the more normal tanks etc”)

I hope these thoughts are of interest! Cheers!

Hi,

Don’t know for the latest version, but before the new GUI there were some issues due to the multiple calls to OnGUI. There were a call for the creation of elements, another for the layout and finaly a repaint one used to draw the final result. I don’t exactly remember the exact flow but it’s something like that, it was leading me to issues so I had to check wich event called the OnGUI to change what kind of code must be executed.

It’s “one call per event”

as said in the scripting reference. Reduce events, reduce calls.

(I like GUITextures. They are fast and responsive.)