Live data from Hacker News

Current hardware trends make C++ exceptions harder to justify

open-std.org

251–260 of 516 posts

Re: Current hardware trends make C++ exceptions harder to justify

#251
post #191

I find this paper quite unconvincing. Exceptions are exceptional so in principle it doesn't matter (within reason) how long it takes to throw one as long as it costs nothing not to do so. So measuring the cost of repeated throws IMHO doesn't cast light on any useful case, and the approaches that add runtime cost for the path not taken, even Herb Sutter's, are not acceptable. His code transformation example is simply…

The problem is that in many practical situations you don’t know which situation is “exceptional”. If you write a jpeg-processing service, it’s intuitive to raise an exception on a malformed jpeg, but there’s no guarantee that only 1% of the jpegs users upload to the service are malformed. In other words, we treat exceptions as exceptions from our code expects , not what’s statistically unlikely in the input space, wh…

> If you write a jpeg-processing service, it’s intuitive to raise an exception on a malformed jpeg (..)

Not really. Having to parse a malformed doc is not an exceptional situation: it's a basic use case, and one which is very close to the happy path.

Re: Current hardware trends make C++ exceptions harder to justify

#252

Earlier quoted context omitted.

It would. On the other hand multiprocessing with explicitly shared memory could be a fast (but potentially painful) workaround.

That could make sense for processes, which would also get around the exception unwind lock, but I don't know how that would work with every thread moved into a separate VM.

Of course. Using VMs here would very deep into overengineering territory.

Re: Current hardware trends make C++ exceptions harder to justify

#253

Earlier quoted context omitted.

The "exceptions should be exceptional aka rare" line sounds aspirational, but I wonder how true it is if you survey the general landscape of actual libraries.

Probably not that rare to use exceptions but I imagine it is very rare to use exceptions for normal flow control - that is, to continue execution after an exception. It's a common pattern in Python but not C++. I've done it exactly once and I ended up removing it because it makes debugging exceptions that you care about really annoying.

> but I imagine it is very rare to use exceptions for normal flow control - that is, to continue execution after an exception

Exceptions are at least a very central part of the normal flow control of parser combinator libraries.

Re: Current hardware trends make C++ exceptions harder to justify

#254

Earlier quoted context omitted.

All of this hinges around the global lock, although I'm not sure what you mean exactly. Are you talking about memory allocation, a lock that exception handling takes or something else?

The main problem is the unwinding lock. Memory allocation is a bit unfortunate, too, but much less so. Note that I am trying to fix the unwinding problem, I have submitted a patch to libunwind to eliminate the contention during unwinding: https://reviews.llvm.org/D120243 It require application support, unfortunately, as there is currently no way that libunwind can figure out if a shared library has been added or remo…

Thanks for that patch - I'll watch this with great interest.

Is there a problem if dynamic libraries invoke dlopen/dlclose they also need to call the sync function - correct?

