For the longest time, I thought Instruments on macOS wasn’t for me. Whenever I saw its icon show up in the /Applications
folder or pop up in a launcher, I assumed it’s part of Xcode and Xcode is an IDE for Objective-C and Swift programmers and that’s not what I do and that’s why Instruments isn’t for me.
I was wrong.
Shortly after joining Zed at the start of the year, I realised two things:
Instruments is an amazing performance-analysis tool
It can be used with anything! Well, at least any binary that uses the native stack
As is my wont, I then went on an Instruments evangelism tour and told everybody who would listen (or, to be honest, wouldn’t) about it.
Now it’s time I tell you about Instruments, in case you’ve been missing out.
The first thing we have to get out of the way is that getting started with Instruments is weirdly hard. It’s not hard-hard in the sense that you need to have read four books to make sense of the menu entries, but hard in the sense that it’s easy to miss which button to click and end up unimpressed.
To avoid that, let me hold your hand while you do your first steps with Instruments.
First: launch Instruments.app
. You’ll see a window like this:
There’s two things to note here:
Wow, does it actually say Zombies on that button there? Yes, it does.
A lot of people give up on Instruments at this point, because it’s not obvious what to click.
So, let’s choose the most straightforward option and select CPU Profiler
, then click Choose.
What you’ll see next is a screen that doesn’t improve on the previous screen’s self-explanatory attributes:
Fear not! This screen tells us that we’re ready to record a profile, but we haven’t done so.
What we need to click is All processes
in the top left (the label might be different) and then select the process we want to profile. Once you click it you’ll see a drop-down in which you can select an already-running process to analyse, or you can start a new one.
As an example, I’m going to launch the amazing atuin in my terminal and keep it running so I can profile it. To do that, I click on said All processes
and — weirdly enough — atuin shows up under System processes
(I guess that’s what Instruments calls all non-GUI processes). I select it and now I end up with this:
Now you need to click on that red button on the left that should be roughly 50 times bigger and have a big, fat label that says “The Button”. Clicking it will record the process.
Once it’s recording, I switch over to atuin (or whatever application I want to profile) and do the thing I want to analyse. In this case, that means I’m just going nuts and type a bunch of stuff into atuin, so it fuzzy-searches my shell history. Once I’m done, I click the stop button in Instruments and end up with this:
How sweet is that? A full CPU profile of atuin and all its threads.
You can zoom in, walk up and down the call tree, order functions by weight (which — roughly — means how much time they took up), filter functions, only select specific threads, and so on.
And that’s only the start!
On that first screen, the one on which we choose CPU Profiler
, there are many more interesting profile templates. Here, for example, is what I recorded using the System Trace
profile, also pointing it at atuin:
Look at that! Isn’t that beautiful! You can see when which thread is running, or when they’re blocked, when they’re doing syscalls or are blocked by them.
In this specific example, you can see that the two sqlx-sqlite-worker
threads atuin apparently has are taking turns on the CPU: when one is blocked, the other is running. You can see the system calls, you can see the CPU usage, you zoom in endlessly. It’s fantastic.
Or, here, a Metal System Trace
of Ghostty:
You can see when VSync events happen, you can see render times, you can correlate that with CPU use, you can then drill into which thread is doing what when a frame is missed — so good.
Look. I could go on and on and on and show you more screenshots or even videos and tell you how amazing Instruments is, but what I want to leave you with are two things.
One: if you’ve ever bumped into Instruments and thought that it isn’t for you, you might want to reconsider. Give it another shot. It’s a bit weird to get started, granted, but it has a lot to offer.
Second: I can’t believe how good this tool is! So much work must have gone into it that it’s actually hard to believe.
I mean, look:
I can drill into every milli— no, microsecond of every frame that Zed renders and see exactly what’s going on in which thread, with basically no noticeably overhead. That’s nuts. The UI — despite the hurdles when getting started — and how easy it then is to drill into data and examine different things going — that’s far ahead of every other profiling tool I’ve used — on macOS and on Linux, with any other programming language.
Don’t sleep on Instruments.
Instruments’ precursor was Shark, and more than a decade ago I lived and died by it while working on JS engine performance at Mozilla.
One thing that Shark had that I miss in Instruments is the ability for the *application* to start/stop/pause/resume profiling. This let us add hooks in the browser so that we got super clean profiles of specific operations, without having to weed out all the setup/teardown stuff by hand in the profile viewer. It was so so good.
Man one thing I gripe about cure gen Mac OS is that when I sleep with lid closed and connect to external monitor the os just wake up instantly. I tried to look into that in activity monitor without availing. I’ll give instruments a shot