Author Topic: Ways to optimize a grid of cards utilizing a pool  (Read 6520 times)

Aurigan

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 21
    • View Profile
Ways to optimize a grid of cards utilizing a pool
« on: August 31, 2016, 12:36:40 AM »
Hi all, I currently have a game where there are several scrollviews, each of which is a panel, that contain 'cards'. Each card has ~40widgets on it, each scrollview might have 20+ cards on it.

These cards can be created and destroyed rapidly (several a second) so I've been using a pooling system whereby cards removed from the scrollview are pushed into the pool and when needed pulled back out and reset with new spites / label contents etc.

This system is working well but, in searching for further optimizations, I discovered that setting the card gameobject active/inactive as it came from / went back to the pool was causing a heavy CPU penalty caused by all the UIWidget OnEnable() calls. A lot of those on drilling down seem to end in hundreds or thousands of UIWidget.PanelCompareFunc() calls.

If on the other hand I keep the gameobjects active while in the pool I end up with massively more calls to UIRect updates etc. which then offsets the benefits of not having to re-enable.

Is there an easier way to stash a collection of NGUI widgets in such a way that un-stashing it is performant?

I saw in another thread the mention that it might be more efficient to use lots of panels (one per card) instead of one panel with all the cards on. Is that the case?

Assuming it is, what's the best way to set up that per-card panel? Should it use clipping? Is there any benefit to then animating the panel around instead of the single child?

Thanks!

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Ways to optimize a grid of cards utilizing a pool
« Reply #1 on: September 03, 2016, 01:43:08 AM »
Just disable the widget component -- that would be the easiest thing.

Moving panels is essentially free. Moving widgets is expensive as it causes draw buffers to be rebuilt. If each card has 40 widgets, and you move cards, each card should have a panel of its own.

Aurigan

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 21
    • View Profile
Re: Ways to optimize a grid of cards utilizing a pool
« Reply #2 on: September 20, 2016, 05:21:58 PM »
I guess I was really asking two questions - how to create a performant pool of objects and best practices for dealing with collections of moving components.

The issue with disabling the widget is that on re-enabling hundreds to thousands of UIWidget.PanelCompareFunc() calls are generated.

For the second question it sounds like I could benefit from moving my cards to a panel for each, thanks for the tip.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Ways to optimize a grid of cards utilizing a pool
« Reply #3 on: September 21, 2016, 06:56:30 AM »
PanelCompareFunc is just a sort function. It simply compares integers inside (depth values). The less widgets you have per panel, the fewer calls to PanelCompareFunc you will have. You can't avoid having those calls entirely, but the cost of doing so is minimal, so not sure why you are even bringing it up. All I can think of is maybe you did a deep profile, which would be a mistake to base your findings on. Deep profile adds a static amount of overhead to every function call, no matter how small the function's execution time may be. So 1 call to a function that takes 1 ms to execute may add 0.01 ms, making it 1.01 ms in deep profile. Now 1000 calls to a function that takes 0.0001 ms to execute would normally be 0.0001 * 1000 = 0.1 ms, but in deep profile that becomes (0.0001 + 0.01) * 1000 = 10.1 ms, leading you to think that there is a problem when in fact there isn't.

Aurigan

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 21
    • View Profile
Re: Ways to optimize a grid of cards utilizing a pool
« Reply #4 on: November 04, 2016, 05:59:41 PM »
PanelCompareFunc is just a sort function. It simply compares integers inside (depth values). The less widgets you have per panel, the fewer calls to PanelCompareFunc you will have. You can't avoid having those calls entirely, but the cost of doing so is minimal, so not sure why you are even bringing it up. All I can think of is maybe you did a deep profile, which would be a mistake to base your findings on. Deep profile adds a static amount of overhead to every function call, no matter how small the function's execution time may be. So 1 call to a function that takes 1 ms to execute may add 0.01 ms, making it 1.01 ms in deep profile. Now 1000 calls to a function that takes 0.0001 ms to execute would normally be 0.0001 * 1000 = 0.1 ms, but in deep profile that becomes (0.0001 + 0.01) * 1000 = 10.1 ms, leading you to think that there is a problem when in fact there isn't.

Yes I was using dee profile, had no idea about the profiler adding overhead to each call ... that drastically changes things! Thanks for the heads-up!