Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

71–80 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#71

Earlier quoted context omitted.

Exceptions are not the Error/Result type in Rust, they are panics. Which can be very expensive. But thankfully rust does them right and only uses them for unrecoverable errors.

You're right, what Rust gets right is standardized errors that aren't exceptions. In other languages you pretty much just return {success: false, message: ""} or whatever million combinations of this idea people sprinkled in the code. Having a single type handle this with a bunch of utility functions associated is great.

Not sure I'd agree. In my limited experience its a hassle with tons of different error types that need converting. You end up converting LibAError to LibBError, etc. Thats tedious so many people use `thiserror` or `anyhow`, where `anyhow` just hides the error types behind a `&dyn Anyhow::error` or whatnot. Since stable Rust lacks compile time or runtime introspection its difficult to figure out whats wrapped up in the dyn Trait without knowing ahead of time.

Inside a single library its not too bad. You get probably an enum type with some errors. But adding stacktraves or anything is a pain if possible at all.

Re: Avoid exception throwing in performance-sensitive code

#72
post #69

Earlier quoted context omitted.

Seems like a language design flaw that this is slow. Imo Rust got this right by making "exceptions" nothing special, just a data type holding an error which can be processed just as fast as anything else.

When exceptions are used for actual exceptional cases, that is both slower in the happy path (as you are having to add a ton of comparisons for the error case, vs. zero-cost exceptions as are now commonly deployed) and more verbose (though Rust has been working to mitigate this over the years, they still failed to realize the people who made the kind of error object popular also designed an abstraction for monads and…

Does OCaml use that exception like setup?

Re: Avoid exception throwing in performance-sensitive code

#73
post #13

Exceptions are great for exceptional conditions in performance-sensitive code. They provide a mechanism to move your error-handling code far out of the hot path. If you are expecting an occasional exception, they are terrible, and the C way of returning an error code is the way to go. In most cases, when you don't control what you expect, exceptions are not great. In a constrained embedded system or a trading system,…

Why would error-handling code impact performance? Besides, exceptions in C++ are known to have negative impacts on overall performance even if you don't use them. (see: https://preshing.com/20110807/the-cost-of-enabling-exception... )

If you use error codes, you always pay the cost (even cheap) of generating codes. If the function isn’t online able this might increase the stack usage, prevent inlining in the first place, etc.

With exceptions the error paths don’t even have to exist in your hot code.

The cost of exceptions when they aren’t thrown has come a long way since 2011 (the time of that post) in clang and gcc and I’m 99% sure is almost always zero now.

Re: Avoid exception throwing in performance-sensitive code

#75
post #69

Earlier quoted context omitted.

When exceptions are used for actual exceptional cases, that is both slower in the happy path (as you are having to add a ton of comparisons for the error case, vs. zero-cost exceptions as are now commonly deployed) and more verbose (though Rust has been working to mitigate this over the years, they still failed to realize the people who made the kind of error object popular also designed an abstraction for monads and…

Does OCaml use that exception like setup?

Yes and no: OCaml supports exceptions, uses them extensively in the standard library, and most guides encourage people to use them for exceptional cases (i.e. where an error is not an expected use case and the caller probably will just propagate the error rather than try to "handle" it... which I would assert is true for almost all error conditions: you should essentially never "handle" errors or "catch" exceptions), so it doesn't really need such syntax... and yet (apparently? I am not an OCaml developer, having only used it enough to demonstrate it for a class I taught a while back) it was finally introduced in a recent version ;P.

https://jobjo.github.io/2019/04/24/ocaml-has-some-new-shiny-...

Re: Avoid exception throwing in performance-sensitive code

#77

Not having exception is not having incorrect code i.e. code that does not throw. This is very hard to do in languages that naturally throws exception like Java or C/C++. If you have errors as part of the contract however...now you can be sure (or surer) that the function you are calling does not fail.

I think most serious C++ shops are probably compiling with -fno-exceptions.

Re: Avoid exception throwing in performance-sensitive code

#78
post #64

Earlier quoted context omitted.

IIRC, that's why Go errors don't come with stack traces by default, performance. I'll admit that this has enraged me on a few occasions when all I have to work with is a logged error message of strconv.ParseInt: parsing "": invalid syntax With no clues as to where the hell the error actually happened, so I have to start grepping the app's code, then the code of its dependencies, then the code of the dependencies' dep…

A stack trace would be helpful, but so would adding context to the error (when appropriate), instead of just bubbling it up indiscriminately. Of course, you can’t enforce this is dependencies, but at least tracking this to the first layer dependencies of your code should be fairly easy right? TBH, Go style errors seem more flexible if some care is put into using them, however they are extremely unhelpful if they are…

I agree very much. This was ultimately an ORM trying to convert a NULL to an int. An error message like "I was trying to load EntityX and got this error" would've been ideal.

It's a reasonably common issue with running Go apps, you're relying on the coder to make good decisions to give you useful insights.

Other ecosystems I've used err more in favour of the person running the thing - compare the more widespread Go logging libs to, say, Java, where the sysop has very fine-grained control if they need it.

Re: Avoid exception throwing in performance-sensitive code

#79
post #8

Different languages have different exception handing optimizations. A Java version of the example can run very slow or very fast, depending on how clever you are. When a new RuntimeException is thrown half the time, the example runs about 650 times slower when compared to a function which adds up the integers without using exceptions. If I define an exception subclass which doesn't fill in the stack trace, then it ru…

I must admit I use exceptions heavily for validation, e.g. checking input at API bounds. It makes the code fairly clean. I would imagine this is considered bad practice, but if there was no overhead this seems preferable over wrapping every call in some wrapper object. Any good links to further info on this?

validating with exceptions is good because it makes your code much cleaner to read. the cost benefits of reading and easy maintainability is extremely high

the example shows an extra time of 500nanoseconds when not throwing. this is 0.005 milliseconds. if your api takes more than 1ms then changing it to not throw will not be noticeable. even if the exception time cost was 10x higher and it took 0.05ms longer it would not be noticeable

Re: Avoid exception throwing in performance-sensitive code

#80
post #18

Earlier quoted context omitted.

C++ exceptions have a lot of machinery behind the scenes, and I don’t think anybody has ever really put the effort in to optimize pathological edge cases like this.

A lot of time and effort went into optimizing the most common case (no exceptions - ideally this should be no-cost) at the expense of everything else. It's very much by design.

Yes, 100%! This is exactly the machinery the makes it hard for a compiler to elide the exception.

I don’t think there’s anything in the standard that prevents the compiler from optimizing away said exception completely, but neither gcc or clang do so even in extremely trivial cases where the exception is identical to an if statement:

https://godbolt.org/z/8Y81bzo5s

Post reply on HN