Live data from Hacker News

C++'s `noexcept` can sometimes help or hurt performance

16bpp.net

41–50 of 166 posts

Re: C++'s `noexcept` can sometimes help or hurt performance

#41

There's a lot of mysticism and superstition surrounding C++ exceptions. It's instructive to sit down with godbolt and examine specific scenarios in which noexcept (or exceptions generally) can affect performance. Read the machine code. Understand why the compiler does what it does. Don't want to invest at that level? You probably want to use a higher level language.

You won't get a sense of how bad exceptions can be by using Godbolt. A lot of the magic of exceptions is handled behind the scenes by the compiler and/or the Itanium ABI. For example one disasterous consequence of using exceptions in GCC is that there is a global application wide lock used to manage stack unwinding.

This means that only one single thread can unwind a stack at a time and the lock is held from the start of the exception being thrown until the very last destructor is called. If you have a multicore server with 100 threads, and one of those threads throws an exception, you better hope that no other thread throws an exception because even if those two threads are entirely independent of one another, one of them will block.

You won't see this by looking at Godbolt.

Re: C++'s `noexcept` can sometimes help or hurt performance

#42
Oh man, don't get me started. This was a point in a talk I gave years ago called "Please Please Help the Compiler" (what I thought was a clever cut at the conventional wisdom at the time of "Don't Try to Help the Compiler")

I work on MSVC backend. I argued pretty strenuously at the time that noexcept was costly and being marketed incorrectly. Perhaps the costs are worth it, but none the less there is a cost

The reason is simple: there is a guarantee here that noexcept functions don't throw. std::terminate has to be called. That has to be implemented. There is some cost to that - conceptually every noexcept function (or worse, every call to a noexcept function) is surrounded by a giant try/catch(...) block.

Yes there are optimizations here. But it's still not free

Less obvious; how does inlining work? What happens if you inline a noexcept function into a function that allows exceptions? Do we now have "regions" of noexceptness inside that function (answer: yes). How do you implement that? Again, this is implementable, but this is even harder than the whole function case, and a naive/early implementation might prohibit inlining across degrees of noexcept-ness to be correct/as-if. And guess what, this is what early versions of MSVC did, and this was our biggest problem: a problem which grew release after release as noexcept permeated the standard library.

Anyway. My point is, we need more backend compiler engineers on WG21 and not just front end, library, and language lawyer guys.

