Jeremy Côté

Timing

The best way to speed up your code is to figure out which parts are running the slowest.

If you spend two hours halving the speed of part A in your code, but part A only takes up two seconds of a minute computation, you’ve shaved off one second. On the other hand, if you spend a few hours halving part B which contributes to the other fifty-eight seconds, then your computation time is only 31 seconds now, almost a 2x improvement.

This is why saying, “My code sure is running slow” is true, but useless. When it comes to making your code more efficient, different parts contribute differently to the overall sluggishness. Saying the whole code is slow is a bit like saying a triathlon is wet. Technically true, but really just a small portion of the entire experience (the swim). Likewise, slow code isn’t an inherent property of everything you wrote, but the result of a few key lines which take up the majority of the computation.

Timing exposes these bottlenecks. It gives you a way to measure how long each line takes, and drill in to the culprits hogging up the computation. Once you find them, you can figure out creative ways to do the same thing more efficiently. But you need to start by finding them, or else you’ll be left with a vague sense of your code being slow, without any deeper knowledge.

There’s a general lesson here: Inefficiencies tend to crop up in specific places, not throughout an entire situation. I don’t remember a time where my code was slow in all places. There’s a distribution of compute times, and it’s the outliers which deserve my attention, not the lines which are already fast.

I see this within my own life as well. It’s easy to feel a general sense of unease or dissatisfaction with where I am. But where does this sense stem from? Often, I’ll just run away from this feeling because it’s uncomfortable, but if I want to understand the source, I need to dig deeper.

When writing code, timing reveals inefficiencies. If you’re reflecting on your own life, asking “Why?” several times plays a similar role. If you’re looking to improve your finances, don’t spend hours improving part A which is already looking pretty good, because you don’t want to deal with the real mess which is part B.

The inefficiency of an outlier dwarfs any improvement you make near the mean.

Examining my life in this critical way isn’t fun. Of course it isn’t: I’m jumping straight into the worst parts. But this is where the biggest returns are. If you look at your life as a black box and try to pick something at random to improve, don’t be surprised when nothing much changes in your life. Instead, take the time to inspect each component, and figure out which ones are inefficient. These are the ones worth spending your time on. Only once you deal with these can you make a noticeable dent in the others.

I try to think of this in terms of my science. Am I spending time improving the parts of my research which will yield the biggest benefit? Or am I just jumping from item to item, wasting most of my time in the switching costs? Where are the inefficiencies in my workflow? Do I get stumped for hours if I have to install a package through the command line (this has definitely happened before)? Do I have processes set up to create presentations, write text, write code, analyze data, make figures, and update my CV?

These questions help me reflect on what I’m doing, because it’s difficult to systematically improve your work or your life when doing so blindly. The general principle of timing can help point out which areas deserve work.

If you want to write faster code, time your lines and figure out what’s taking the bulk of the computation. If you want to improve your general sense of being, take the time to figure out where your inefficiencies are first.

There are many ways to improve your life. But there are a few which will make an outsized difference in your life. Find out what those are, and then take action.