The cost of throwing exceptions

After read­ing Ayende’s post today, it got me think­ing, just exact­ly what’s the cost of a try/catch block and more impor­tant­ly what’s the cost of throw­ing excep­tions.

Like Ken Egozi men­tioned in the com­ments, I too believe the test was unfair as the try/catch block was applied to the top lev­el code as opposed to each iter­a­tion. How­ev­er, based on every­thing I know about excep­tion in .Net I’d imag­ine what­ev­er per­for­mance cost will be asso­ci­at­ed with throw­ing the excep­tions rather than sim­ply try­ing to catch them. With that in mind, I decid­ed to car­ry out my own set of tests to try out three sim­ple cas­es:

  1. 10000 invo­ca­tions of a blank Action del­e­gate, this should be con­sid­ered as the ‘base line’ of the cost of iter­at­ing through the inte­gers 1 – 10000 and what­ev­er cost of invok­ing a del­e­gate
  2. 10000 invo­ca­tions of a blank Action del­e­gate INSIDE a try-catch block, this should indi­cate the addi­tion­al cost of try­ing to catch an excep­tion when com­pared with 1.

  3. 10000 invo­ca­tions of an Action del­e­gate that throws an excep­tion INSIDE a try-catch block, this should indi­cate the addi­tion­al cost of throw­ing and catch­ing the excep­tion when com­pared with 2.

Each test of 10000 invo­ca­tions are repeat­ed 100 times (no debug­ger attached) and here are the aver­age exe­cu­tion times in mil­lisec­onds:

image

For any­one who wants to try it out them­selves, I’ve post­ed the code on github here.

As you can see, wrap­ping a call inside a try-catch block doesn’t add any mean­ing­ful cost to how fast your code runs, although there’s a mea­sur­able dif­fer­ence when excep­tions are repeat­ed­ly thrown but 300 mil­lisec­onds over 10k excep­tions equates to over 30k excep­tions per sec­ond, which dare I say is more than any­one would ratio­nal­ly expect from a real-world appli­ca­tion!

Anoth­er thing to con­sid­er is the impact the stack trace depth has on the cost of throw­ing excep­tions, to sim­u­late that I put togeth­er a sec­ond test which exe­cutes a method recur­sive­ly until it reach­es the desired lev­el of recur­sion then throws an excep­tion. Each test per­forms this recur­sion 1000 times, and repeat­ed over 100 times to get a more accu­rate read­ing. Here are the aver­age exe­cu­tion times in mil­lisec­onds:

image

Good news is that the cost of going deep­er before throw­ing an excep­tion seems to be lin­ear as opposed to expo­nen­tial­ly.

Closing thoughts…

Before I go I must make it clear that excep­tions are nec­es­sary and the abil­i­ty to throw mean­ing­ful excep­tions is a valu­able tool for us devel­op­ers in order to val­i­date busi­ness rules and com­mu­ni­cate any vio­la­tions to the con­sumers of our code. As far as these per­for­mance tests go, they’re mere­ly intend­ed to make you aware that there IS a cost asso­ci­at­ed with throw­ing excep­tion and not to men­tion a lit­tle bit of fun!

Ulti­mate­ly, throw­ing excep­tions means doing work, and doing work takes CPU cycles, so you real­ly shouldn’t be sur­prised to see that there’s a cost for throw­ing excep­tions. Per­son­al­ly, I take my excep­tions seri­ous­ly, for all the projects I have worked on I have tak­en the time to define a set of clear and mean­ing­ful excep­tions, each with a unique error code ;-)

The ques­tion you got­ta ask your­self is this – would you trade 0.03ms in excep­tion­al cas­es for clean­er, more con­cise code that lets you com­mu­ni­cate errors to users more clear­ly and help you debug/fix bugs much more eas­i­ly? Know­ing that you end up pay­ing for it in terms of code main­te­nance, debug­ging time any­way, I sure as hell knows which one I’d pre­fer! Remem­ber, avoid pre­ma­ture opti­miza­tion, pro­file your appli­ca­tion, tar­get the real prob­lems and then opti­mize instead.