Sign in to follow this  
Jaiminho

How slow are exceptions?

Recommended Posts

Jaiminho    184
I always hear people saying they can be slow for game programming, therefore being reasonable the choice of return codes. But how slow are they? I mean on code that is not close to being performance critical. That would be initializing some API subsystems, file loading, thread creation (not execution), and stuff like that.

Share this post


Link to post
Share on other sites
legalize    116
Premature optimization is the root of all evil, particularly when your premature optimization tosses by the wayside one of the tools that will make you a more productive and effective programmer.

Use exceptions until you've profiled your application and determined that exceptions cost too much.

Chances are you'll never encounter the point where the overhead matters. Is there some overhead? Yeah, but it varies from language to language and from compiler to compiler (there's more than one way to implement C++'s exception model, for instance).

Also, if you're using a framework like XNA, you can't avoid exceptions anyway.

Personally, I've never bought into the opinion that the cost of using exceptions outweighs the benefits they provide.

Share this post


Link to post
Share on other sites
Numsgil    501
Since exceptions should be relatively rare, and only occur when something EXCEPTIONal happens, something that wasn't expected. Performance should be the least of your worries in these cases.

Share this post


Link to post
Share on other sites
Antheus    2409
Exceptions are problematic in C++ due to somewhat inconsistent handling. There's nothing really wrong with them, there are just semi-valid reasons why many developers dislike their design as it is.

Performance penalty in C++ comes from increased code size, and prolog/epilog code that's inserted at certain places.

For all practical purposes, the hit due to this will be < several %, compared to code with *no* error handling whatsoever.

The only cost that does occur, is propagation of exceptions (creating exception class, populating the data, copying it as needed, destroying the object). But since those are exceptional situations, something is breaking down, so performance isn't your concern.