I'm asking because we've developed a Common Lisp implementation that interoperates with C++ and it uses exception handling to unwind the stack (https://github.com/clasp-developers/clasp.git). We hit this global lock in unwinding problem a lot - it causes us a lot of grief.

Re: Current hardware trends make C++ exceptions harder to justify

#255
post #251

Earlier quoted context omitted.

The problem is that in many practical situations you don’t know which situation is “exceptional”. If you write a jpeg-processing service, it’s intuitive to raise an exception on a malformed jpeg, but there’s no guarantee that only 1% of the jpegs users upload to the service are malformed. In other words, we treat exceptions as exceptions from our code expects , not what’s statistically unlikely in the input space, wh…

> If you write a jpeg-processing service, it’s intuitive to raise an exception on a malformed jpeg (..) Not really. Having to parse a malformed doc is not an exceptional situation: it's a basic use case, and one which is very close to the happy path.

Your opinion being that you should not use exceptions in that type of case. In which cases should you use exceptions?

Re: Current hardware trends make C++ exceptions harder to justify

#256
post #191

I find this paper quite unconvincing. Exceptions are exceptional so in principle it doesn't matter (within reason) how long it takes to throw one as long as it costs nothing not to do so. So measuring the cost of repeated throws IMHO doesn't cast light on any useful case, and the approaches that add runtime cost for the path not taken, even Herb Sutter's, are not acceptable. His code transformation example is simply…

But there's a design pattern where nearly everything is returned as an exception. It's the normal path in some code. I deplore that - its side-effects writ large. But those that use it, find it reasonable and sensible. It's become hard to distinguish right and wrong when it comes to CPU optimization. Different versions of the 'same' CPU can have wildly different sweet spots.

[deleted]

Re: Current hardware trends make C++ exceptions harder to justify

#257
post #191

I find this paper quite unconvincing. Exceptions are exceptional so in principle it doesn't matter (within reason) how long it takes to throw one as long as it costs nothing not to do so. So measuring the cost of repeated throws IMHO doesn't cast light on any useful case, and the approaches that add runtime cost for the path not taken, even Herb Sutter's, are not acceptable. His code transformation example is simply…

But there's a design pattern where nearly everything is returned as an exception. It's the normal path in some code. I deplore that - its side-effects writ large. But those that use it, find it reasonable and sensible. It's become hard to distinguish right and wrong when it comes to CPU optimization. Different versions of the 'same' CPU can have wildly different sweet spots.

> But there's a design pattern where nearly everything is returned as an exception. It's the normal path in some code.

The problem isn’t that C++ exceptions are slow when used the way the compiler expects. The problem is a mismatch between how C++ expects you to use the feature, and how people are actually using the feature.

I can’t find the story now, but I read about this happening with Ruby on Rails. Someone dug into why rails was so slow at Twitter, and found the way rails was looping through an array was that it would loop unbounded, and catch and discard the array out of bounds exception at the end of the loop. Whenever Ruby throws, it allocates 10k of memory and fills it with all sorts of information for debugging - including a full stack trace. And it was doing this work in the background every time someone iterated through an array. Fixing this resulted in a massive speed up at Twitter, and presumably across the entire rails ecosystem.

I saw the same thing at (big tech company) a decade or so ago. I was working on a project which used GWT. We brought some people in to help us optimize, because the program was too slow. The first thing they found was that the JS VM was spending most of its time in the exception handler for some reason. Turned out one of our engineers had a habit of using throw & catch as a way to do multi level returns in complex code in Java. But the exception was being converted to a javascript exception by GWT. And javascript exceptions are (were?) super slow.

Y’all gotta stop using exceptions like that. I know it feels clever. But in most programming languages, using exceptions for control flow will kill your performance.

Re: Current hardware trends make C++ exceptions harder to justify

#258

Earlier quoted context omitted.

Why am I "not supposed to use exceptions"? I don't understand why exception should be used when errors occur occasionally, or when they occur 50,000/sec. They are a control flow method for when errors occur.

For the same reason you may want to use or not use memory allocations when doing something 1 time per second or 1 million times per second. Performance is not amenable to arguments about degree (especially when talking about this many orders of magnitude in degree).

But again, the question is whether exceptions need to be slow.

If I'm writing a string_to_int function today I would return an optional (or some Either variant). But if exceptions were cheap I would use them. If I'm catching an exception in the context of immediate caller and the compiler inlines the calle, it ought to be able to optimise the exceptional path away. But it doesn't happen.

Re: Current hardware trends make C++ exceptions harder to justify

#259
post #251

Earlier quoted context omitted.

> If you write a jpeg-processing service, it’s intuitive to raise an exception on a malformed jpeg (..) Not really. Having to parse a malformed doc is not an exceptional situation: it's a basic use case, and one which is very close to the happy path.

Your opinion being that you should not use exceptions in that type of case. In which cases should you use exceptions?

When something happens that violates your assumptions about your own program's behavior, throwing it into a state where it doesn't know what happens next. Kind of like a panic.

Re: Current hardware trends make C++ exceptions harder to justify

#260

Earlier quoted context omitted.

Because that meshes so well with copy and move ctors, const and reference members, or inheritance.

It meshes well with move ctors at least, since objects need a "dead state" they can be put into when moved from.

This is incorrect. You are not supposed to make any assumptions about the state of an object that has been destructed or moved from. A “dead state” would still be a state, whereas a “dead object” should be thought of as having no state at all, i.e. not being an object any longer.
Post reply on HN