Performance and Optimization
The first rule of Optimization Club is that you don’t optimize.
Not too quickly, anyway.
Let’s say you have two algorithms for accomplishing a particular task. Option #1 is the easy approach, as far as the code goes. Easy to write, easy to test, easy to debug, easy to understand. Option #2 is more sophisticated, but it is likely to be faster when it comes time to run.
Which algorithm do you choose?
Until you know you have performance problems, don’t stress too much over algorithms that might be slow. It would be a shame to waste valuable time optimizing something that wasn’t ever slow enough to be a problem in the first place.
The second rule of Optimization Club is to know what’s slow.
As soon as we have performance problems, we have a tendency as programmers to say things like, “Well if my game is running slow when there are dozens of torpedoes being fired, I know it’s a problem with how torpedoes are being drawn, because I know I coded that terribly.”
As programmers, we know our programs really well, and we usually have a good hunch at where the problem lies. But if you had jumped in and started optimizing the torpedo rendering on your hunch, you wouldn’t have discovered that this wasn’t the problem until you eventually stripped out all of the rendering for your torpedoes and still saw performance problems.
Sheesh. Good thing you didn’t do that, right?
When you have performance problems, the first step is to find out what is actually running slow, and the only way to do that is to measure it. What methods does your lazy butt program spend all of its time hanging out in? Is it always going to the alley behind the school to hang out with shady variables? You’ve gotta keep an eye on these kids. They’re always up to no good. (Sometimes, I have no hope for the future generations of code lines.)
Even relatively fast methods can be the problem, if they’re called a lot.
You’ve got to pinpoint the time consuming operations, and it’s not always what your gut tells you.
Now, before you go and add a lot of logging statements, or a bunch of
Console.WriteLine statements throughout your program, wait.
There are already programs that will make this easy for you, with no changes to your code. Please, for the love of Stinky Pete, don’t write your own. These programs are called profilers, and they give you all sorts of cool information about where your code is spending all of its time. (An ankle monitor for those no good codes!)
For C# applications (including XNA games) my first choice is a profiler called EQUATEC Profiler. It’s free, though there’s a paid version as well, and they make you sign up and may send you emails until you tell them to stop. You know. The normal junk.
I don’t have time in this particular post to explain exactly how it works (maybe another day) but the basic idea is, you drop your .exe file into the program and start it running. About a bajillion times a second, it stops it and checks what method it’s currently in. When you’re done, you can have the program collect it all and display it for you in some very nice little diagrams, and you can see exactly what methods are taking up all of the time.
It tells you the total time for each method, the total times the method was called, and the average time for each call. That’s some very powerful information, and it helps you pinpoint the problem to a specific method.
Of course, if you have big methods (they’re not fat, they’re just big boned) you may ultimately need to split the methods apart to see what specifically is causing the problem.
The bottom line is, you don’t know what’s slow until you measure it.
Turns out, it’s not rendering the torpedoes that’s slow, it’s all of that checking to see if the torpedo is in any of hundreds of bounding boxes, to determine if the torpedo has hit its target. (Or another of your own ships. Friendly fire!)
Now that you know where the problem lies, you can come up with plans to fix it. Before this point, there was no value in optimizing anything.
This brings us to…
The third rule of Optimization Club is that you should design your code in ways that easily change it; specifically, to swap one algorithm for another.
So the third rule of Optimization Club is the first rule of Software Design Club. How quaint.
Obviously, the design and structure of your game is a very large iceberg that I can’t even begin to cover here.
But rather than leave you completely hanging, one common approach is for the things where is more than one option available, especially if you think it might change down the road, define an interface for the algorithm. Implement your initial pass as a class that implements the interface, and if you need to optimize with a faster algorithm later on, you just create a second class that implements the interface and swap the one out for the other.
Performance and optimization are strange beasts. No matter how much planning you do up front, you sometimes just can’t tell what will need to be fast. (Which makes it the bane of the waterfall model.) Nearly every “real” program you build will have performance problems sooner or later.
Just remember: don’t optimize prematurely, know what’s running slow, and plan ahead for areas of your program that may need to be swappable, so that you don’t paint yourself into a corner.