Disk Benchmarking on macOS

Recently, I tried benchmarking a USB stick using fio, and it turned out to be a cursed journey. To save you some time, here are the quirks I encountered and how I worked around them.

macOS employs aggressive file caching, and even with --direct=1, there’s no guarantee that reads or writes will bypass the Unified Buffer Cache. This behavior is discussed in this GitHub comment.
The XNU kernel ignores direct I/O requests if the chunk size is less than 16,384 bytes. In practice, even with larger chunk sizes, I often had to manually flush or purge the cache to get reliable results, as noted in this issue.

For accurate read performance measurements:

  • Pre-create the test file using the same flags. Use a short runtime (e.g., --runtime=1s) and a large chunk size (e.g., --size=1M).
  • Run sudo purge.
  • Then run the actual benchmark with --allow_file_create=0, pointing to the same file.
  • Make sure --direct=1 is set for both the file creation and the benchmark runs.

Measuring write performance is less tricky:

  • --direct=1 gives results closer to raw flash speed.
  • Alternatively, use --direct=0 and --fdatasync=1 to simulate real-world usage more accurately, similar to what AmorphousDiskMark and Finder report.

That should wrap it up. If you are coming from CrystalDiskMark or AmorphousDiskMark, there’s a script that automates the tests for you. Do read through the script and use it at your own risk.