In Systematic Error Handling in C++ Andrei Alexandrescu claims that C++ exceptions are very slow. This is understandable: the code behind the scenes that handles an exception is rather complicated. It needs to dispatch the exception to a proper catch block and make stack unwinding happen so that all objects that need to be destroyed, be destroyed.

It is clear that exceptions should be used for exceptional situations, and not just as a way to transfer control way up the stack.

Nevertheless, it is interesting to know how fast / slow exceptions are.

I used Google’s benchmark library to benchmark exception handling.

Scenarios I benchmarked were:

  1. No exceptions: the benchmarked function calls another external function and modifies its result. Why call an external function: because the optimizer can optimize away an empty try…catch block. Why modify the result: because the optimizer can turn CALL instruction into JMP.
  2. Same as above but with try…catch around the external call. This allows for measuring the real cost of the “zero cost” exception model.
  3. Same as above but the external function throws an exception. The catch block swallows the exception and does nothing else. This allows for measuring the cost of exception handling.

System specifications: 4 X 3800 MHz CPUs, CPU Caches: L1 Data 32K (x4), L1 Instruction 32K (x4), L2 Unified 256K (x4), L3 Unified 6144K (x1)

Compilers tested: g++ 7.2.0, g++ 6.4.0, g++ 5.4.1 (all are x86_64-linux-gnu); clang++ 5.0.0-3, clang++ 4.0.1-6, clang++ 3.9.1-17ubuntu1, clang++ 3.8.1-24ubuntu7. (all are x86_64-pc-linux-gnu).

g++ 4.8.0 didn’t work, the application crashed: bm: malloc.c:2427: sysmalloc: Assertion (old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize – 1)) == 0)’ failed.

According to the Compiler Explorer, all g++ compilers generated the same code; clang++ compilers also generated the same code, albeit a bit different from g++.

func_empty
time, ns
func_trycatch
time, ns
func_throw
time, ns
g++ 7.2 2 2 1320
g++ 6.4 3 2 1288
g++ 5.4.1 3 2 1305
clang++ 5 2 2 1323
clang++ 4.0.1 2 2 1329
clang++ 3.9.1 2 2 1321
clang++ 3.8.1 2 2 1304

Some g++ tests says that func_empty() is sometimes slower than func_trycatch(). I find it hard to believe, as the code generated for both functions is the same (obviously, only catch` part differs). This is probably a measurement error, and the difference in couple of nanoseconds is insignificant.

The results show that:

  • in terms of execution time, zero cost exception model is really zero cost — unless you have to catch an exception;
  • when you have to catch an exception, the overhead is quite significant — microseconds vs nanoseconds. In my opinion, this confirms the statement that exceptions should be used for exceptional situations — at least when you are concerned with performance.

Recommended reading: Top 15 C++ Exception handling mistakes and how to avoid them.

How Slow Are C++ Exceptions?
Tagged on:         

Leave a Reply

Your email address will not be published. Required fields are marked *