I argued then that if instead noexcept violations were undefined, we could ignore all this, and instead just treat it as the pure optimization it was being marketed as (ie, help prove a region can't throw, so we can elide entire try/catch blocks etc). The reaction to my suggestion was not positive.

Re: C++'s `noexcept` can sometimes help or hurt performance

#43
post #10

That's quite interesting and a huge work has been done here, respect for that. Here's what has jumped out at me: `noexcept` qualifier is not free in some cases, particularly, when a qualified function could actually throw, but is marked `noexcept`. In that case, a compiler still must set something up to fulfil the main `noexcept` promise - call `std::terminate()` if an exception is thrown. That means, that putting `n…

> in that case, a compiler still must set something up to fulfil the main `noexcept` promise - call `std::terminate()` This is actually something that has been more of a problem in clang than gcc due to LLVM IR limitations... but that is being fixed (or maybe is already?) There was a presentation about it at the 2023 LLVM Developer's meeting which was recently published on their youtube channel https://www.youtube.co…

In MSVC we've also pretty heavily optimized the whole function case such that we no longer have a literal try/catch block around it (I think there is a single bit in our per function unwind info that the unwinder checks and kills the program if it encounters while unwinding). One extra branch but no increase in the unwind metadata size

The inlining case was always the hard problem to solve though

Re: C++'s `noexcept` can sometimes help or hurt performance

#44

Oh man, don't get me started. This was a point in a talk I gave years ago called "Please Please Help the Compiler" (what I thought was a clever cut at the conventional wisdom at the time of "Don't Try to Help the Compiler") I work on MSVC backend. I argued pretty strenuously at the time that noexcept was costly and being marketed incorrectly. Perhaps the costs are worth it, but none the less there is a cost The reaso…

Added to my list why I compile with -fno-exceptions

Re: C++'s `noexcept` can sometimes help or hurt performance

#45
post #8

I don't feel like this article illuminates anything about how noexcept works. The asm diff at the end suggests _there is no difference_ in the emitted code. I plugged it into godbolt myself and see absolutely no difference. https://godbolt.org/z/jdro5jdnG It seems the selected example function may not be exercising noexcept. I suppose the assumption is that operator[] is something that can throw, but ... perhaps the…

You can't just look at the codegen of the function itself, you also have to consider the metadata, and the overhead of processing any metadata

Specifically here (as I said in other comments) where it goes from complicated/quality of implementation issue to "shit this is complicated" is when you consider inlining. If noexcept inhibits inlining in any conceivable circumstances then it's having a dramatic (slightly indirect) impact on performance

Re: C++'s `noexcept` can sometimes help or hurt performance

#47
post #4

Shouldn't the compiler deduce noexcept for you?

The compiler can tell about the immediate function, but not any functions it calls. If a function marked noexcept calls a function that throws an exception, then the program is terminated with an uncaught exception. A called function can throw through a non-noexcept function to a higher-level exception handler no problem. So in order to avoid changing the semantics of the function, the compiler would have to be able…

No, we compile in bottom up order, starting with leaf functions, and collecting information about functions as we go. So "not throwing" sort of trickles up when possible to a certain degree.

In LTCG (MSVC)/O3 (GCC/Clang) there are prepasses over the entire callgraph to collect this order

Re: C++'s `noexcept` can sometimes help or hurt performance

#48
post #33

Earlier quoted context omitted.

> The point of standardized components is to provide reusable elements that can be used across all platforms and implementations, thus saving on the development effort of upgrading and porting the code across implementations and even platforms. It's a shame that C++'s "standardized" components ARE COMPLETELY DIFFERENT on different platforms. Some of the C++ standard requires per-platform implementation work. For exam…

I consider the current tradeoff to be a feature. It permits implementations to take advantage of target-specific affordances (your thread case is an example) as well as taking different implementation strategies (e.g. the small string optimization is different in libc++ and libstdc++). Also you may use another, independent standard library because you prefer its implementation decisions. Meanwhile they remain compati…

Hard, hard disagree.

If you want to support different implementation strategies it needs to be far more piecemeal. Not all or nothing. I mean there's only 3 meaningful implementation - libstdc++, libc++, and MSVC. And they aren't wholly interchangeable!

Quite frankly if you value trying different implementation strategies then the C++ model is a complete and total failure. A successful model would have many, many different implementations of different components. The fact there are just 3 is an objective failure.

Re: C++'s `noexcept` can sometimes help or hurt performance

#49

Oh man, don't get me started. This was a point in a talk I gave years ago called "Please Please Help the Compiler" (what I thought was a clever cut at the conventional wisdom at the time of "Don't Try to Help the Compiler") I work on MSVC backend. I argued pretty strenuously at the time that noexcept was costly and being marketed incorrectly. Perhaps the costs are worth it, but none the less there is a cost The reaso…

Oh, cool! I googled myself and someone actually archived the slides from the talk I gave. I think it holds up pretty well today

https://github.com/TriangleCppDevelopersGroup/TerryMahaffeyC...

*edit except the stuff about fastlink

*edit 2 also I have since added a heuristic bonus for the "inline" keyword because I could no longer stand the irony of "inline" not having anything to do with inlining

*edit 3 ok, also statements like "consider doing X if you have no security exposure" haven't held up well

Re: C++'s `noexcept` can sometimes help or hurt performance

#50
post #40
post #33

Earlier quoted context omitted.

I consider the current tradeoff to be a feature. It permits implementations to take advantage of target-specific affordances (your thread case is an example) as well as taking different implementation strategies (e.g. the small string optimization is different in libc++ and libstdc++). Also you may use another, independent standard library because you prefer its implementation decisions. Meanwhile they remain compati…

Unlike in C, in C++ it is not possible to use an independent implementation of the standard library. Clang is compatible with GCC's standard library/libstdc++ and MSVC's standard library because the clang compiler explicitly supports them, but it's not possible to use clang's standard library with GCC in a standard conforming way or interchange GCC's with MSVC's standard library. There are some hacks that let you use…

> Unlike in C, in C++ it is not possible to use an independent implementation of the standard library.

It sure is, and is pretty easy to do. I know companies using EASTL, libcu++, and HPX, as well as more who use Folly and Abseil which have alternate implementations to much of the standard library.

These days many languages have a single implementation so some people whose experience is only in those environment complain that C++ is “unnecessary complicated to use”. But a lot of that flexibility and back compatibility is what allows these multiple implementations to thrive while representing different points in the design/feature space.

Post reply on HN