Search Unity

GUI... That hidden bastard

Discussion in 'Scripting' started by LightStriker, Jul 16, 2014.

  1. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    I'm in the process of optimization for a game. Targeting device like iPhone 4S isn't that easy. It's a war against wasted milliseconds and reducing garbage generation to a minimum.

    Am I not surprised when today I found out our biggest waste of CPU cycles and our biggest garbage generator comes from GUI.Repaint... While we have no GUI on screen! (We are using Scaleform)

    What I discovered is stunning... GUI.Repaint takes time - lot of it - and generate garbage for every single OnGUI method in existence, EVEN if it doesn't draw anything. As example, we have debug class that when activated draw debug information. However, GUI.Repaint still take time and garbage even while the method is;

    Code (csharp):
    1. private void OnGUI()
    2. {
    3.     return;
    4. }
    Sure, someone would say that 0.5 ms - on PC - isn't that huge... But on iPhone, it can climbs up to 2 ms of waste CPU cycle for no reason. The 2Kb of garbage it generated every frame was triggering the GC way more often than I would have liked. Commenting out all our OnGUI solved the problem, GUI.Repaint takes no time anymore, but frankly, I would have expected Unity to be a bit more intelligent with that!

    Digging in the UnityEngine.DLL, I found out the garbage comes from the creation of GUILayoutGroup, which exists only for one frame and is recreated all the time.

    Stats;
    - 0.12 ms of CPU per empty OnGUI in existence
    - 336 bytes of garbage per empty OnGUI per frame
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Yep. OnGUI() is known to be a huge performance hog on mobile. It's one of the big reasons for uGUI.

    If you have something like a debug output that may or may not show stuff in OnGUI, best practice for performance would be to put OnGUI() in a second MonoBehaviour, and disable that component when not needed.
     
  3. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    I just flagged all the OnGUI methods with #if UNITY_EDITOR || DEBUG

    Frankly, it's insane that an empty method would cost so much, and that Unity offers no way to prevent the garbage generation if you need that method but without the drawing part.
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Does useGUILayout = false have any effect on that?

    --Eric
     
  5. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Ah! A flag I didn't know.

    It does remove the garbage generated, and it reduces the waste CPU from 0.12 ms to 0.02 ms. Not perfect, but a lot better than I expected. One of those little things with almost no documentation, I guess.
     
  6. JFo

    JFo

    Joined:
    Dec 9, 2007
    Posts:
    217
    Something to remember when using that flag (a little "note" from GUI.Window doc):

    "if MonoBehaviour.useGUILayout is set to false then a call to GUI.Window will not have any effect, even though it is not a GUILayout function"

    Took one evening to figure this out before found the reason...
     
  7. shkar-noori

    shkar-noori

    Joined:
    Jun 10, 2013
    Posts:
    833
    so disabling useGUILayout will improve the performance of OnGUI ?
     
  8. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    If you are not using GUILayout or GUI.Window, it save about 0.11 ms of CPU per OnGUI call, and a ton of garbage generated.
     
    shkar-noori likes this.
  9. shkar-noori

    shkar-noori

    Joined:
    Jun 10, 2013
    Posts:
    833
    No I aint using any of them. thank you for the knowledge