November 2022
When interviewing programmers, I often ask them to code a simple program to count word frequencies in a text file. It’s a good problem that tests a bunch of skills, and with some follow-up questions, allows you to go surprisingly deep.
One of the follow-up questions I ask is, “What’s the performance bottleneck in your program?” Most people say something like “reading from the input file”.
In fact, I was inspired to write this article after responding to someone on Gopher Slack, who said, “I also note there’s a lot of extra work happening here in splitting the entire line, etc, it’s just that typically this is all so much faster than I/O that we don’t care.”
I’m not picking on him … before I analyzed the performance of the count-words problem, I thought the same. It’s what we’ve all been taught, right? “I/O is slow.”
Not anymore! Disk I/O may have been slow 10 or 20 years ago, but in 2022, reading a file sequentially from disk is very fast.
Just how fast? I tested the read and write speed of my development laptop using this method but with count=4096
so we’re reading and writing 4GB. Here are the results on my Dell XPS 13 with a Samsung PM9A1 NVMe drive, running Ubuntu 22.04:
I/O Type | Speed (GB/s) |
---|---|
Read (not cached) | 1.7 |
Read (cached) | 10.8 |
Write (incl. sync time) | 1.2 |
Write (not incl. sync) | 1.6 |
System calls are relatively slow, of course, but when reading or writing sequentially you only have to do one syscall every 4KB, or 64KB, or whatever your buffer size is. And I/O over a network is still slow, especially a non-local network.
So what is the bottleneck in a program that