Author Topic: Shrugger! Unity!  (Read 151213 times)

Offline Shrugging Khan

  • Hero Member Mark III
  • *****
  • Posts: 1,217
  • Neinzul Y PzKpfw Tiger!
Re: Shrugger! Unity!
« Reply #315 on: September 15, 2015, 04:51:46 am »
Alright, we did some good stuff to performance. Turns out the main hog (apart from complicated mathematics. Hello, Orbital Mechanics!) was all the debugging we did, and how it was displayed in the interface. Debugging UI Windows and UI elements in general now update at much more reasonable occasions. Yay. Now, so much for the stuff that was obvious with the profiler.

Is there any way to have it display averages rather than per-frame data?
The beatings shall continue
until morale improves!

Offline keith.lamothe

  • Arcen Games Staff
  • Arcen Staff
  • Zenith Council Member Mark III
  • *****
  • Posts: 19,505
Re: Shrugger! Unity!
« Reply #316 on: September 15, 2015, 08:52:55 am »
If it just averaged in a generic sense the results would be pretty meaningless. There may be some averaging you can do yourself, by measuring a given section every frame for a few seconds and so on. But why would you want the averages? General speed-up is mostly a matter of seeing what hits it the hardest and chopping it down, rinse, repeat.
Have ideas or bug reports for one of our games? Mantis for Suggestions and Bug Reports. Thanks for helping to make our games better!

Offline Draco18s

  • Resident Velociraptor
  • Core Member Mark V
  • *****
  • Posts: 4,251
Re: Shrugger! Unity!
« Reply #317 on: September 15, 2015, 12:33:44 pm »
Alright, we did some good stuff to performance. Turns out the main hog (apart from complicated mathematics. Hello, Orbital Mechanics!) was all the debugging we did, and how it was displayed in the interface.

Oh yeah.  Debug.Log() is so ridiculously expensive its not even funny.

Offline keith.lamothe

  • Arcen Games Staff
  • Arcen Staff
  • Zenith Council Member Mark III
  • *****
  • Posts: 19,505
Re: Shrugger! Unity!
« Reply #318 on: September 15, 2015, 12:46:42 pm »
Generally you want any remotely-frequent debugging to not be on by default unless you're specifically hunting something down. We use F3 as the debug mode toggle for most of our common debugging info.
Have ideas or bug reports for one of our games? Mantis for Suggestions and Bug Reports. Thanks for helping to make our games better!

Offline Shrugging Khan

  • Hero Member Mark III
  • *****
  • Posts: 1,217
  • Neinzul Y PzKpfw Tiger!
Re: Shrugger! Unity!
« Reply #319 on: September 16, 2015, 03:32:17 am »
If it just averaged in a generic sense the results would be pretty meaningless. There may be some averaging you can do yourself, by measuring a given section every frame for a few seconds and so on. But why would you want the averages? General speed-up is mostly a matter of seeing what hits it the hardest and chopping it down, rinse, repeat.
I guess that's true.
Imagine some sighing here, please, as I adjust to the reality of not being able to solve all my problems at once  :(

Oh yeah.  Debug.Log() is so ridiculously expensive its not even funny.
Truth! But we threw most of those out a fair while ago and moved every non-critical debug logging to the ingame interface. The problem in this case was some string formatting the homebrew interface did - inserting line breaks into overly-long strings. I haven't yet figured out why that specifically took so long, but it led me to some old and performance-owwie faults in the UI that I managed to fix.

Generally you want any remotely-frequent debugging to not be on by default unless you're specifically hunting something down. We use F3 as the debug mode toggle for most of our common debugging info.
How does that toggle work, if I may ask? Does it disable logging at runtime, or from the editor?
The beatings shall continue
until morale improves!

Offline keith.lamothe

  • Arcen Games Staff
  • Arcen Staff
  • Zenith Council Member Mark III
  • *****
  • Posts: 19,505
Re: Shrugger! Unity!
« Reply #320 on: September 16, 2015, 08:58:11 am »
The problem in this case was some string formatting the homebrew interface did - inserting line breaks into overly-long strings. I haven't yet figured out why that specifically took so long, but it led me to some old and performance-owwie faults in the UI that I managed to fix.
strings are often a source of unexpected performance problems. Remember that strings are immutable, and that adding a 1-character string onto the end of a 1000-character string results in the allocation of another 1001-character string. Similarly, adding a 1-character ('\n') string into the middle of a 1000-character string does at least creates another 1001-character string, but it may actually also create an intermediate string that's 501 characters long (if you were putting the \n smack in the middle of the old string), depending on how you wrote it.

For situations where you're building a string out of a lot of pieces, StringBuilder is a good just-get-it-done class. If you're doing a _huge_ amount of string building (as we do when serializing data to disk), it's a good idea to write your own buffer class that wrappers a char[] or something like that, and carefully think through the allocations and how to avoid them (for instance, you don't have to use Int32.ToString(), the code for translating an int to a sequence of characters isn't all that complex and doesn't have to involve any heap allocation).

