> > 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 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 >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200817/80273633/attachment-0001.html>
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
> > 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>