Intermission #8–What’s gone wrong?

The title reflects that odd moment when you have added some new content to your project, you have been meticulous and double checked everything, it should be OK.  But it isn’t.

The odd pain as you scramble through the code, add breakpoints and sometimes spend hours looking for what you missed, miss-typed or just plain got wrong.

Drawing bugs are fairly easy to recognise, two objects are drawn in the wrong order, are missing or are in the wrong colour or format, even shader bugs are usually easy to notice although they can be sometimes a nasty piece of work to get right.

Breaking bugs are generally easy, your code won’t compile and you get lots of warnings, to trace back o the root of the problem (my worst offence has always been the scope of a class or function, always takes me a few attempts to find the right balance).

In games there is nothing worse than a performance bug.  Which is what I hit while writing the last Intermission, so this has prompted and impromptu (Smile) intermission before we jump back on to Windows Phone 7 and get that back up to speed.

Code is already included in the same codeplex area as the last post, for those of you like with with an astonishingly bad short term memory…. (the link is earlier on this line)…

Source updated for Final combined update project for GS 4.0 project here on Codeplex (Windows and WP7)

 


 

Identifying the problem

Discovering a performance problem is usually easy to spot, your game runs like it was published on a badly written and run on a ZX 81 (almost showing my age, ZX 81’s were not new when I started doing games Open-mouthed smile, doh.).  It’s slow, it’s cranky, it stops responding to your input or looks like it has crashed (that is indeed if it hasn’t)

There are several tools for digging in to your game and wheezing out all the intricate details for how your game is running:

    MS PIX (part of the Direct X SDK)
    NVIDIA PERFHud (part of the Nvidia PerfSDK) – Useful Post here on how to get the most of this in XNA
    AMD PerfTools
    The Performance Timers Project on Codeplex (couldn’t get this to actually work, but with a little more time it looks like it is quite good and simple to use)

All these tools are good and will give you a great deal of information on how your game or app is running, however….

 


 

The KISS approach

As we don’t have a large asset base or a complex set of routines in the background, there are a few simple tricks to see if you do actually have a problem.  We just need to take some timing measurements and check our game is actually running as expected.

I’ve used these principles and solved many an issue in the past, they are always a good indicator if you need to dig deeper or if there is just a simple problem that needs tweaking.

As an example of this, one of the first games I wrote for a competition seemed to be working well, however over time the game would get slower and slower until it became unresponsive.  After doing some checking I couldn’t see any actual problem.  After putting some timings into my code and a few tests, the answer became obvious, I was creating new spritebatch’s each update loop and they were either left in memory or were making garbage.  A two second code change soon resolved that and everything was hunky dory (until the next time Smile).

So how did I do this, the answer is actually very straight forward, use a clock Winking smile.

 


 

Game Monitoring or Stopwatch class

Implementing watches in your code is very straight forward and I’ve put together a little Game Component to do all the hard work for you (not that it is that hard really).  This component offers two simple features:

    A stopwatch list which measures when events start, finish and the time it took.
    A display list, to record things when they happen and what they look like.

Here’s what the class looks like:

I haven’t commented the code much so I’ll walk you through it.  First off, like the Particle Manager I created a basic Drawable game component (“Create New Item” –> XNA “Game Component” –> change inherited type from Game Component to Drawable game component and copy Draw and Content functions in)

At the top of the class are two of the core parts of the event recording, two structs, one to record Stopwatch times and one to record information.

    The STOPWATCH class stores start and end times in computer ticks and has a single property which displays the difference between start and finish
    The DISPLAYINFO class stores two information attributes, one for Text and the other for numeric’s (so that I could store information about emitters and the amount of particles they had)

Following on from these structs is the main class itself, this has two Dictionaries that use the two structs.  I use dictionaries because I can use the Key of the dictionary to also store information about each item, like the Name of the stopwatch I’m recording (so I can have several and track them back later).

In the constructor, I also load a font into the class, this is so the class itself can write it’s output to the screen and I do not need to modify any part of my game code to do it, the class is self maintained.  We also set the Draw order for the component to ensure it is always on the top of the screen and doesn’t interfere with the game itself. (more on fonts later in the series)

After that the next section that has changed is the Draw function.  Pretty basic stuff though where we loop through each of the two dictionaries and display their contents, one after the other on the left hand side of the screen (note the “I” variable which helps control where each line is drawn)

