Exception(al?) performance
Read on for an exception performance review with Visual C++ and x86 vs. the new x86_64
ABI.
Test setup
All tests were compiled using Visual C++ 8.0 in the default release mode. The host system was a Turion64 with 1.8 GHz running Windows XP x64. Here are the raw performance timings:
ABI | Time (in sec.) |
---|---|
x86 | 0.281 |
x86_64 | 0.156 |
Obviously, the x86_64
ABI is already better in this simple test-case, let’s so how well it performs when it comes to exception handling.
Throwing exception
Let’s start off with the unusual case - we’ll throw hundreds of thousands of exceptions in tight loops, rethrow them in recursive functions and catch them at the highest level. After that, we’ll only throw at the deepest recursion level and capture at the top-most level.
ABI | Time (in sec.) |
---|---|
x86 | 47.25 |
x86_64 | 208.234 |
Really horrible, isn’t it? From roughly 200 times up to 1000 times slower. Note however that in this example, 12.5 million exceptions have been throw, of which 10 million have been rethrown again and 2.5 million exceptions have been caught somewhere.
ABI | Time (in sec.) |
---|---|
x86 | 12 |
x86_64 | 23.469 |
Much much better already, again, 2.5 million exceptions thrown and captured. Obviously the stack unwinding is fast, but the x86 ABI is able to find the right handler more than twice as fast as the x86_64
.
Not throwing exception
Let’s take a look what happens when we handle exceptions basically everywhere but if we don’t throw them.
ABI | Time (in sec.) |
---|---|
x86 | 0.484 |
x86_64 | 0.218 |
This is an interesting result, isn’t it? When no exception is throw, the performance is nearly equal to the completely exception-free version.
ABI | Time (in sec.) |
---|---|
x86 | 0.421 |
x86_64 | 0.203 |
This is probably the usual case. High-level code is catching exceptions which might be thrown somewhere in the low level code. Actually the situation exceptions have been primary designed for ;) . And here, the x86_64
ABI really pays off. Seems those folks did a good job, the exception handling version became merely 25% slower, while the x86 slowed down by 50%. Please note that the test function was rather pathetic, a single fmul/fdiv and an add. In real-world code, exception handling won’t slow things down that much (except you start adding exception handling to high-performance code inside the tightest loops), I’ve observed slowdowns in the range of 1-2% on larger functions.
Conclusion
Exception performance is not as bad as many think, and most importantly, it’s getting better with the new x86_64
ABI. Finally you pay for the exceptions your throw and not for those you don’t throw, and this is how it was meant to be from the beginning.