Author Topic: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate  (Read 18088 times)

MakeCodeNow

  • Guest
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #15 on: November 20, 2013, 07:03:55 PM »
I just wanted to chime in to say that I'm seeing very similar behavior in one of my UIs. In my case, doing a cascaded fade of items in a list causes a series of panel rebuilds, each of which takes on the order or 30-40ms on a high end phone. While they are not constant, I would hardly describe them as "rare" either. To make matters worse, I'm not using any atlases (dynamic data), so all of those rebuilds don't make things any more efficient.

I've been able to mitigate the issue by avoiding cases that cause panel rebuilds (like never setting widget alpha below 0.001), but they are only so effective. It would be ideal to not have such huge rebuild times, or to have some control over what sorts of changes cause rebuilds. Reducing draw calls is primarily a way to save CPU time, and it seems counterproductive to spend 10s of ms of CPU time just to save a ms or two.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #16 on: November 20, 2013, 07:27:29 PM »
I've done a solid optimization pass on 3.0.6 that greatly reduced memory allocations (and thus GC collection spikes). I'd suggest trying it again with 3.0.6.

MakeCodeNow

  • Guest
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #17 on: November 22, 2013, 02:10:40 PM »
Quote
I've done a solid optimization pass on 3.0.6 that greatly reduced memory allocations (and thus GC collection spikes).

I like all of these words :) I'll take 3.06 for a spin when I have a moment and post my performance observations here.

bluescrn

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #18 on: November 27, 2013, 01:30:41 PM »
We've recently moved to 3.0.5, from a fairly old 2.x build, and have been getting some fairly large performance spikes during gameplay that weren't happening before, when updating some fairly simple HUD elements (in a scene with a fair bit of other UI loaded but turned off, but a relatively simple HUD, with no panel containing more than a few widgets)

In our case, it looks like it's related to instantiating widgets - I'm instantiating a number of small HUD popups (e.g. floating score text, health bars). This is already done through an object pooling system, but the objects are stored outside of the target panel (and become children of a PoolManager object instead)

When these objects are spawned, UIPanel.mFullRebuild gets set. And it looks like this is now a global flag (for the whole UI), rather than a flag per panel (as in 2.x)? - and in our case, it results in a much more expensive UIPanel.LateUpdate than before (a few millisecs on the Mac build, significantly more on a mobile device)

I suspect/hope that I'll be able to fix these cases by pre-allocating and pooling the spawned objects within the destination panel, avoiding any instantiation/re-parenting, but I've not had a chance to try that out yet.
« Last Edit: November 28, 2013, 10:45:13 AM by bluescrn »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #19 on: November 27, 2013, 04:38:20 PM »
3.0.6 is the release that had performance optimizations. 3.0.1-3.0.5 had none.

bluescrn

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #20 on: November 28, 2013, 07:24:26 AM »
I've now updated to 3.0.6.  It may have made the spikes smaller, but they're still big spikes that weren't there with 2.x.

It looks like I'd misunderstood the problem yesterday. It's not just instantiation - With 3.x, it seems that enabling/disabling a widget has become a very expensive operation?

With 3.0.6, on a Nexus 7, I'm getting 7-9ms spikes whenever I update small elements on our HUD. (This happens every time a shot is fired, so it's quite a big deal)

When enabling widgets, UIPanel.InsertWidget is setting mRebuild flag, causing an expensive full update. (Yes, only if it needs a new draw call, but in practice that happens most of the time in our scene)

With 2.x, NGUI had never been a real performance concern in-game. Small updates to small/simple panels seemed inexpensive. We certainly weren't seeing spikes like this. Panels were independent, and updating a small panel was fast. But now, it's forced to update all visible panels/widgets, and grouping things into panels doesn't help keep performance managable.

I can't see any obvious way around it. It's looking like the improvements to sorting in 3.x came with a very high price for some scenes?

Is there anything that we can do to regain some performance, other than reverting back to a 2.x version of NGUI?... 

