Error codes are far slower than exceptions
lordsoftech.com
lordsoftech.com
> Error codes fail the test of “zero overhead for common cases; pay for play for uncommon cases”:
> There is calling convention impact. You now have two values to return (for non-void returning functions): the actual return value and the possible error. This burns more registers and/or stack space, making calls less efficient. Inlining can of course help to recover this for the subset of calls that can be inlined.
> There are branches injected into callsites anywhere a callee can fail. I call costs like this “peanut butter,” because the checks are smeared across the code, making it difficult to measure the impact directly. In Midori we were able to experiment and measure, and confirm that yes, indeed, the cost here is nontrivial. There is also a secondary effect which is, because functions contain more branches, there is more risk of confusing the optimizer.
> This might be surprising to some people, since undoubtedly everyone has heard that “exceptions are slow.” It turns out that they don’t have to be. And, when done right, they get error handling code and data off hot paths which increases I-cache and TLB performance, compared to the overheads above, which obviously decreases them.
That is in contrast to the code run during an exception, the destructors, which run all the damn time.
If you do make the effort to test your error-handling code, that is a significant expense on top of the reduced performance. Maintaining those tests as the code changes from under them is another expense.
The conclusion is that panics have less overheads than returning errors. I'm curious to actually hear more
In principal exceptions should be much faster than explicit error checking, and as in the article this is often the case. But modern CPUs are really good at speculating through conditional branches. To achieve "zero cost" exceptions compilers often have to do non-trivial code reordering and duplication to segregate the non-exception and exception branches. Sometimes this necessary rewriting can have a negative impact on performance.
So you could write code like
log_stuff(stuff); // on an error will panic.
var rtn = log_stuff(stuff);
if(rtn.error)
{
// handle error
}
try
{
log_stuff(stuff);
}
catch()
{
// jumps here on an error
}Slides and missing graph on slide 45 available at: https://sec.ch9.ms/ecn/events/GoingNative12/GN12Cpp11Style.p...
https://llvm.org/devmtg/2019-10/slides/Kumar-HotColdSplittin...
No, thank you. I'll keep my Result even if it was 200% slower.
Btw. Is there anything that prevents compiler from compiling error handling code the way exception throwing would be?
>Although it should fail gracefully, it does not need to be optimised for failure.
That case is easy to hit with compilers or annotation and such features. It is still one thing to optimize but impact is typically big.