Tuesday, 24 August 2010

How fast is your debug build?

Why is your debug build slow? Lots of asserts? Awkward templates that only compile out to sensible stuff in release?

It's only a theory right now, but I think that if your game is running like a dog in debug, maybe there's something wrong with the number of branches you're doing. Not just in debug, but in general.
Asserts are the usual cause of slow down (they break the cache and branch and cause memory wastage), but they are valuable as warnings when things are going wrong. They provide great protection, but they aren't necessary if you make sure that the condition that would normally trigger them cannot be achieved.

One of the most common uses I've seen for an assert is checking for NULL. This can be avoided by just making sure that your queries are either returning null objects instead (dummy objects), or by making the query inherently null proof (use a queued up todo list rather than a fetch from and check for work to do).

Another slowdown can be from templates that aren't being fully expanded or optimised in debug code. This is a lot simpler to fix. Stop using template meta programming. Your compile time will go down too. Template meta-programming is also a replacement for moving wholesale to scripted development. Consider the problem your meta-programming is solving in light of a scripted environment.

On the PS2, we never saw that big a difference in final build and the debug build. This was mostly down to the fact that the PS2 was spending all its time streaming data from one place to another (no nulls in the middle of a stream), and processing them with data driven transforms (no meta-programming for us, just plain coded transforms driven by data demand). The only code that ever got all that faster was the C++ class style math library (which was hilarious to watch as it went from being slower than hand coded vector unit code by a factor of four to being faster than the hand coded vector unit code by a factor of two.)

Tuesday, 10 August 2010

Hidden Branches

How often do we use if's and function calls without thinking about the cost? Quite often I'd bet. But in addition to the branch operations that are explicit, there are some that are hidden, or implicit. Consider the humble logical and operation &&

if( A==1 && B==2 && C==3 )
// I needed to branch three times to get here
// I needed to branch at least once to get here, possibly two times, sometimes three.

consider the alternative

resultA = A-1;
resultB = B-2;
resultC = C-3;

if( !( resultA|resultB|resultC ) )
// I needed to branch once to get here
// I needed to branch once to get here

This is better because it's more consistent, there is no short-circuiting going on. Short circuits worked well when CPU time mattered. Now it doesn't so much. It only matters when the arguments in the short circuit depend on previous items in the chain:

if( pThing && pThing->GetStuff() && pThing->GetStuff()->IsOkay() )

But this coding style is slow and should be used sparingly.

Tuesday, 3 August 2010

Mother of invention

Developing your game through a data and transform centered design philosophy leads to short cuts around things that have been ubiquitous in games development for some years.

Managers: Managers for tweakable variables, for resource loading, for inventories, bad guys, weapons and debris.
Setup functions: Setup functions or scripts for menu systems and user interfaces, for scene trees, for levels, for rendering subsystems, and shaders, and player input configuration.
Ticks: Ticks for entities, for pre render phases, for pre physics phases, for post frame memory defragging, physics, rendering, sound and asynchronous file IO.

These are artifacts of the coding style that C++ in games has given us. They, like their design patterns cousins, offer us an insight into what's wrong with the language as much as they help us get stuff done.

Managers vanish when making an item is a simple case of adding a row to a table, deleting the item is simply removing it, and getting a reference to an item is just holding it's primary key in another table. This explains why databases never had managers for their tables. They just had the tables. Everyone knew how to access the tables, and helpful people wrote helpers to access them in terms of stored procedures (which are like macros for databases) so that changing the access pattern was removed from the use of the data.

Setup functions seem to vanish as what was setup now becomes the main loop, or the set of transforms for a particular way of doing something. In SQL, you define the tables at the beginning, and after that you don't add new ones unless something major changes. In games development that's akin to having globals for all your tables, and the main loop has static functions coupling transforms to process the data on a frame by frame basis. the code is the design, and therefore doesn't need to change unless something significant about the game changes. After the rubbish has boiled off, you naturally end up with the real data driving the game, the scripts, the level data, but none of the unnecessarily dynamic schema changing code that plagues games development built by people with good intentions.

All the various ticks vanish as the very idea of a tick becomes quite obsolete in the face of transforming data over the designated frame or other interval. Tick functions and schedulers are for systems that don't know what they're ticking. If your design is in the code, you don't need a tick, you just need to perform the sequence of transforms to produce your frame output or update your network or game logic.

In conclusion, big helpful managers, setup functions and scheduling tick systems are all symptoms of object oriented development in C++ in games. They're not implicitly good or bad, but they do point to a problem because they are not necessary.

Monday, 2 August 2010

Entity, tick thy self!

When developing in OO C++, you tend to think "entities, bunches of them, then tick them once a frame"...
However, I have come across TickAll(), Think(), Advance(), Update(), PreUpdate(), PreRender(), Step() and many other functions in my history of games development with C++. Not all the tick functions were even OOD, but the ideas behind why they were ticking generic entities were definitely coming from some OOD way of thinking.

Many engines have a form of scheduling their entities to do things in some specific order, so data is ready just in time for the next stage of it's processing. Think about how your game engine ticks movement, before doing collisions, then after collisions, ticks responses to collisions... so, you're already serially ticking sub parts of your entities. Funny thing is that you're normally ticking the entities that aren't involved in physics along with the ones that are, just in some post physics or pre rendering tick because you can't think where else to put them, or more often than not, in a function that used to be called MainTick(), but it's now called PostMovePreRender() because other ticks needed to be added to sync up data in stages over the years the engine's been evolving.

Simple example:
1. Do movement on all the moving things.
2. Do collision on all the colliding things.
3. Do collision response on all the collided things.
4. Do a general tick based on general state.

The object oriented approach is normally to MoveTick all objects in the moving things list (if you have the foresight to actually have an awake list), then Collide in the collision system (that caches and spatially coordinates stuff its own way), then CollisionResponse all objects that emerged from that tick, then GeneralTick all objects in the system that aren't hibernating. This stalls the things that don't interact from updating until their interactive brethren have finished poking each other.

It works, but it's a series of calls. So when you get around to re-writing your code as data oriented, remember that you were already calling a series of functions even when doing OO, so don't look down on a long list of function calls as if it's something horrible you'd never have done in the days of object oriented. You did before, you will again.

Splitting out the ticks like this is a habit of necessity. Coding, for games, like many successful games themselves, is a set of simple rules and a very large number of exceptions. Thinking you can get away with one Tick method is like saying that "if you hit, you deal damage"... except that's not always true.

It should also be considered as another reason why everyone should move away from entities containing all their data. Entities containing data for all circumstances is bad. Simply because if you put everyone's exceptions in your data size goes up unnecessarily. Also, if your entities share data (simple stuff like their position) then an update function has to be called before or after some other tick. This is a stall somewhere. If instead you assume prev-frame data is good enough, then you can make a read-only reference for all the things using the entity's position, while still updating the physics position multiple times due to collision and response before committing ready for the next frame.

A series of logical steps at a high level isn't bad, in fact, having your main thread a series of discrete steps through the logical transforms gives you massive benefits when it comes to debugging, performance analysis, and tuning. Consider this: if you start out by knowing how everything fits together you can reason about the whole system better and make much larger changes without fear of damage, and a general idea of what to fix/change.

Just because it seems easy, doesn't make it wrong.