For managed languages (the likes of C#), the question is irrelevant. Exceptions are normal part of that language, and normalized impact doesn't matter - a better question would be, if you're generating thousands of exceptions per second, shouldn't you rethink your code flow?


All of the above applies only when and if exceptions are used for exceptional situations. It doesn't apply if they are abused for return codes, or even worse cases.

Share this post


Link to post
Share on other sites
Jaiminho    184
Quote:
Original post by SiCrane
Which programming language are you asking about?


Any programming language. C++, Java, C#... just wanted to know the general impact on the most used languages.

Got the answers I needed. Thanks.

Share this post


Link to post
Share on other sites
OrangyTang    1298
It's worth noting that exception handling in Java is quite fast (negligable overhead for entering a try/catch, and actually throwing and catching an exception is fast too), but the construction of the Exception object itself can be quite slow (relatively speaking). More precisely, constructing the stack trace to go inside the Exception object is what takes the time. Therefore if you must use an exception is a performance-critical section of the code, you can pre-create the exception object (say, at level load time) so that you can throw the exception without the speed hit.

Share this post


Link to post
Share on other sites
Antheus    2409
Quote:
Original post by OrangyTang
It's worth noting that exception handling in Java is quite fast (negligable overhead for entering a try/catch, and actually throwing and catching an exception is fast too), but the construction of the Exception object itself can be quite slow (relatively speaking). More precisely, constructing the stack trace to go inside the Exception object is what takes the time.


This is true for all languages.

Which is why it's important to use exceptions for exceptional things. Java frameworks tend to abuse them to no end. But that, as with any language, is not the problem of language itself.

Same considerations apply to everything else, C++ as well. When people say exceptions are slow in C++, they mean that after 6 months of optimization of every single aspect of the engine, they could squeeze additional 3% out by disabling them altogether.

Quote:
Therefore if you must use an exception is a performance-critical section of the code, you can pre-create the exception object (say, at level load time) so that you can throw the exception without the speed hit.


How many exceptions do you throw? Tens of thousands? Per level load? Shouldn't there be either zero or one (in which case you fail to load the level).

Share this post


Link to post
Share on other sites
OrangyTang    1298
Quote:
Original post by Antheus
Quote:
Original post by OrangyTang
It's worth noting that exception handling in Java is quite fast (negligable overhead for entering a try/catch, and actually throwing and catching an exception is fast too), but the construction of the Exception object itself can be quite slow (relatively speaking). More precisely, constructing the stack trace to go inside the Exception object is what takes the time.


This is true for all languages.

C++ exceptions don't even build a stack trace, how can that be the slow part? I think you're confusing this with the actual stack unwinding code, which in Java is completely different from building the stack trace within the Exception object itself.


Quote:
Quote:
Therefore if you must use an exception is a performance-critical section of the code, you can pre-create the exception object (say, at level load time) so that you can throw the exception without the speed hit.


How many exceptions do you throw? Tens of thousands? Per level load? Shouldn't there be either zero or one (in which case you fail to load the level).

You're missing the point. Yes, you probably shouldn't be throwing lots of exceptions during the normal flow of your code, but if for some reason that's unavoidable, then you can avoid the slow stack trace generation by using a pre-canned Exception object.

Share this post


Link to post
Share on other sites
SiCrane    11839
Quote:
Original post by Antheus
Quote:
Original post by OrangyTang
It's worth noting that exception handling in Java is quite fast (negligable overhead for entering a try/catch, and actually throwing and catching an exception is fast too), but the construction of the Exception object itself can be quite slow (relatively speaking). More precisely, constructing the stack trace to go inside the Exception object is what takes the time.


This is true for all languages.

Over generalize much? This is not the case for C++ exceptions under most exception implementations. Construction of the exception object is usually much faster than the time it takes for throwing and catching the exception; exception objects in C++ do not contain the stack trace. Taking Windows based C++ implementations as an example, which tend to use Structured Exception Handling as an implementation, actually throwing an exception has non-negligible overhead since that requires construction of the exception record (which is not part of the C++ exception object), checking for the presence of a debugger, search for a frame-based exception handler and then triggering the frame-based exception handler, which in C++ subsequently quite often re-raises the exception due to the joys of destruction of objects on the stack, which means it goes through the whole rigmarole all over again.

For that matter, that's not even the case for .NET languages with Microsoft's .NET implementation since .NET exceptions are implemented with the same underlying mechanism that C++ exceptions on the MS platform are implemented: SEH. On the plus side, with the .NET exceptions there tend to be fewer frame-based exception handlers that will just re-raise the exception. On the downside, .NET exceptions do contain the stack trace, so the cost of construction for the .NET exception object bulks up quite a bit more than the C++ exception object.

Share this post


Link to post
Share on other sites
Antheus    2409
Quote:
Over generalize much?


I missed that original quote included exception propagation as well.

Originally I referred to impact of exceptions-based code vs. the cost of what happens once the exception is thrown - which will inevitably be costly.

Share this post


Link to post
Share on other sites
Quote:
Original post by Numsgil
Since exceptions should be relatively rare, and only occur when something EXCEPTIONal happens, something that wasn't expected. Performance should be the least of your worries in these cases.

Well, an exception is something which is not the norm. It doesn't have to be exceptionnal - that's rather limiting.

Share this post


Link to post
Share on other sites
SiCrane    11839
Quote:
Original post by Antheus
I missed that original quote included exception propagation as well.

And you'd still be overgeneralizing because a) many languages have cheap exception object construction and b) it's possible to have an exception handler implementation where exceptions are quite fast by decreasing the performance of code in the general case such as SJLJ implementations.

Share this post


Link to post
Share on other sites
ZQJ    496
Well, I'm not sure about the implementation in detail, however I know the newest versions on MinGW actually come in two versions with different mechanisms:

1) SJLJ (as SiCrane said): uses C library functions setjmp/longjmp for control flow (involves calling setjmp whenever you enter a try block; might also involve calling setjmp whenever you construct a non-POD object stack because that would require the destructor to be called if an exception is thrown).

2) DWARF2: no performance penatly in regular code flow, uses debugging information (hence DWARF2) to figure out how to throw exceptions.

That's about all I know about mechanisms; Microsoft has its own mechanism (SEH - Structured Exception Handling, I have no idea how that works technically), but my point is I don't think there is one 'most common' mechanism.

Share this post


Link to post
Share on other sites
Jan Wassenberg    999
Quote:
Use exceptions until you've profiled your application and determined that exceptions cost too much.

Bwahahaa! There's nothing like failing to look before you leap; the end result may be something you'd like to change, but simply can't because there's way too much that depends on it.
Time for some due diligence beforehand: (http://www.on-time.com/ddj0011.htm; the numbers are somewhat dated, but quite interesting)


Program Code Size Time (no throws) Time (with throws)
XBench.c 4.6k 1392 ms 1362 ms
CPPBench.cpp 35.3k 1492 ms 71343 ms


That's the kind of difference I'd like to know beforehand, while it's not yet too late.

Quote:
Since exceptions should be relatively rare, and only occur when something EXCEPTIONal happens, something that wasn't expected. Performance should be the least of your worries in these cases.

Would that it were this simple, but both of the common ways of implementing C++ exceptions have serious overhead (prolog/epilog, or large tables) regardless of whether the exceptions actually fly or not.
Let's have a look at the way things work under the hood:
http://www.microsoft.com/msj/0197/exception/exception.aspx
http://blogs.msdn.com/cbrumme/archive/2003/10/01/51524.aspx
http://www.codeproject.com/cpp/exceptionhandler.asp

And then read this interesting anecdote/opinion piece:
http://www.seventhstring.com/resources/exceptionfree.html

Personally, I like RAII and find automatic cleanup without bailout ladders convenient. Even toss in a few exceptions when things happen where the only thing you can do is a controlled crash&burn (machine-check exception, out of memory*). But: EOFException et al. really are the kind of goto-travesty people are so happy to jump on, yet even worse, because they may end up jumping ANYWHERE. (heh, that's not going to bode well for static analysis..)


* this probably needs expanding upon. You might ask: why not just roll back the current transaction or whatever if there's not enough memory to do it? That may work from the perspective of a single routine, but I bet not all code will have been tested for this and your app WILL die. Also, the fact that memory is exhausted probably indicates a bug somewhere else (leak, overflow/incorrect calculation). Some go further and say: there should be no runtime allocations at all, but that may be a bit too extreme for most projects.

Share this post


Link to post
Share on other sites
mfawcett    373
Quote:
Original post by Jan Wassenberg
Quote:
Use exceptions until you've profiled your application and determined that exceptions cost too much.

Bwahahaa! There's nothing like failing to look before you leap; the end result may be something you'd like to change, but simply can't because there's way too much that depends on it.
Time for some due diligence beforehand: (http://www.on-time.com/ddj0011.htm; the numbers are somewhat dated, but quite interesting)


Program Code Size Time (no throws) Time (with throws)
XBench.c 4.6k 1392 ms 1362 ms
CPPBench.cpp 35.3k 1492 ms 71343 ms



Umm, you do realize that those time differences are showing how long it takes to throw 0 exceptions, vs throwing and catching 1,000,000 exceptions?

Look at the code...

Share this post


Link to post
Share on other sites
Jan Wassenberg    999
Quote:
Umm, you do realize that those time differences are showing how long it takes to throw 0 exceptions, vs throwing and catching 1,000,000 exceptions?

No, I do not. Look at example 2 to see that XBench.c throws and catches "exceptions" much like CPPBench.cpp; the difference is that it uses a home-brewed method akin to SEH.
Or maybe you have chosen a narrow definition of "exception"; if that's the case, let's not bandy semantics.

Share this post


Link to post
Share on other sites
iMalc    2466
Quote:
Original post by bulgurmayo
Anybody knows a good link describing in details how C++ exceptions are implemented for the most common compiler/platform.
Just this week I watched a Microsoft video at work, about how exception handling was implemented. On WIN32 functions with exception information are added-to / removed-from a linked list upon entry and exit. This means that simply using exception handling adds a certain overhead, but throwing is not as costly as it might otherwise be.
On x64 each function has a table containing the object lifecycle information and is indexed by the instruction pointer. Simply using exceptions is very cheap, but throwing them is considerably more expensive.
.NET is different again, but they didn't go into the details.
Sorry I don't have a link to it.

Share this post


Link to post
Share on other sites
legalize    116
Quote:
Original post by iMalc
Just this week I watched a Microsoft video at work, about how exception handling was implemented. On WIN32 functions with exception information are added-to / removed-from a linked list upon entry and exit.


What exactly is meant by "functions with exception information"?

Functions that throw?

Functions that catch?

Functions that have an exception signature?

*Every* function?

Do you have a link to the video? (Was it on Channel 9?)

Share this post


Link to post
Share on other sites
Ahnfelt    176
Well, if you use exceptions like most people do in imperative languages, the amount of exceptions thrown during normal execution of the program is probably below 100 (likely zero). Then the amount of time it takes to throw these would have to be absurdly high for it to be noticeable. The interesting part is then how much it slows your program down when you're not throwing, which has been discussed already.

I don't really see any performance reason not to use exceptions. And in the OP's case, it's not even being used in performance critical code...

Share this post


Link to post
Share on other sites
Antheus    2409
Quote:
Original post by Jan Wassenberg
Quote:
Umm, you do realize that those time differences are showing how long it takes to throw 0 exceptions, vs throwing and catching 1,000,000 exceptions?

No, I do not. Look at example 2 to see that XBench.c throws and catches "exceptions" much like CPPBench.cpp; the difference is that it uses a home-brewed method akin to SEH.
Or maybe you have chosen a narrow definition of "exception"; if that's the case, let's not bandy semantics.


I'd just like to point out the following:
Quote:
Code sizes and benchmark results for C and C++ exception-handling compiled with Borland C++ Builder 4.0, run under Windows NT


IIRC, that version was released in '99. Or 8-9 years ago, which makes it almost as relevant as VC6.

I would however be interested into someone re-running the same benchmarks on today's compiler. Preferably, without modification.

It's commonly considered that MVS2003 was first step in the right direction, and that MVS2005 is the first commonly accepted "good" C++ compiler outside of gcc.

Share this post


Link to post
Share on other sites
MaulingMonkey    1728
Quote:
Quote:
Use exceptions until you've profiled your application and determined that exceptions cost too much.

Bwahahaa! There's nothing like failing to look before you leap; the end result may be something you'd like to change, but simply can't because there's way too much that depends on it.

That sounds more like an argument for profiling something before adding an orgasm of dependencies, or better yet, not doing so -- keeping your code sanely decoupled, avoiding such a situation in the first place. Of course, if you're working at developer hell, and for some god forsaken reason feel the need to stay there, where all your coworkers are basically conspiring against you personally and eschewing all common sense WRT sane coding practices, then yes, I suppose an avoidance policy like that would be good approach. Personally, I'd prefer to deal with whatever issues are preventing me from jumping ship, and prevent them from happening again.

Here's some slightly less dated numbers from Q4 2006.

A couple highlights from VS2k5 release build on a 2.4Ghz processor:
~87 thousand exceptions thrown and caught/second max (0.011 msec/exception thrown and caught in a local scope)
~1.6 billion individual try blocks/second (max)

Quote:
But: EOFException et al. really are the kind of goto-travesty people are so happy to jump on, yet even worse, because they may end up jumping ANYWHERE. (heh, that's not going to bode well for static analysis..)

Error codes can be handled ANYWHERE too. Even worse, they can be silently forgotten and ignored without the slightest shred of code evidencing it. I fail to see how this alternative isn't 100x worse.

Certainly, where local error handling is sane and viable, exceptions make no sense. This may be what you were getting at with your "EOFException et al.". However, there's a lot of failure conditions which end up as a "controlled crash and burn" up to a given scope. An EOF inside 3 levels of indentation in the parsing of a C++ file would qualify, crashing and burning all the way out to the end of that translation unit.

Player pingout? Propagating error codes from possibly hundreds of individual socket read and write positions by hand is only going to make for horribly jumbled code for the most part. Crash and burn out to the player I/O iteration loop.

There are plenty of non-app-fatal exceptional circumstances which exceptions are appropriate for. I'd argue all of these situations are going to be places where the overhead of exception handling is entirely acceptable too.

Share this post


Link to post
Share on other sites
Jan Wassenberg    999
Quote:
IIRC, that version was released in '99. Or 8-9 years ago, which makes it almost as relevant as VC6.

Yes and no. BCB was worlds better than the VC6 travesty, and the mechanism of how exceptions are *thrown* remains unchanged AFAICS.

Quote:
It's commonly considered that MVS2003 was first step in the right direction, and that MVS2005 is the first commonly accepted "good" C++ compiler outside of gcc.

huh? ICC isn't "commonly accepted to be good"? Comeau is of course the gold standard for conformance, and Watcom has its fans.


[q]keeping your code sanely decoupled, avoiding such a situation in the first place[/q]
Um, no. No amount of decoupling is going to change the fact that going from exception handling to error codes or vice versa is very hard.

From the other thread:
Quote:
Note: The timing mechanism used was boost::timer, I'm uncertain how coarsely grained it is.

FYI, it's good to about 10ms on Windows.

Quote:
~1,686,340,640 entries/leaves from try blocks/second

Since you mention a 2.4 GHz processor, your results indicate that each operation takes 1.5 clocks. There's no way in hell that this is realistic or even remotely imaginable. C++ exceptions are based on SEH, which involves a kernel transition, which by itself burns a few hundred cycles. I bet you're only measuring the loop and increment.

Quote:
I realized there was no signal to be found in the noise

Correct! The compiler is clearly optimizing out the throw/catch.
When presenting microbenchmarks, you must look at the asm code.


Quote:
Error codes can be handled ANYWHERE too.

Yes, but existing static analysis tools can see where.

Quote:
Even worse, they can be silently forgotten and ignored without the slightest shred of code evidencing it.
Alexandrescu has a solution :)



// in a rush, got to head to work..

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this