Boost logo

Boost :

Subject: Re: [boost] Boost.Outcome review - First questions
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2017-05-24 21:30:53


> construct a toy example that shows that. However, people who choose to
> avoid exceptions make a bigger claim, something along the lines of "in my
> domain we can't afford exception handling overhead". I have _never_ seen
> hard data to support this.

SG14 have tried to find where enabling or disabling C++ exceptions made
any difference to performance so long as exceptions were not regularly
thrown. They have found none.

There are lots of other reasons to globally turn off C++ exceptions, but
performance in the non-throwing case is not one.

> Moreover, in the above response you seem to be talking about the speed of
> the unwinding itself, not about the effect of exception handling on the
> general speed of the code (when exceptions are not thrown).

No I am exclusively talking alone about the cost of throwing and
catching exceptions. Non-throw induced unwinds I have found there to
also be no difference in performance between C++ exceptions on versus off.

> This may be
> true but your reasoning is still rather abstract. Does anyone have a
> concrete program where reporting a failure by throwing would be too
> expensive? If not, what problem are we aiming to solve with Outcome?

c.f. the AFIO v1 review some years ago where my view that the cost of
throwing an exception was irrelevant compared to a disc i/o. I was still
panned for that design choice.

Because I believe in giving people what they want, we have arrived here
with a generalised framework for avoiding exception throws entirely as
was necessary for AFIO v2 given peer review feedback from here. So far,
most people seem to feel that I have given them what they wanted. I am glad.

> By the way, it would be very helpful if the examples in Outcome don't talk
> about failures to open files, especially if the objection to using
> exceptions is that their performance is "unpredictable".

File i/o failure can be both common and unpredictable. It's why AFIO v2
needed a very low overhead failure handling mechanism, and I use it with
a vengeance in afio::algorithm::* the AFIO v2 filesystem algorithms
library. Performance, especially on NVMe SSDs, is spectacular.

> I agree that talking about actual compilers today is relevant and should be
> considered, so when I'm discussing exception handling overhead I do mean
> actual real world uses.

In real world code, the cost of the exception throw and catch mechanism
will be dwarfed by work done during the unwind in most cases. So for the
average case, just go with C++ exceptions and relax.

But for some users, every possible execution path needs to have a hand
allocated CPU cycle budget. For these users, Expected or Outcome is less
error prone than integer error codes.

> That said, in the spirit of C++ we should think of exception handling
> abstractly, even not considering specific ABIs. After all, we don't talk
> about the overhead of using for loops vs. do-while, do we? It should be the
> same with exceptions. If I have:
>
> try { throw x(); } catch( x & ) { }
>
> there is no reason for any exception to be actually thrown. In principle,
> compilers should be able to see that the above is noop.

Most of the time trivially obvious try...catch are turned into a branch
to early exit by the compiler. But it's not consistent. I've seen very
obvious trivial try...catch get turned into a full dive into the runtime
for execution despite the obviously inlined code. I would assume an
optimiser bug.

> From this point of view, there should be no performance difference between
> returning an error code or throwing an exception, and if there is, that is
> a problem of the compiler or the ABI but not of the semantics of exception
> handling as defined by C++.

For some users, "should" isn't enough. They want *guaranteed*.

> We shouldn't be inventing new styles of reporting failures to work around
> the shortcomings of C++ code generators, or at least we should openly state
> this as the main motivation.

Either monads are absolutely standard in Rust and Swift. They can be
overused or misused just like anything else. But nobody is inventing
anything here. We are cloning and putting another tool into developer's
hands. Given the huge popularity of this review, I would say most agree.

Niall

-- 
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk