Tasharen Entertainment Forum

Support => NGUI 3 Support => Topic started by: quickfingers on October 20, 2013, 06:25:18 AM

Title: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: quickfingers on October 20, 2013, 06:25:18 AM
getting some really severe performance spikes since using ngui 3.

(http://f.cl.ly/items/3p3v031F2I2A3g260a1W/Screen%20Shot%202013-10-20%20at%2012.45.46.png)

So far it seems the spikes appear when widgets colors fade in and out and/or when widgets are moved in an Update.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: ArenMook on October 20, 2013, 03:58:43 PM
What happens in your ScrollingTextArea object?
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: quickfingers on October 21, 2013, 04:45:06 AM
The panel which takes up all the frame time seems arbitrary...
If I disable the ScrollingTextArea panel then the next panel in the queue lags in the same way.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: quickfingers on October 22, 2013, 09:16:29 AM
I think it may have something to do with using dynamic fonts as testing another scene with only bitmap fonts and it seems fine.

I am also using Unity 4.3. beta so there may be issues with the gc
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: NaxIonz on October 22, 2013, 02:01:33 PM
Yeah, I noticed this as well. As soon as you let go of dragging something..... boom lag spike!

Some of our outsource testers on some old devices are saying our scrolling menu is almost unusable now :-(

I figured it was because we added some more widgets to that panel, so I told our producer that we needed to allocate time to re-write the panel to re-use widgets instead of having the actual widgets we need on it. (i.e. when widgets go off-screen we manually reposition them and re-set their data/layout, giving the illusion of a long scrolling list)
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: Nicki on October 22, 2013, 02:54:00 PM
It might be something that triggers when the momentum runs, which is only when you've released, but it isn't still yet. Internally on my team, we've made a cyclical wrapper for scroll lists and it increases performance quite a bit and also has the added bonus of having infinite elements in the list.

This is not something we're ready to release yet though, if we ever will be. If we get to a point where the higherups have no objections to it and we feel comfortable putting it out there, we'll post it in here or something.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: kurozael on October 22, 2013, 04:07:11 PM
I, too, have noticed bad performance after switching to NGUI 3.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: NaxIonz on October 22, 2013, 06:20:38 PM
It might be something that triggers when the momentum runs, which is only when you've released, but it isn't still yet. Internally on my team, we've made a cyclical wrapper for scroll lists and it increases performance quite a bit and also has the added bonus of having infinite elements in the list.

This is not something we're ready to release yet though, if we ever will be. If we get to a point where the higherups have no objections to it and we feel comfortable putting it out there, we'll post it in here or something.

Yeah, I've done infinite lists twice before in NGUI. Sadly, I no longer have access to the code :'(
Guess I get the fun of writing it again ^_^
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: NaxIonz on October 24, 2013, 09:09:03 AM
In testing this morning, even when we reduce the pages of widgets from 8 pages down to 3 (the minimum viable amount to implement infinite scrolling) there is still a noticeable hitch on release after dragging. This is even on a Note 2 device, which is pretty decent. When we compare it to our build that used NGUI 2.6.4, the dragging is very smooth with 7 pages of widgets. And in case you wondering, the widgets have the same complexity as they did before. No new sprites, text, gameObjects, particles, or any UIWidget of any sort has been added to them.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: NaxIonz on October 24, 2013, 09:58:03 AM
More digging and I found why there was the lag spike.
It was coming from all the draw calls being destroyed. And they were being destroyed because the UIPanel was being set to dirty, which was causing a full rebuild. The UIPanel was being set dirty because we had page indicators at the bottom of the screen that were turning on/off based on the page you were on. (Basically gameObjects with 3-4 sprites on them, and they look one way or the other based on which page # you are viewing).

So, setting gameObjects active/inactive is bad-bad-bad in NGUI 3.0.x, at least it seems that way.

I'm not sure why the reasoning behind RemoveFromPanel() in OnDisable() of a UIWidget. If I might just turn it back on later, why make the widget go through all the effort of figuring out which panel it is on?
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: ArenMook on October 24, 2013, 09:43:49 PM
If the widget in the middle of the draw process gets removed or inserted, this causes the whole list to require re-batching, which is a slow process. Reason for that is this: if you had 3 widgets, one using atlas A, another using atlas B, and last one using atlas A, disabling the 2nd widget will allow the first and last widget to get batched into a single draw call.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: blechowski on October 25, 2013, 01:24:49 AM
This is bad.

I rather have constant, but small performance drop than a short, but big performance hit.

It would be great if we got some control over what happens when widget is disabled or enabled.
The typical usecase is that I disable a widget and then enable it some time later. It would be great if the widget did not cause the re-batching nor geometry rebuilding.
I would expect the re-batching to happen whe I destroyed the widget or the widget was no longer a child of the Panel.

Another typical use case is changing of sprite on a widget from the same atlas without the need to rebuild geometry. As we all know the more we do preprocessing in the editor the less processing is needed when the game runs.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: NaxIonz on October 25, 2013, 01:13:18 PM
If the widget in the middle of the draw process gets removed or inserted, this causes the whole list to require re-batching, which is a slow process. Reason for that is this: if you had 3 widgets, one using atlas A, another using atlas B, and last one using atlas A, disabling the 2nd widget will allow the first and last widget to get batched into a single draw call.

Seems a little assumptive that draw calls are more important than latency. It also assumes that you have more than one atlas in the project/scene. Since our scene has just one atlas, we pay this price of rebuilding but gain no draw calls. I can write wrapper logic around this (in our team's local code) to prevent it, but I have a feeling we're not the only ones that are in this sort of scenario. We only have 4-7 UI draw calls at any given moment, so that stutter from rebuilding is significantly noticeable.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: blechowski on October 28, 2013, 04:22:47 AM
@ArenMook
Are there any plans to resolve this issue? Or should we try on our own?
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: ArenMook on October 29, 2013, 01:34:01 AM
In the near future? No plans. I address such things as I encounter them. I work based on priority, not urgency. For example: exceptions thrown when a label ends in [-] is a high priority task. Eliminating rare spikes when you enable / disable content is a very low priority task.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: MakeCodeNow 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.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: ArenMook 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.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: MakeCodeNow 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.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: bluescrn 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.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: ArenMook 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.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: bluescrn 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)

Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: ArenMook 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.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: afroman 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.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: ArenMook 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.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: bluescrn 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.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: ArenMook 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.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: zincoontrin 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
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: Ferazel 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.
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: bluescrn 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)
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: ArenMook 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. :)
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: oddurmagg on December 10, 2013, 08:47:55 AM
ArenMook: Do you know which release this might make it into ?
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: bluescrn on December 10, 2013, 09:41:21 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. :)

Cool, this sounds good :)

What's likely to be different/slower compared to 2.7? -  are you planning to keep the global widget list, or go back to widget lists per-panel?
Title: Re: Serious performance spikes with 3.0.2 and UIPanel.LateUpdate
Post by: ArenMook on December 10, 2013, 09:51:46 PM
Per-panel.

I made it global to make it backwards-compatible with the 2.7 ways of doing things, but now that most people have already gone up to 3.0, I can change it.