Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

31–40 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#31

This post is poorly named. What it's saying is to avoid throwing exceptions for normal flow control, and just use them for exceptional cases (file not found, etc). Performance-sensitive code or not, exceptions for exceptional situations are not going to hinder the app's performance until the exceptional situation becomes common (unless your language does lots of exception setup work on the happy path - which most hav…

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.

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.

Re: Avoid exception throwing in performance-sensitive code

#32
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…

Thanks for this short and fine example of Java optimization. I still have a lingering loathing for the language based on the 2000s era marketing, but technically speaking there's rather a lot to like about the java ecosystem.

Re: Avoid exception throwing in performance-sensitive code

#33
post #17
post #13

Earlier quoted context omitted.

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... )

This blog post is specifically talking about 32-bit x86 C++ ABI, which was notoriously not zero-cost wrt exceptions even on success-only code paths. Lessons learned from that went into the Itanium C++ exceptions ABI based on static unwind maps, which has been adopted by basically every other architecture except for Windows, which has its own take (that is still zero-cost).

Huh? It’s for skylake which works imply x64 no? I doubt Daniel Lenore is running 32 but code given his background of focusing on applying AVX everywhere which requires x64. X64 uses itanium exception handling.

Re: Avoid exception throwing in performance-sensitive code

#35

I'm completely ignorant of the subject, but most surprising to me in his example was that the compiler didn't optimize away the inefficiency. Is there something about exception handling that makes it not get taken into account during optimization?

C++ exceptions and by extension Rust panics and C# exceptions (with caveats) involve stack unwinding as well as gathering of corresponding details and producing an exception object (C#). It is very expensive and using it as a normal condition in general is not the best idea. It is by definition cannot be optimized in a way that gets both good performance and keeps all existing side effects. That's why Rust's Result i…

I don't know how it is now, but back in the day C++ exceptions were so messy and non-performant that Google forbid their use in company C++ code. And they employed at least one member of the standards committee!

Re: Avoid exception throwing in performance-sensitive code

#36
post #29

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.

> Seems like a language design flaw that this is slow I think stack traces take up much of the time, including converting it [1]. Without them it could probably be a lot faster. Also see hashmash's post. But other than that, there is the logic issue, not using exceptions for normal flow control makes sense at least to me too independent of any performance questions. [1] For a Java example: https://ionutbalosin.com/20…

This is another reason why Common Lisp style condition system (where exception handlers can execute without unwinding the stack) just seems to work better. If you need the stack, get the stack, if you don't then just use handler-case. I really don't see the downside for any language that has anonymous function literals.

Re: Avoid exception throwing in performance-sensitive code

#37

I'm completely ignorant of the subject, but most surprising to me in his example was that the compiler didn't optimize away the inefficiency. Is there something about exception handling that makes it not get taken into account during optimization?

Exceptions in C++ have a ton of slow machinery, so available optimization is limited, and they are assumed to be... exceptional... so they are not generally speed-optimized. If you are expecting an occasional exception in a C++ program, std::optional with error checking will make you a lot happier.

On top of everything else, the behavior of exceptions when mixed with setjmp and longjmp is undefined, which can be a real problem if you're using any libraries that you haven't exhaustively analyzed to confirm that they don't use that feature. If memory serves, this includes things like the Lua interpreter (ETA: this used to be true. ca 2008, the Lua interpreter was changed so that it can conditionally compile to implement its try/catch via setjmp / longjmp or via C++ exceptions).

I generally consider exceptions in C++ harmful and avoid them if possible. It is not, unfortunately, always possible, as exceptions are the only way the language defines for constructors to fail.

Re: Avoid exception throwing in performance-sensitive code

#38
post #17

Earlier quoted context omitted.

This blog post is specifically talking about 32-bit x86 C++ ABI, which was notoriously not zero-cost wrt exceptions even on success-only code paths. Lessons learned from that went into the Itanium C++ exceptions ABI based on static unwind maps, which has been adopted by basically every other architecture except for Windows, which has its own take (that is still zero-cost).

Huh? It’s for skylake which works imply x64 no? I doubt Daniel Lenore is running 32 but code given his background of focusing on applying AVX everywhere which requires x64. X64 uses itanium exception handling.

OP was ambiguous, he means that the article "The Cost of Enabling Exception Handling" that was linked only applies to Windows x86, not to Windows AMD64 or the Itanium ABI.

The Itanium ABI and 64-bit Windows have near-zero cost when exceptions aren't thrown.

Re: Avoid exception throwing in performance-sensitive code

#39
This is a real problem with C++ exceptions - so much effort has gone into making them "free if you don't use them" that any time you do use them the perf is horrific.

This means even reasonable "control flow" cases like network errors for example can be terrible.

The more general case - and the real thing this article is complaining about - is the use of exceptions for normal control flow, which is something I agree is awful (aeons ago exceptions under .net's debugger were orders of magnitude slower than outside the debugger, but it meant that if you tried to debug logic involving an ANTLR generated parser your life was misery as - at least then - ANTLR used exceptions for parser control flow \o/)

Re: Avoid exception throwing in performance-sensitive code

#40

TIL that it's even possible to use exceptions instead of bog standard if statements. Would love to know why people would do this, though. Surely everyone masters if-else ssatements well before they even learn what a try-catch statement is!?

Using exceptions as control flow is a pattern I saw a lot at AWS in Java code.

It boiled down to it was simpler to abuse exceptions. You could instead return objects, but the code simply ended up being more to write.

At some point I tried to write things the 'proper' way by returning a Result object with the possible states, but it ended up being more complex than just throwing exceptions.

Post reply on HN