Lastly we have 4 helper functions for Starting / Stopping watches and for adding new information text or removing it from display.  These just make the implementation in the game code much smoother and easier (reducing them to single line calls for each)

    I originally used a “STRUCT” for the stopwatch and displayinfo classes.  Now it wasn’t exactly wrong but I realised an important lesson there.  ONLY use STRCTS for read only single use classes.  If you intend to change the values stored in a struct, then you probably should not be using a struct.  Because to change the values you need to really create a new or copy instance of the struct and overwrite it with one with the updated settings.


 

Adding the checks

It usually pays to only put tests and check in where you need them, starting at a high enough point to know where to drill down.  So start with a few tests and add more as you need them (I have added a fair few to the test project, but here’s where to start).

One thing to keep straight in your mind if the old “Observer effect”.  “By watching or observing something, you change that thing” (or something like that), just look up the Schrödinger’s cat theory to tax you mind.  Basically, by adding observations or tests you are in fact changing how your game runs.  Too many tests can cause other problems which may indeed create a new performance issue for you to solve.  As always remember KISS (I should record tat tune), start small, drill down and remove unneeded tests.

  1. Start with the main functions in your game, Draw and Update to see if you have an Update or Draw issue Smile
  2. Then drill into the suspect function (do one at a time)
  3. Add some more tests and then drill down again
  4. Once you have passed a level or two, remove some of the higher tests to ensure they are not interfering with your results.

With my initial implementation, I hit big problems when 5 or more shots were fired on the screen at once, when they left the screen it didn’t get any better.

So I added my shiny new simple testing class to my StarTrooperGame.CS class, first I created a static instance of the class, so it could be accessed easily by the entire project:

And then I instantiated it in the Initialise function, so it would be ready when the game started:

Note the #IF statements, I’ve added this to all the areas where I have implemented tests, so I can just run the game in “Release” mode to see if my changes are having any effect, if the game is in “Release” mode then the tests are ignored by the compiler.

Next I added stop watch tests around the Draw and Update loops, starting each stop watch like so.

Update:

Draw:

And then stop each stopwatch before each function had finished.

Update:

Draw:

    Note that each Stop and Start Timer call uses the same Key / Text, this is what is used in the DisplayTimer class’s dictionary to identify which clock we are dealing with.

This yielded results to show that it was the Draw function that was costing me the most, so I drilled further and added the same tests in the particle managers Drawing function (see the code for the implementation or try yourself)

From this I could see that the Particle manager and more specifically each Emitter was taking a long time to draw.

So I then added some information queries into the Emitter Update calls to see just how much information the draw call was dealing with.  In the Particle Manager class I added the following to the beginning of the Update function:

And also for good measure, I also added the following inside the update loop to get information on each emitter:

The first calls ID is set to –1 to separate it from the rest of the emitters in the information as I want to know exactly how many emitters have been called and are active.  In the second call I use the Emitters NODE ID as the key for the report and then output the emitters type and the number of particles active in each emitter.

And then it hit me, I noticed two disturbing things:

    Firstly, each emitter was using a very large amount of particles, I had set the threshold far too high in the emitters Initialise Constants function.  Turning this down helped (but by more than I expected, it turned out I only needed a few particles to achieve the effect I needed)
    Secondly, the emitters were not dying out.  At first this was because I was not killing the emitter when it left the screen (simple location check to kill the emitter) and second becuase I was not then removing the emitters information test I had just added (added a “Remove information” call when the emitter died, whoops).

The last part of that was a but silly but a good example where I fixed the problem but because I didn’t update my tests, it didn’t seem to go away.  In reference I added the following in the Particle Managers Update call to remove the information I was tracking when a emitter died (this shows both fixes for the second issue:

Feel free to play with this information gathering and see what you can dig up.  After all the main parts have been fixed, I added some extra tests in to the project and it now sees the main resource hog is XNA’s own Draw call outside of my game, but this could be because of the testing itself, see below:

image

Here you can see the information test listed on the left hand side of the screen with the run time values, note that the main clock tick cost (game runtime cost) is now coming from the Base Game class.  The particle Manager and each emitter is behaving itself nicely.

 


 

Planning ahead

Of course one of the best things to do is to plan in advance for performance and try to stay ahead of the curve, here’s a few links to resources to help you do just that:

    XNA Performance sessions – Best resources are on the XNA Developers central link (not the CC site which is curious, but you can find them there if you dig enough)
    Windows Phone 7 Performance – Shawn Hargreaves recently gave a Mix 2010 session on Phone performance, Channel 9 also has an entire channel full of WP7 Training videos as well.

 


 

Conclusion

Hopefully you have gained a little insight in this extra little session, now back to updating the phone and maybe playing with the extra little idea from the post on alternate particle solutions

Yay, Shiny.

%d bloggers like this: