Harry Jeffery

Exceptions and flow control

2021-12-23

Yesterday’s Advent of Code problem was about efficiently performing boolean operations on axis-aligned bounding boxes.

While solving it, it reminded me of a significant optimisation I made some years ago. Around 2014-2015, I was on a placement year away from my computer science degree. I had a 12 month placement working for the Science and Technology Facilities Council, a public sector gig which had me working on Mantid, an open source data analysis application primarily for use on neutron scattering experiments. That is, data from their particle accelerator. It was a fun first experience of professional software development and a good example of well written and maintained academic software.

One task I had was to improve the performance of various processing and filtering operations that Mantid could apply to a user’s dataset. One such operation required determining the intersection of many pairs of axis-aligned bounding boxes.

This is a very simple calculation, but my profiling informed me that it was taking the vast majority of the eight minute runtime of this particular process.

The intersection test was defined like this:

1
2
3
4
5
6

AABB findIntersection(const AABB &a, const AABB &b)
{
  // if intersection found, return an AABB of intersected area
  // else, throw an exception
}

This function was being called thousands and thousands of times on many pairs of axis-aligned bounding boxes that very rarely overlapped. The result was a deluge of non-stop exception handling.

Fixing that is simple enough fortunately, so I changed the function to look like this:

1
2
3
4
5
bool findIntersection(const AABB &a, const AABB &b, AABB &out)
{
  // if intersection, write it to out and return true
  // else, return false
}

I knew that this would improve the performance, but I didn’t appreciate just what a difference it would make.

The total runtime for the processing decreased from eight minutes down to just eight seconds. Instead of requiring a tea break, the user could carry on working in just the time it takes to have a nice yawn and stretch at their desk.

So when people say exceptions are a terrible way to implement flow control, they aren’t kidding. It doesn’t just muddy the internal flow of your software and make it harder to reason about; it can have a significant user perceivable impact to the way your software performs.

To this day, this remains the most satisfying performance fix I’ve made in my professional career.