Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

noexcept, stack unwinding and performance

The following draft from Scott Meyers new C++11 book says(page 2, lines 7-21)

The difference between unwinding the call stack and possibly unwinding it has a surprisingly large impact on code generation. In a noexcept function, optimizers need not keep the runtime stack in an unwindable state if an exception would propagate out of the function, nor must they ensure that objects in a noexcept function are destroyed in the inverse order of construction should an exception leave the function. The result is more opportunities for optimization, not only within the body of a noexcept function, but also at sites where the function is called. Such flexibility is present only for noexcept functions. Functions with “throw()” exception specifications lack it, as do functions with no exception specification at all.

In contrast, section 5.4 of "Technical Report on C++ Performance" describes the "code" and "table" ways of implementing exception handling. In particular, the "table" method is shown to have no time overhead when no exceptions are thrown and only has a space overhead.

My question is this - what optimizations is Scott Meyers talking about when he talks of unwinding vs possibly unwinding? Why don't these optimizations apply for throw()? Do his comments apply only to the "code" method mentioned in the 2006 TR?

like image 934
Pradhan Avatar asked Sep 27 '14 22:09

Pradhan


People also ask

Does Noexcept make code faster?

That noexcept keyword is tricky, but just know that if you use it, your coding world will spin faster.

What is stack unwinding?

When an exception is thrown and control passes from a try block to a handler, the C++ run time calls destructors for all automatic objects constructed since the beginning of the try block. This process is called stack unwinding. The automatic objects are destroyed in reverse order of their construction.


2 Answers

There's "no" overhead and then there's no overhead. You can think of the compiler in different ways:

  • It generates a program which performs certain actions.
  • It generates a program satisfying certain constraints.

The TR says there's no overhead in the table-driven appraoch because no action needs to be taken as long as a throw doesn't occur. The non-exceptional execution path goes straight forward.

However, to make the tables work, the non-exceptional code still needs additional constraints. Each object needs to be fully initialized before any exception could lead to its destruction, limiting the reordering of instructions (e.g. from an inlined constructor) across potentially throwing calls. Likewise, an object must be completely destroyed before any possible subsequent exception.

Table-based unwinding only works with functions following the ABI calling conventions, with stack frames. Without the possibility of an exception, the compiler may have been free to ignore the ABI and omit the frame.

Space overhead, a.k.a. bloat, in the form of tables and separate exceptional code paths, might not affect execution time, but it can still affect time taken to download the program and load it into RAM.

It's all relative, but noexcept cuts the compiler some slack.

like image 117
Potatoswatter Avatar answered Sep 22 '22 00:09

Potatoswatter


The difference between noexcept and throw() is that in case of throw() the exception stack is still unwound and destructors are called, so implementation has to keep track of the stack (see 15.5.2 The std::unexpected() function in the standard).

On the contrary, std::terminate() does not require the stack to be unwound (15.5.1 states that it is implementation-defined whether or not the stack is unwound before std::terminate() is called).

GCC seem to really not unwind the stack for noexcept: Demo
While clang still unwinds: Demo

(You can comment f_noexcept() and uncomment f_emptythrow() in the demos to see that for throw() both GCC and clang unwind the stack)

like image 29
Anton Savin Avatar answered Sep 23 '22 00:09

Anton Savin