Exceptions

Optimizing exceptions

You might often hear about exceptions being slow. For this reason they are usually shunned in the embedded space, and sometimes even for regular desktop/server programming. What makes them slow? When one is thrown it needs to search through the call stack for exception handlers.

I guess I don’t understand this line of thinking. For one, exceptions are meant for exceptional situations: things you don’t expect to happen under normal operation. Code that uses exceptions will run just as fast (or maybe even faster) as code without, until you throw one. These exceptional situations are truely rare, so I usually don’t care if they do happen to run slower.

A compiler can actually use exceptions to optimize your code. Consider this inefficient (but typical) pseudo-C:

int dosomething(void) {
   /* do something A */
   if(err) return -1;

   /* do something B */
   if(err) {
      /* cleanup previous work A */
      return -1;
   }

   /* do something C */
   if(err) {
      /* cleanup previous work B */
      /* cleanup previous work A */
      return -1;
   }

   return 0;
}

Or even this more efficient (yes boys and girls, goto actually has a good use case in C, get over it) pseudo-C:

int dosomething(void) {
   /* do something A */
   if(err) return -1;

   /* do something B */
   if(err) goto err1;

   /* do something C */
   if(err) goto err2;

   return 0;

   err2:
   /* cleanup previous work B */

   err1:
   /* cleanup previous work A */

   return -1;
}

Why are these bad? Cache locality. In the first example, you have error handling code inline with your regular code. In the second you have it slightly better and off to the end of the function. Ideally the code you run will all be compacted in as few cache lines as possible, and erroring handling this way will waste significant space on cleanup code that in the large majority of cases won’t be run.

But with exceptions, the compiler is free to take all the cleanup code in your entire app, and shove it into a single separate area of code. All your normal code that you expect to run can be compact and closer together. Of course, this will make exceptions run slower. If your code is heavy on throwing exceptions (which would probably be an abuse) it will probably cause a significant overall slowdown. But if they are used correctly–for exceptional situations–then the common case will be improved cache usage and therefor faster code.