You are on page 1of 2

Back to C++ Optimization Techniques

1: General Strategies
There's a right way and a wrong way to do optimization. Here's some strategies c
ommon to all programming endeavors that work and don't work.
1.1: Optimization Strategies that Bomb
Assuming some operations are faster than others. When it comes to optimizing, ne
ver ever assume anything. Benchmark everything. Use a profiler. Even while I was
doing examples for this paper, some of my "optimizations" turned out to be majo
r duds.
Reducing code to improve performance. Reducing code might improve performance; i
t might not. Increasing the amount of code will often improve performance. Loop
unrolling is a prime example.
Optimizing as you go. Big mistake. As software engineer Donald Knuth said, "prem
ature optimization is the root of all evil." Optimization is one of the last ste
ps of a project. Plan for it, but don't optimize too soon. If you do, you'll end
up optimizing code that you either don't use or that doesn't need to be streaml
ined in the first place. However, there are some efficiency techniques you can u
se throughout your project from day one. These tips can make your code more read
able and concise. I've listed them in the "as you go" section.
Worrying about performance before concentrating on code correctness. Never! Writ
e the code without optimizations first. Use the profiler to determine if it need
s to be revised. Don't ignore performance issues; let performance issues guide y
our design, data structures, and algorithms, but don't let performance affect ev
ery aspect of your code. In a typical application, only a small percentage of th
e code requires optimization. In a game, it's usually the inner loops of the bli
tting, AI or physics routines.
1.2: Optimization Strategies that Work
Set design goals for performance levels. How responsive should the app be? Be sp
ecific. Think in terms of concrete millisecond values. Put the values in the spe
cs. What's the target frame rate? How will the program deal with Internet latenc
y and bandwidth issues? In what portions of the application is efficiency critic
al, and in what portions is efficiency secondary?
Choose a program architecture appropriate to the problem at hand. When you evalu
ate each option, whether it be the choice of using a single-threaded vs. multith
readed architecture, using a database vs. a flat file, using a custom engine or
writing your own, be sure to consider efficiency.
Select the proper data structures. Carefully evaluate whether you should use flo
ating point or integer math, lists or vectors, hash tables or trees. The right d
ata structures can make the difference between a great game and a dog. That's wh
y the id team used BSP trees instead of Z-buffering in Quake. BSP trees best sol
ved their particular problem.
Choose the right algorithms. A linear search may be more appropriate than a bina
ry search. Insertion sort may be faster than quicksort. See the discussion of sw
apping algorithms in the next section to see how small algorithm variations can
effect performance.
Be sure to concentrate on perceived performance. Focus on how the app feels, not
the actual numbers. Perhaps increasing object velocity produces a better app th
an increasing the frame rate. Try it. Use progress bars, animations or other eff
ects to hide level loading or other long processes. Be sure the program is respo
nsive to player input, too. If your app runs at 60 fps but takes half a second t
o process mouse clicks, it's time to refocus your optimization efforts where it
will make a difference.
Understand the costs of common programming operations and algorithms. Is integer
division faster than multiplication or the other way around? Is floating-point
math faster than integer math for your target platform? Knowing the answer can h

elp you make your app run faster. See the costs of common operations.
Profile to find bottlenecks. Add your optimizations. Profile to find bottlenecks
. Rinse and repeat. Don't settle on an optimization without verifying that it ac
tually improves the program. Always run "before" and "after" benchmarks to evalu
ate optimizations. Store the results of each profiling run so you can compare th
e differences.
Evaluate near-final code. Don't evaluate the debugging version, and don't evalua
te the release version too early - you'll end up modifying code that you'll thro
w out anyway.
Use your QA department (or person) to create and automate profiling runs. If you
don't have a QA department, automate the profiling runs yourself. You'll never
regret it.
1.3: Example of Selecting the Proper Algorithm: Swapping
Swapping objects is a common operation, especially during sorting. The standard
C++ swapping function is very simple.
template <class T> void MySwap(T& a, T& b)
{
T t = a; // copy ctor
a = b; // assignment operator
b = t; // assignment operator
}
// destructor (element t)
Swapping is so simple that we really only need a single function to handle it, r
ight? Not necessarily. Often an object can provide its own swapping method that
is considerably faster than calling the object's constructor, assignment operato
r (twice), and destructor. In fact, with STL, there are many specialized swap ro
utines, including string::swap, list::swap, and so forth.

As you can see, calling STL swap is the same as using the MySwap algorithm above
. However, for specialized classes, like strings, swapping has been optimized to
be 6-7 times faster. For the bitmap object, which has extremely expensive const
ructors and assignment operators, the bitmap::swap routine is over 8000 times fa
ster!
Back to C++ Optimization Techniques

You might also like