I love doing performance optimizations. Let’s take some algorithm or some part of the app, understand it, and then improve, so it works 5x… or 100x faster! Doesn’t that sound awesome?
I hope that you answered “yes” to the question in the introduction. Doing optimizations is cool, fun… and it’s like a game: How far you can go, how much you can beat?
On the other hand, not everything can be funny and easy. Sometimes we must stop and not optimize anymore.
Let’s have a look…
Are You Really Optimizing?
There are lots of optimization manuals that will give you tips and guides on how to write faster code. It’s relatively easy just to pick up some code and start applying the tricks.
You see a branch? OK, here are some tips to reduce branching.
Is the object too large? OK, let’s see how to squeeze things a bit.
Too many allocations? OK, let’s use some memory pool.
I am not saying the tips are bad — far from that. But sometimes that will only give you a few percent of improvement.
A real optimization is often much harder than applying five random tricks.
First of all, you should understand the system/module/algorithm. Maybe you can eliminate some code completely? Maybe you can use some better algorithm with optimal complexity? Or maybe you can do things in some other way?
Ideally, you should start from the top: understand the system and then go down doing optimizations on layers. It would be bad to see that you spend a week optimizing code in the lowest layer, but then someone noticed that the half of the module could be removed entirely (with your changes, of course).
Is It the Right Place?
Are you sure the part of the system really makes things faster?
If you optimize a routine from one second to 0.1 seconds, that’s 10x improvement. Great!
But, if the whole system takes 100 sec and the routine is called only once, you only improved a part that is responsible for 1% of the work… was it worth doing?
To optimize things correctly, you should find hot spots in the app. Measure first, see how the system performs and the pick the real problems.
Do you try to measure the system, or just use your intuition?
Do the Real Task
Optimizing code is a funny game, but the job needs to be done. Not everything should run as fast as possible. A feature should work. It’s better to have two features than one-half finished feature but (potentially) working super fast. Who cares…
Rendering engines need to be fast; it’s their nature. But what about simple GUI actions?
In theory, there should be a plan for optimizations, and it should be written in the spec. If the feature is critical/important, then the spec should mention that you should optimize up to some desired level.
Do you plan the optimization in your projects?
It’s a Delicate Thing
Doing right benchmarks, finding hotspots, and improving the code might be really tough. So many factors can influence the results. Often, you can look at the wrong data and be mislead. Some tricks will work in your case, but others might even degrade the perf. Also, if you go down to CPU instructions level optimizations be prepared to do a lot of testing because other platforms might show different results.
So many times, my performance tests showed different results than I expected. One time, I thought that I’m simply using data that is causing instruction dependency, while the slowdown came more from the branching. In real apps, the problems might be even harder to measure. You think that one system is causing the trouble, while it’s because of hidden effects on a different side of the app.
Do you like perf optimization topics? Signup to my newsletter for more.
Root of Evil
Optimized code might is also perceived as much complex, with all of the crazy
asm instructions, SIMD, code duplication, loop unrolling, and that kind of creative stuff. Still, I believe that fast code can also be a clean code — for example by code simplification, code removal, and using optimal algorithms. The parts that really needs the special tricks might be extra commented so at least people can understand what’s going on.
You might also avoid premature optimization and read more here: StackExchange: Is premature optimization really the root of all evil?
Premature optimization is the root of all evil. – Donald Knuth
There’s also a nice post from Arne Mertz on Simple and Clean Code vs. Performance.
The performance game is fun. So many things you can learn, experiment, and be happy that you’ve beaten the CPU. Still, it’s good to remember to stop at some point. To have work done it’s better to leave some cool algorithm in a good enough state, and move to other tasks. Or even, you have to stop because there’s no sense to put more effort in a particular area.
However that sounds, when playing the optimization game don’t forget about the funny/creative part. Just recall from time to time, that if you have more understanding of the whole system, you can beat the CPU even more.
What are your thoughts on doing optimizations? Do you apply random tricks or have some plan? Do you have some policy in the company regarding optimizations? Do you have performance tests for your apps?