Profile Based Optimization and Test Driven Development
April 2nd, 2007 by proj
Modern video games can be about as hard to tame as a large fire breathing dragon. It’s usually not until around when the marketing budget is finalized, traditionally around 6 months before release that people start talking about bringing the dragon out of the cave to meet the general public. It’s not wise to allow the general public to be maimed, charred and eaten by a fire breathing dragon.So the dev team picks a few brave souls to go into the cave and coax the dragon out. Presumably at this point the band of merry men look around blithely at one another and one of them decides to prove his worth by charging straight on in and biting the dragons knees off. This however royally pisses off the dragon and only makes the matter worse.
It takes some serious hardware to fight dragons, don’t go into a dragon fight without taking at least some of the following:
GlowCode, gprof, ElectricFence, LOP/F1 Profiler, BoundsChecker, ValGrind, dbghelp.lib, VLD
I put GlowCode at the front of the list intentionally. I just downloaded it but this thing is the excalibur of dragon slaying tools.
GlowCode is a great developer tool, it might look a little crufty but all the little interface issues are thought through and the thing is just fast and does everything you want right how you want it. I quickly found a number of hot spots in the game and immediately went to take a nap (no sense fighting a dragon while tired right?)
Out of curiosity I profiled the RubyCube stress test and timefree() was using about 50% of the total time, this is the internal ruby hook that returns a Time object to the heap. Of the other time 70% was spent in gshape_render() which is the function that renders a single shape. So again, this especially outlines the need to use an alternative timing mechanism in RubyCube. Exclusive time gives a good indication of what routines are doing the most actual work but often times looking at average or total Exclusive+Inclusive time can give you a good idea of where you might find some low hanging fruit.
All of the other tests are running well. One more documentation pass and I’ll be ready to do a windows release. I want to follow that closely with the mac release. To get things running on the mac should be as simple as:
- Replace Win32 threads with pthreads (nothing fancy, just conditional compilation)
- Ditto for the critical sections migrating to pthread mutexes.
- Some cross platform glue sniffing in extconf.rb will be needed as well.
Having the test cases has been instrumental in making any progress. I keep the build stable between work sessions and focus all my work around achieving results in a test case. A lot of bugs and usability issues have been fixed already using this method. I added a couple big handfuls of useful functionality as a result.
As an example two new global methods ‘pause’ and ‘resume’ were added to allow me to control the animation test more explicitly. This is actually a really simple feature that is fun to play with.
Also as a result of this type of work I converted to using array tuples for vector arguments. This has made the ruby code more readable and allows an easier transition from 2D to 3D.
Timers are another big example, without the stress test I never would have seen the timer GC thrashing and decided to implement a timer event.
Related posts:






