3

I asked a question about exceptions and I am getting VERY annoyed at people saying throwing is slow. I asked in the past How exceptions work behind the scenes and I know in the normal code path there are no extra instructions (as the accepted answer says) but I am not entirely convinced throwing is more expensive then checking return values. Consider the following:

{
    int ret = func();
    if (ret == 1)
        return;
    if (ret == 2)
        return;
    doSomething();
}

vs

{
    try{
        func();
        doSomething();
    }
    catch (SpecificException1 e)
    {
    }
    catch (SpecificException2 e)
    {
    }
}

As far as I know there isn't a difference except the ifs are moved out of the normal code path into an exception path and an extra jump or two to get to the exception code path. An extra jump or two doesn't sound like much when it reduces a few ifs in your main and more often run) code path. So are exceptions actually slow? Or is this a myth or an old issue with old compilers?

(I'm talking about exceptions in general. Specifically, exceptions in compiled languages like C++ and D; though C# was also in my mind.)

Community
  • 1
  • 1
  • 8
    I'm reluctant to post this as an answer, but its probably not the extra jumps, but I'm betting is has something to do with capturing the currently executing stack frame which causes the slowdown. Have you ever used "new System.Diagnostics.StackTrace()"? Very slow. – Juliet Nov 20 '09 at 15:38
  • 1
    Juliet: To bad someone added the C# tag and ruined what people thought i was asking. But i think your right. But thats in the case of C#, hopefully more people will read this question and answer regarding C++ –  Nov 20 '09 at 15:58
  • @Juliet - you don't need to capture a stack trace to unwind the exception stack. Furthermore most of the time in StackTrace() is going to be symbol lookup. – Aaron Nov 20 '09 at 16:00
  • 1
    Is the problem simply not the object creation time and reflection needed to build it? Surely its better to test against a simple value rather than test against a (possibly) large exception object? Using Exceptions instead of a simple if statement smells bad to me. +1 for raising the question though and not just accepting the Dogma :) – Pete Duncanson Nov 20 '09 at 16:57

10 Answers10

8

Okay - I just ran a little test to make sure that exceptions are actually slower. Summary: On my machine a call w/ return is 30 cycles per iteration. A throw w/ catch is 20370 cycles per iteration.

So to answer the question - yes - throwing exceptions is slow.

Here's the test code:

#include <stdio.h>
#include <intrin.h>

int Test1()
{
    throw 1;
//  return 1;
}


int main(int argc, char*argv[])
{
    int result = 0;
    __int64 time = 0xFFFFFFFF;
    for(int i=0; i<10000; i++)
    {
        __int64 start = __rdtsc();
        try
        {
            result += Test1();
        }
        catch(int x)
        {
            result += x;
        }
        __int64 end = __rdtsc();
        if(time > end - start)
            time = end - start;
    }

    printf("%d\n", result);
    printf("time: %I64d\n", time);
}

alternative try/catch written by op

