# C++ exception performance three years later

DevFeed: [C++ exception performance three years later](<https://devfeed.tech/articles/c-exception-performance-three-years-later-25087.md>)

Original publisher: [Read original article](<https://databasearchitects.blogspot.com/2024/12/c-exception-performance-three-years.html>)

Author: Thomas Neumann (noreply@blogger.com)

Published: 2024-12-10T14:44:00Z

Content type: article

Language: en

Sources: [Database Architects](<https://devfeed.tech/sources/database-architects.md>)

Topics: [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [Exception](<https://devfeed.tech/topics/exception.md>), [Scalability](<https://devfeed.tech/topics/scalability.md>), [gcc](<https://devfeed.tech/topics/gcc.md>), [JIT](<https://devfeed.tech/topics/jit.md>), [LLVM](<https://devfeed.tech/topics/llvm.md>)

Tags: [benchmark](<https://devfeed.tech/tags/benchmark.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [clang](<https://devfeed.tech/tags/clang.md>), [exception](<https://devfeed.tech/tags/exception.md>), [gcc](<https://devfeed.tech/tags/gcc.md>), [glibc](<https://devfeed.tech/tags/glibc.md>), [jit](<https://devfeed.tech/tags/jit.md>), [llvm](<https://devfeed.tech/tags/llvm.md>), [performance](<https://devfeed.tech/tags/performance.md>), [series](<https://devfeed.tech/tags/series.md>)

## AI overview

The article reviews improvements to C++ exception unwinding performance. Lock-free lookup mechanisms in glibc and libgcc improve scalability for statically generated and JIT-generated code, although clang's implementation may still have scaling limitations.

## Source excerpt

About three years ago we noticed serious performance problems in C++ exception unwinding. Due to contention on the unwinding path these became more and more severe the more cores a system had, and unwinding could slow down by orders of magnitude. Due to the constraints of backwards compatibility this contention was not easy to eliminate, and P2544 discussed ways to fix this problem via language changes in C++. But fortunately people found less invasive solutions. First, Florian Weimer changed the glibc to provide a lock-free mechanism to find the (static) unwind tables for a given shared object. Which eliminates the most serious contention for "simple" C++ programs. For example in a micro-benchmark that calls a function with some computations (100 calls to sqrt per function invocation), and which throws with a certain probability, we previously had very poor scalability with increasing core count. With his patch we now see with gcc 14.2 on a dual-socket EPYC 7713 the following performance development (runtime in ms): 1 2 4 8 16 32 64 128 threads 0% failure 29 29 29 29 29 29 29 42 0.1% failure 29 29 29 29 29 29 29 32 1% failure 29 30 30 30 30 30 32 34 10% failure 36 36 37 37 37 37 47 65 Which is more or less perfect. 128 threads are a bit slower, but that is to be expected as one EPYC only has 64 cores. With higher failure rates unwinding itself becomes slower but that is still acceptable here. Thus most C++ programs are just fine. For our use case that is not enough, though. We dynamically generate machine code at runtime, and we want to be able to pass exceptions through generated code. The _dl_find_object mechanism of glibc is not used for JITed code, instead libgcc maintains its own lookup structure. Historically this was a simple list with a global lock, which of course had terrible performance. But through a series of patches we managed to change libgcc into using a lock-free b-tree for maintaining the dynamic unwinding frames. Using a similar experiment to the