So, I've been working on a rewrite of the most time-critical component of our code. I've been begging for a chance to do this pretty much the entire time I've been working here, and I've finally been given the chance.
There are several versions of this code that already exist -- so why write it again? Well, our options are:
- An incomprehensible mess of Fortran that runs (presumably) very quickly, but is one of the greatest examples of write-only code I've ever seen.
- A huge, featureful and highly-modular C++ implementation that takes about 3-4x longer to run.
- A slimmer C/C++ implementation (C++ design with a lot of C-isms) that was developed by a collaborator. It strikes a compromise between the previous two in both size and speed.
As an aside, I am completely sick of "Fortran is faster than C/C++" arguments. How you write the code affects speed, but the distinction between these languages (for line-by-line equivalent code) does not. Most modern compilers for all of these languages share a common backend, so STFU and GTFO. C++ provides a lot of tools to help you write better and cleaner code, but it's the responsibility of the programmer to understand the cost associated with each of these optional tools.
Anyway... I've been working on a new version of the code. The underlying philosophy is to never sacrifice any performance, then make the cleanest and most extensible code possible.
I completely missed my target. My goal has been to match the performance of the original Fortran code, which takes 20 seconds to run on a standard example problem. Not only did I miss my target, I missed it by a factor of three. Ouch.
My new code runs in 6.5 seconds.
Oh. :)
I did the following:
- Obsessively tighten and optimize the memory layout.
- Restructure the iteration order for better cache performance.
- Write the code in a way such that the compiler can do a decent job rewriting the math with SIMD (SSE2) instructions.
- Exploit a near-symmetry in the kernel (my pride and joy, the only thing that could still be done to actually reduce the number of flops).
I know that, often, the "let's re-write it from scratch" argument is a bad one, but I think I've made my case this time around.
Summary: Rewriting critical code, and I did better than I expected. Not only did I make my performance target, but I managed to beat it by a factor of three. Yay.

4 comments:
Wow. Well done! Kudos to you. =]
So I guess it's fair to say you're not doing it wrong?
P.S I suggest you write a formal version of this essay (you know, without the GTFO and internal hyperlinks or pointers to some more technical discussion of various key points) and link to this document on your new website. Seriously---this is the type of stuff you want to show people.
Feel a little silly tooting my own horn, of course, but I've been feeling a bit celebratory since I finished it up.
I'm mostly not doing it wrong, though I've certainly still commited a few crimes. I blitzed through the code so fast that it isn't even in CVS yet, and it's *DEFINITELY* writing the same code (in a sense) for the umpteenth time.
Thank youu for this
Post a Comment