Though I think I've already mentioned the above and you're talking about string formatting, so perhaps there's something else going on that this doesn't cover. Do you mean actually using string.Format?

Quote from: Shrugging Khan
Generally you want any remotely-frequent debugging to not be on by default unless you're specifically hunting something down. We use F3 as the debug mode toggle for most of our common debugging info.
How does that toggle work, if I may ask? Does it disable logging at runtime, or from the editor?
It's just a bool that our code toggles when it detects F3, and that bool is checked a bunch of places in our code to see whether it should do whatever kind of debugging. Not all debugging is under that toggle, just the "diagnostic stuff we frequently want to be able to get at without having to recompile or even restart the app".
Have ideas or bug reports for one of our games? Mantis for Suggestions and Bug Reports. Thanks for helping to make our games better!

Offline Shrugging Khan

  • Hero Member Mark III
  • *****
  • Posts: 1,217
  • Neinzul Y PzKpfw Tiger!
Re: Shrugger! Unity!
« Reply #321 on: September 25, 2015, 07:35:06 am »
Alright, we've discovered that yes, we have a shit-ton of GC happening due to List.Contains().
Now that it's diagnosed, what can be done about it?  ???
The beatings shall continue
until morale improves!

Offline Draco18s

  • Resident Velociraptor
  • Core Member Mark V
  • *****
  • Posts: 4,251
Re: Shrugger! Unity!
« Reply #322 on: September 25, 2015, 09:14:06 am »
I'm not sure why that would require GC, and a little of googling around didn't provide any insight either.

Offline keith.lamothe

  • Arcen Games Staff
  • Arcen Staff
  • Zenith Council Member Mark III
  • *****
  • Posts: 19,505
Re: Shrugger! Unity!
« Reply #323 on: September 25, 2015, 09:29:40 am »
Now that it's diagnosed, what can be done about it?  ???
A variety of things. Which one is best depends on your situation.


1) Simply converting:
Code: [Select]
bool inTheList = someList.Contains(foo);
to:

Code: [Select]
bool inTheList = false;
for(int i = 0; i < someList.Count;i++)
{
  if(someList[i] == foo)
  {
    inTheList = true;
    break;
  }
}

(all this assuming that foo is a value type, NOT a reference type, and that someList is a List<foo>)

Will solve the problem for that particular call, but if you're doing it in a lot of places that's a lot of code expansion and is somewhat error prone, etc.


2) Avoiding having lists of value types is another approach, as often you can just have it be a list of reference types instead, but that's very specific to your codebase.


3) You could write your own non-generic collection for each value type you need to have a list of. This can be very simple, like:
Code: [Select]
public class ListOfInts : List<int>
{
    public new bool Contains( int Item )
    {
        for ( int i = 0; i < this.Count; i++ )
            if ( this[i] == Item )
                return true;
        return false;
    }
}
I haven't tested the memory performance of that approach, but I suspect it's basically the same as approach 1.
Have ideas or bug reports for one of our games? Mantis for Suggestions and Bug Reports. Thanks for helping to make our games better!

Offline Shrugging Khan

  • Hero Member Mark III
  • *****
  • Posts: 1,217
  • Neinzul Y PzKpfw Tiger!