(I'm starting to wonder whether I could modify NGUI 3.x myself to use per-panel widget lists/updates/draw calls, to keep panel updates as independent as possible without reverting to an old version)

« Last Edit: November 28, 2013, 12:34:17 PM by bluescrn »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #21 on: November 28, 2013, 02:54:33 PM »
A cheap way to get around the list rebuilding would be to ensure that there is already a widget active using the same atlas and within the same draw call. When a widget gets activated it will check to see if it's possible to re-use an existing draw call or not. If not, then it's an expensive operation and will require NGUI to re-think what happens to the draw order and draw calls. If it is possible, then it's cheap and behaves exactly as it did in 2.7.

Make sure your panels are using unique depth values. Panels sharing depth values is going to cause performance issues.

afroman

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 14
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #22 on: November 28, 2013, 04:47:38 PM »
Yeah I've noticed the spike as well. The spike is actually so bad that it crashes the game on some devices. it has however improved slightly since upgrading to 3.0.6.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #23 on: November 28, 2013, 05:13:14 PM »
If you still get large spikes like that in NGUI 3.0.6f6, then I'd appreciate some example project to go with so I can investigate further. And as I mentioned, make sure that all your panels have unique depth values.

bluescrn

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #24 on: December 02, 2013, 10:29:26 AM »
A cheap way to get around the list rebuilding would be to ensure that there is already a widget active using the same atlas and within the same draw call.

I briefly experimented with that sort of solution, but it wasn't working out too well - it avoided the spike when enabling the widget, but removing it still caused a spike, due to this:

  1. if (depth == w.drawCall.depthStart || depth == w.drawCall.depthEnd) mRebuild = true;
  2.  
         

And there were lots of things in our HUD scene still triggering the expensive UIPanel.mFullRebuild (for example, enabling/disabling panels for pop-up HUD elements - less frequent events, but still an undesirable performance spike)

Our GUI layouts are not ideal/optimized, there can be quite a lot of draw calls. It's mostly just two fonts and a HUD atlas, but split into a number of panels, and layered up in a way that doesn't batch amazingly well. But they're split up in such a way that no panel contains more than a few widgets, so a single-panel update should be a cheap operation. But with 3.0.x, panels are not independent, and it's easy to cause a rebuild of the entire HUD.

I've spent some time now modifying the internals of 3.0.6f6 fairly significantly (mostly UIPanel/UIDrawCall) to make panels independent again:

- mFullRebuild is per-panel
- Widget lists are per-panel
- DrawCall lists are per-panel
- Panel depth directly controls the render queue of the first draw call in the panel

So nothing will force a rebuild of all panels, at worst there'll be a single-panel update (and minor changes will still only update the single draw call). It seems to be working fairly well so far...

There's a definite trade-off between optimizing draw calls and optimizing update speeds. If you have a complex UI down to one draw call, any small change to it will mean an expensive rebuild of that draw call.

If things are split into more independent panels/draw calls, updates are likely to be less expensive. And in our case, a few more draw calls is a fairly smalls sacrifice to avoid big performance spikes.
« Last Edit: December 02, 2013, 10:39:02 AM by bluescrn »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #25 on: December 03, 2013, 10:00:50 AM »
You know.. thinking about it, if I enforce unique panel depths there is no reason not to have everything be done on a per-panel basis. The whole "common list" deal was necessary because of panels that didn't have unique depths. More for backwards compatibility than anything else. I'll give it some thought after the next update is out.

zincoontrin

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 6
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #26 on: December 09, 2013, 06:20:50 AM »
This is resulting in spikes for us too, 7-10 ms in a iPhone 5.

We don't see any way of not firing a mRebuild when enabling/disabling components. How are we supposed to hide/unhide components without triggering a full rebuild? I think that panels should be independent, a widget in a panel which has a different depth than other panel should not fire a full rebuild. Panels not being able to share their depth seems the right thing to me.

We are still looking for a solution. Bluescrn, would it be asking too much sharing your code modification?

Thanks

Ferazel

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 2
  • Posts: 150
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #27 on: December 09, 2013, 12:07:04 PM »
This is also probably related to the optimization request that I had requested in regards to improving performance with multiple UIPanels. (http://www.tasharen.com/forum/index.php?topic=7014.0) Even iterating through a list of 1000 widgets every frame for 90 panels had a huge impact on performance for us. Granted, 90 panels is a bit excessive, but I don't think NGUI should be iterating through the entire list of UIWidgets for every active panel (1000 x 90 = 90,000 iterations per frame). Even though there are performance checks, there is still work being done every iteration ([] operator and comparison checks). If the widgets were parented to specific panels this could be prevented. I look forward to this optimization.

bluescrn

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 9
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #28 on: December 09, 2013, 06:55:34 PM »
This is resulting in spikes for us too, 7-10 ms in a iPhone 5.

We don't see any way of not firing a mRebuild when enabling/disabling components. How are we supposed to hide/unhide components without triggering a full rebuild? I think that panels should be independent, a widget in a panel which has a different depth than other panel should not fire a full rebuild. Panels not being able to share their depth seems the right thing to me.

We are still looking for a solution. Bluescrn, would it be asking too much sharing your code modification?

Thanks

To be honest, I'd rather that we try to convince ArenMook that bringing back independent panel updates is essential, as these unavoidable full rebuilds are causing severe performance issues in real-world mobile projects. It's a serious drop in performance over 2.x, especially if you're trying to use NGUI for highly-dynamic in-game HUD elements.

My modifications are fairly significant, not particularly pretty, and spread across a number of files. And they're not perfect. Although it's working fairly well in our project, I've got at least one or two tricky bugs still to deal with (draw calls disappearing in the editor after recompiling scripts). I've also only got them working with 3.0.6f6, which is already somewhat out-of-date. But 3.0.7 seems to be a fairly large update, so merging may be tricky.

Not yet sure whether we'll do that for our project, or maybe just try to fix up 3.0.6 by bringing in the most critical fixes from later versions (for example, the slow font/atlas selectors, which are now fixed in 3.0.7)

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
« Reply #29 on: December 10, 2013, 01:07:58 AM »
There is no need to convince me, you already have. I already said I'll change it soon. It won't be back to 2.7 days, but I will make it so that widget changes only affect their own panel. :)