try
{
        if(Test1()!=0)
                result++;
}
catch(int x)
{
        result++;
Aaron
  • 9,123
  • 5
  • 40
  • 38
  • Yes! finally someone with a real test and real answer. –  Nov 20 '09 at 16:44
  • I wonder what its doing... But this at least tells me its a huge hit. –  Nov 20 '09 at 17:36
  • Here is another in C#. Its also vastly slower. I wonder why expections are so different from return values. http://www.pastie.org/707883 –  Nov 20 '09 at 17:47
  • I've found that having the debugger attached to my C# programs can vastly change the results of benchmarking. I assume C programs can be subject to the same effect, so I hope you ran your benchmark with the debugger off. – Greg Nov 20 '09 at 20:19
  • @Greg - I did run it with the debugger off... Running under the debugger gets you 10,000 first chance exceptions you have to ignore. – Aaron Nov 20 '09 at 21:04
  • I ran it with the debugger off as well. I also notice the first exception and the second takes different amount of time (i assume its related to caching or in C# case the JIT) so i made sure the loop ran at least once before testing. –  Nov 20 '09 at 22:38
5

I don't know exactly how slow it is, but throwing an exception that already exists (say it was created by the CLR) is not much slower, cause you've already incurred the hit of constructing the exception. ... I believe it's the construction of an exception that creates the majority of the addtional performance hit ... Think about it, it has to create a stack trace, (including reading debug symbols to add lines numbers and stuff) and potentially bundle up inner exceptions, etc.

actually throwing an exception only adds the additional code to traverse up the stack to find the appropriate catch clause (if one exists) or transfer control to the CLRs unhandled Exception handler... This portion could be expensive for a very deep stack, but if the catch block is just at the bottom of the same method you are throwing it in, for example, then it will be relatively cheap.

Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
  • At least in C++ this is absolutely wrong. See my answer for an example - I'm throwing '0' -- that's about as cheap a construction as you can get. As far as reading debug symbols I would be really suprised if it did more than store the trace locations and deal with symbols lazily. – Aaron Nov 20 '09 at 21:06
  • @Aaron, I'm not a C++ expert by any means, but in yr code snippet, using the throw(1) statement, isn't it constructing an exception object? Even though you're only throwing(1), doesn't the compiler have to roll up that integer value into an Exception of some type? When you use the return value in the other case, are you not commenting put the throw(1) line? Just for grins, (I wonder what results will be?) - try constructing an exception without throwing it, return an op code to caller, and see how long that takes.. – Charles Bretana Nov 20 '09 at 23:28
  • That would isolate the portion of the performance hit due to construction of the exception frpm the hit due to throwing it ... – Charles Bretana Nov 20 '09 at 23:33
  • Ok, from msdn. "3.If an exception is thrown during execution of the guarded section or in any routine the guarded section calls (either directly or indirectly), an exception object is created from the object created by the throw operand. (This implies that a copy constructor may be involved.) " Doesn't this meant that yr line reading throw(1) causes a constructor to be executed which instantiates an Exception Object? – Charles Bretana Nov 20 '09 at 23:40
3

If you are using exceptions to actually control the flow it can be a pretty big hit.

I was digging in some old code to see why it ran so slow. In a big loop instead of checking for null and performing a different action it caught the null exception and performed the alternative action.

So don't use exceptions for things they where not designed to do because they are slower.

ElGringoGrande
  • 638
  • 6
  • 13
2

In C# raising exceptions do have an every so slight performance hit, but this shouldn't scare you away from using them. If you have a reason, you should throw an exception. Most people who have problems with using them cite the reason being because they can disrupt the flow of a program.

Really if your reasons for not using them is a performance hit, your time can be better spent optimizing other parts of your code. I have never run into a situation where throwing an exception caused the program to behave so slowly that it had to be re-factored out (well the act of throwing the exception, not how the code treated it).

Thinking about it a little more, with all that being said, I do try and use methods which avoid throwing exceptions. If possible I'll use TryParse instead of Parse, or use KeyExists etc. If you are doing the same operation 100s of times over and throwing many exception small amounts of inefficiency can add up.

kemiller2002
  • 113,795
  • 27
  • 197
  • 251
2

Use exceptions and generally anything without worrying about performance. Then, when you are finished, measure the performance with profiling tools. If it's not acceptable, you can find the bottlenecks (which probably won't be the exception handling) and optimize.

Tamás Szelei
  • 23,169
  • 18
  • 105
  • 180
  • Someone went on a downvote-fury, or they haven't heard about premature optimization? – Tamás Szelei Nov 23 '09 at 10:06
  • Rewriting an application that uses return codes to use exceptions or visa-versa requires significant effort. It's really a decision that should be made in advance as it's so difficult to change later. – JoeG Dec 30 '09 at 14:00
  • That's genuinely a new perspective for me, thanks. I doubt that exceptions would be the bottlenecks in general though. – Tamás Szelei Dec 30 '09 at 19:17
1

tl;dr IMHO, Avoiding exceptions for performance reasons hits both categories of premature and micro- optimizations. Don't do it.

Ah, the religious war of exceptions.

The various types of answers to this are usually:

  • the usual mantra (a good one, IMHO): "use exceptions for exceptional situations" (IOW, not part of "normal" code paths).
    • If your normal user paths involved intentionally using exceptions as a control-flow mechanism, that's a smell.
  • tons of detail, without really answering the original question
  • someone pointing at microbenchmarks showing that something like i/j with j == 0 is 10x slower catching div-by-zero than checking j == 0
  • pragmatic answer of how to approach performance for apps in general
    • usually along the lines of:
    • make perf goals for your scenarios (ideally working with customers)
    • build it so it's maintainable, readable, and robust
    • run it and check perf of goal scenarios
    • if a set of scenarios aren't making goal, USE A PROFILER to tell you where your time is being spent and go from there.
    • IOW, any perf changes, especially micro-optimizations like this, made without profiling data driving that decision, is typically a huge waste of time.

Keep in mind that your perf wins will typically come from algorithmic changes (adding an index to a table to avoid table scans, moving something with large n from O(n^3) to O(n ln n), etc.).

More fun links:

nobody
  • 19,814
  • 17
  • 56
  • 77
James Manning
  • 13,429
  • 2
  • 40
  • 64
1

Yes. Exceptions make your program slower in C++. I created an 8086 CPU Emulator a while back. In the code I used exceptions for CPU Interrupts and Faults. I made a little test case of a big complex loop that ran for about 2 minutes doing emulated opcodes. When I ran this test through a profiler, my main loop was making a significant amount of calls to an "exception checker" function of gcc(actually there were two different functions related to this. My test code only threw one exception at the end however.) These exception functions were called in my main loop I believe every time(this is where I had the try{}catch{} part.). The exception functions cost me about 20% of my runtime speed.(the code spent 20% of it's time in there). And the exception functions were also the 3rd and 4th most called functions in the profiler...

So yes, using exceptions at all can be expensive, even without constant exception throwing.

Earlz
  • 62,085
  • 98
  • 303
  • 499
0

If you want to know how exceptions work in Windows SEH, then I believe this article by Matt Pietrik is considered the definitive reference. It isn't light reading. If you want to extend this to how exceptions work in .NET, then you need to read this article by Chris Brumme, which is most definitely the definitive reference. It isn't light reading either.

The summary of Chris Brumme's article gives a detailed explanation as to why exception are significantly slower than using return codes. It's too long to reproduce here, and you've got a lot of reading to do before you can fully understand why.

Greg Beech
  • 133,383
  • 43
  • 204
  • 250
0

Part of the answer is that the compiler isn't trying very hard to optimize the exceptional code path.

  • A catch block is a very strong hint to the compiler to agressively optimize the non-exceptional code path at the expense of the exceptional code path. To reliably hint to a compiler which branch of an if statement is the exceptional one you need profile guided optimization.

  • The exception object must be stored somewhere, and because throwing an exception implies stack unwinding, it can't be on the stack. The compiler knows that exceptions are rare - so the optimizer isn't going to do anything that might slow down normal execution - like keeping registers or 'fast' memory of any kind available just in case it needs to put an exception in one. You may find you get a page fault. In contrast, return codes typically end up in a register (e.g. EAX).

JoeG
  • 12,994
  • 1
  • 38
  • 63
-1

it's like concating strings vs stringbuilder. it's only slow if you do it a billion times.

wefwfwefwe
  • 3,382
  • 1
  • 21
  • 24
  • i am asking the why. I am pretty sure it ISNT like concating strings –  Nov 20 '09 at 15:30
  • because it has to unwind the stack, create the exception object, compare to the list of catchable exceptions etc. Obviously i'm comparing the effects of concating strings, not literally what happens – wefwfwefwe Nov 20 '09 at 16:02
  • btw i didnt -1 you. unwinding would happen when leaving the function via if(cond) return; compare the list sounds like many ifs of a switch. So i dont see the difference yet. –  Nov 20 '09 at 16:09
  • don't worry i get -1d all the time ;) i get your point about the stack. i'd argue comparing exceptions is more heavyweight than comparing ints. But IMO it's unlikely to ever make a significannt difference in the real world. – wefwfwefwe Nov 21 '09 at 15:20