Thanks to the handy dandy new profiler, I can see that our GUI code is taking up a lot of time - about 16ms per frame...ouch. I thought I must have buried some logic in there that shouldn't be there, but all of the functions that are taking up the vast majority of the time are internal ones that I do not call directly. Obviously I call them indirectly though, so I'd would like some advice on what I can/should be doing to reduce the time taken in these functions: GUI.Repaint->GUIUtility.EndGUI() GUI.Repaint->GUIUtility.BeginGUI() GUI.ProcessEvents->GUIUtility.EndGUI() Also, I have noticed there are spikes every 4-5 frames in: GUI.Repaint->GUIUtility.EndGUI->GC.Collect What can I do differently in my code to reduce those?
Put another way: What do these functions do? GUI.Repaint->GUIUtility.EndGUI() GUI.Repaint->GUIUtility.BeginGUI() GUI.ProcessEvents->GUIUtility.EndGUI()
Wow 16 ms is really a lot. But you should still remember that the computer testing has every thing to do with the problem. So are you testing on your lowest denominator? or on your high end work station :/ Is it possible to get a screenshot? It could be that you are just using a lot of gui.. All that said, I have noticed that GUILayout is quite expensive to use. Compared to screen relative GUI with out the use of BeginGroup. I personally always prototype with GUILayout and then implement the final result with clean GUI when possible. About the GC collect, you can remove a lot of that by caching styles, rects and other mics classes. Of course it's not always possible, but it makes the garbage collection faster. Hope I helped in some way, felt like I just rambled, :S ..
Thanks for the reply, it does help a bit. I assume by "cache the styles" you mean maintain a reference to them between calls so they are not created and destroyed? I guess in general anything created in OnGUI (including Rects?) would contribute to that, but I'm seeing 3-4ms spikes, so I thought it might be something else. I've attached a couple shots of the profiler. The first is with an "average" frame, and the second with a spike.
Could you elaborate a bit? If I move all the OnGUI code to a single/fewer OnGUIs, but it is still the same amount of code, what is going on that will make that so dramatically faster? i.e. why are 2 calls with 1/2x the code so much slower than 1 with 2x the code? (I'm assuming since we're talking about milliseconds here that the overhead of a single function call is negligible).
basically each ongui function is called multiple times per frame. once for rendering and x times for all x events that might or might not happen
I understand, but even the overhead of 200 function calls wouldn't add up to 18 milliseconds. You may be right that there are too many, but what else is going on that makes it so much different?
I appreciate you taking the time to respond. I meant the overhead of the call, not what happens in the call. I want to make sure I understand what you're saying: OnGUI() A OnGUI() B ... OnGUI() Z should be: OnGUI() A B ... Z And will save something on the order of milliseconds? Doesn't that seem unintuitive? What is happening in GUIUtility.EndGUI (which I do not call directly and is undocumented) that grows with apparently non-linear complexity in the number of OnGUI functions? Or is it something else? I'm just trying to understand before I embark on what amounts to a major overhaul.
no idea what happens in the endgui directly but I would expect it to be the step that assembles all the meshes for the ui (due to the vbo mention) and event handling ... generally you should potentially not combine the ui but just disable all you don't need at the time (with that I mean the whole game object / component, not just have a switch in the functino)
Cache Cull! Anything that doesn't change or doesn't change often should be member variables, and anything that doesn't render at all (be it a message box or an item in a list that isnt on-screen) should be culled and ignored by OnGUI.
A note about gc, it is drastically reduced when deep profiler is on. Any one know why? The overhead does not add up to that many ms. Close rendering and memory windows and enable deep profiler. This should reveal the evil culprit. Besides what looks like a extensive use of GUILayout.
I, too, have noticed that OnGUI is far more expensive than it should be. ~30 GUI.Box's drops my framerate by 100 fps, and a single GUIArea and GUILayout with about 10 items drops it another 50. I'm fairly experienced with Unity GUI and I've cached and culled a lot, but it's still far too intensive... To combat this, I've developed my own system to detect button clicks and just use DrawTexture a lot, but I need the GUILayout for the automatic resizing. Anyone else experiencing precipitous speed drops of this nature? BTW, I have all my code in a single OnGUI loop. Perhaps more loops would initiate multi-threading? I'm not an expert on how that works, so I'm not sure. -CJ
Unity code will never run on multiple threads even if you had half a million loops and a peta core processor. The whole unity environment runs on a single thread (scripting, gui etc). The only things that run on own threads are potentially physics (unsure if PhysX in that old version was multithreaded) and your own threads naturally. And yes it drains a lot of performance, its commonly the major cpu time eater in my projects if I use it. Luckily I don't use it that commonly, I use GUIX which I have owned since the day of its release and I definitely don't regret it in any way given the performance GUIX has (significantly higher) in the same situations as the normal gui, it becomes clear that it is related to the fact that GUIX has per object even callbacks instead of doing bruteforce "event pumping" (as far as I understand you have 1 call to each ongui for each event generated ...)
Well that's not promising... Good thing it's only on mouse over that the GUILayout call kicks in. GUIX, hmm? I'll have to look into it.
Do a search on GUIManager in this forum. You can create GUI's with it with a low performance impact. Originally it was created for the iphone but it works with the non iphone-Unity too
Hi Molix, have you found any reason for GUI.Repaint eating the CPU time? We have exactly the same problem and thus interested, if there are anything we can do about it... GUIX is only a C# wrapper to the normal Unity GUI so I don't think it can be more efficient than using the normal GUI directly.. BR, Juha
Can someone elaborate on the GUIX performance gain? Too bad I have no option to test it myself (GUIX trial run out).
I've added a request for a replacement / fix for OnGUI GC spikes on the Feedback site: http://feedback.unity3d.com/forums/15792-unity/suggestions/1604963-gc-spikes-caused-by-ongui