Re: Shrugger! Unity!
« Reply #324 on: September 25, 2015, 09:40:38 am »
Thanks! I've already started working on approach 1, but I was unsure if it would even help. Will finish it immediately  :D

Converting everything to reference types isn't really something I want to do; too many problems at other ends of the thing.
Approach 3 might be worth doing if we end up running into a lot of these. Will keep it in mind.

Edit: Hello there! Using approach three for just one List type, I was able to speed things up by 20%, cut GC by 60%, and reduce the GC trouble caused by Contains() by...100%? Seriously? I'll be off to make non-generic List classes for EVERYTHING now!

Or is that a bad idea?  :o

Edit2: I don't suppose using the same approach for IndexOf() would work to the same effect?
« Last Edit: September 25, 2015, 10:03:00 am by Shrugging Khan »
The beatings shall continue
until morale improves!

Offline keith.lamothe

  • Arcen Games Staff
  • Arcen Staff
  • Zenith Council Member Mark III
  • *****
  • Posts: 19,505
Re: Shrugger! Unity!
« Reply #325 on: September 25, 2015, 11:24:41 am »
I'll be off to make non-generic List classes for EVERYTHING now!

Or is that a bad idea?  :o
Premature optimization is the root of all evil. Just wrapper the ones you actually need to and focus on writing the game :) We still use tons of lists of value types that need none of these treatments, because we never use Contains() or whatever on them.


Quote
Edit2: I don't suppose using the same approach for IndexOf() would work to the same effect?
We don't use IndexOf() often enough for me to know for sure, but I suspect it's the same deal there if you're seeing allocation from that method.


The general principle is that List<T>, where T is a struct (includes int, enums, etc), has to "box" a T before it can test it for equality to another T. Both Contains() and IndexOf() necessarily involve O(n) "does T1 equal T2?" operations, hence O(n) boxing operations. Boxing means allocating a reference type on the heap which contains a T (that may not be exactly what happens, but it allocates something on the heap).

Boxing is often not a problem, and you don't have to make it public enemy number one, but if it's something that gets hit a _ton_, like thousands of time per frame for sixty frames per second, then... ow.
Have ideas or bug reports for one of our games? Mantis for Suggestions and Bug Reports. Thanks for helping to make our games better!

Offline Shrugging Khan

  • Hero Member Mark III
  • *****
  • Posts: 1,217
  • Neinzul Y PzKpfw Tiger!
Re: Shrugger! Unity!
« Reply #326 on: September 25, 2015, 12:33:40 pm »
Yep, IndexOf() was another one this approach fixed.

I'll stop optimising now; everything seems to run pretty smooth as is  :D
The beatings shall continue
until morale improves!

Offline Draco18s

  • Resident Velociraptor
  • Core Member Mark V
  • *****
  • Posts: 4,251
Re: Shrugger! Unity!
« Reply #327 on: September 25, 2015, 12:45:29 pm »
IndexOf() can be optimized....if the list is already sorted.  Then there's a binary-search shortcut version that you can utilize.

Again, assuming the list is already sorted.  Which is easy if you start with an empty array, use BinaryIndexOf() and then Insert().

Probably best for large, but typically unchanging, collections.  Smaller and more mutable ones will likely benefit most from the manual search.

Another alternative is to use Dictionaries, which have O(1) lookup times (and O(1) insertion), but operate on key-value pairs.

Offline Shrugging Khan

  • Hero Member Mark III
  • *****
  • Posts: 1,217
  • Neinzul Y PzKpfw Tiger!
Re: Shrugger! Unity!
« Reply #328 on: September 25, 2015, 01:05:25 pm »
I think I really should look into that, because Insertion is shaping up to be the next-biggest performance problem.

But no more optimising for now, I have to play with all the pretty shapes colours I can finally afford (performance-wise) :D
The beatings shall continue
until morale improves!

Offline Draco18s

  • Resident Velociraptor
  • Core Member Mark V
  • *****
  • Posts: 4,251
Re: Shrugger! Unity!
« Reply #329 on: September 25, 2015, 01:30:01 pm »