[llvm-dev] Exceptions and performance

Haoran Xu via llvm-dev llvm-dev at lists.llvm.org
Mon Aug 17 15:38:57 PDT 2020


>
> David was specifically talking about the case where SomeOtherFn  and
> SomeFn "don't depend on any data flow between each other".
>
> eg: you are performing lookups on two containers - compiler doesn't
> know these lookups have no side effects, so it can't collapse the two,
> but you as the author can see that readily.
>
I see, thanks for the clarification.


David Blaikie <dblaikie at gmail.com> 于2020年8月17日周一 下午3:14写道:

> On Mon, Aug 17, 2020 at 3:04 PM Haoran Xu via llvm-dev
> <llvm-dev at lists.llvm.org> wrote:
> >>
> >> I did some experiments about a year ago with different hand-written
> >> assembly implementations of error handling control flow patterns and it
> >> was really hard to beat the checked return on recent Intel hardware.
> >> This was a microbenchmark, so didn't see effects from increased cache
> usage.
> >
> > That's a very interesting result. Thanks for the insights!
> > Just out of curiosity, did you remember how much slowdown you get
> between checked return and no check at all (simply ignore the error)?
> >
> >> There's also the fact that explicit error checking lets the programmer
> >> simplify the CFG explicitly.  If you're calling two functions that don't
> >> depend on any data flow between them, you can do something like:
> >>
> >> auto a = someFn();
> >> auto b = someOtherFn();
> >> if (!a || !b)
> >>         doSomeErrorHandlingStuffs();
> >>
> >> Transforming exception-driven code into this structure would be an
> >> invalid transform unless the compiler could prove that someOtherFn() has
> >> no observable side effects.
> >
> > I didn't fully understand this part. If someOtherFn() has obversable
> side effects, you cannot convert
> > auto a = someFn(); if (!a) { ... }
> > auto b = someOtherFn() if (!b) { ... }
> > to your code snippet either..
>
> David was specifically talking about the case where SomeOtherFn  and
> SomeFn "don't depend on any data flow between each other".
>
> eg: you are performing lookups on two containers - compiler doesn't
> know these lookups have no side effects, so it can't collapse the two,
> but you as the author can see that readily.
>
> >
> >
> >
> >
> >
> >
> >
> >
> > David Chisnall via llvm-dev <llvm-dev at lists.llvm.org> 于2020年8月14日周五
> 上午7:55写道:
> >>
> >> On 14/08/2020 03:39, David Blaikie via llvm-dev wrote:
> >> > Once you get past the nothrow default problems, then you probably have
> >> > to deal with the performance tradeoffs between the current strategy
> >> > for exception implementations (table based, etc) compared to the
> >> > tradeoffs for explicit error handling. You'd probably find that using
> >> > exceptions for/every/  error return would not be the right perf
> >> > tradeoff for many use cases where errors are at least somewhat common.
> >> > So you'd probably end up with a hybrid solution - some things using
> >> > exceptions where the failure is rare/going to be costly anyway
> >> > (stopping the process, showing an error to a user/asking for user
> >> > input about retrying, etc) and then still using explicit error
> >> > handling for other things.
> >>
> >> There's a second-order effect here too.  Everyone knows exceptions are
> >> slow, so everyone writes fast-path code with explicit error returns.  As
> >> a result, modern branch predictors are *really* good at predicting the
> >> no-error case.  A lot of the arguments about checked return values being
> >> slow date back to in-order processors where adding any instructions on
> >> the fast path was always a slowdown, even if they were not-taken
> branches.
> >>
> >> I did some experiments about a year ago with different hand-written
> >> assembly implementations of error handling control flow patterns and it
> >> was really hard to beat the checked return on recent Intel hardware.
> >> This was a microbenchmark, so didn't see effects from increased cache
> usage.
> >>
> >> There's also the fact that explicit error checking lets the programmer
> >> simplify the CFG explicitly.  If you're calling two functions that don't
> >> depend on any data flow between them, you can do something like:
> >>
> >> auto a = someFn();
> >> auto b = someOtherFn();
> >> if (!a || !b)
> >>         doSomeErrorHandlingStuffs();
> >>
> >> Transforming exception-driven code into this structure would be an
> >> invalid transform unless the compiler could prove that someOtherFn() has
> >> no observable side effects.
> >>
> >> David
> >>
> >> _______________________________________________
> >> LLVM Developers mailing list
> >> llvm-dev at lists.llvm.org
> >> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
> >
> > _______________________________________________
> > LLVM Developers mailing list
> > llvm-dev at lists.llvm.org
> > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200817/5164224b/attachment.html>


More information about the llvm-dev mailing list