TL;DR
The 8 most useful fio invocations.
Copy-pasteable. If you remember nothing else, remember the first one.
The essentials
# Sequential read of a 1 GiB file (writes nothing; pre-existing file needed)
$ fio --name=read --rw=read --size=1G --filename=/tmp/test.bin
Random 4 KiB write benchmark (4 parallel jobs, 1 GiB each)
$ fio --rw=randwrite --bs=4k --size=1G --numjobs=4 \
--filename=/tmp/fio-test.bin --runtime=60 --time_based
IO engines
Linux io_uring engine (kernel ≥ 5.6; lowest-latency async path)
$ fio --ioengine=io_uring --rw=randrw --bs=4k \
--size=1G --filename=/dev/nvme0n1 --runtime=30 --time_based
Sanity check the binary without touching disk (null engine; useful in CI)
$ fio --name=smoke --ioengine=null --rw=randrw \
--runtime=1 --time_based --size=1M --minimal
3;fio-3.41;smoke;0;0;17175736;17158577;4289644;1001;...
Output & reporting
Latency histogram + percentile breakdown (stdout, terse format)
$ fio --rw=randread --bs=4k --size=1G --filename=/dev/nvme0n1 \
--runtime=30 --time_based --output-format=normal,latency
JSON output for downstream parsing (e.g. dashboards, regression tests)
$ fio --rw=randwrite --bs=4k --size=1G --filename=/tmp/test.bin \
--output-format=json --output=out.json
$ jq '.jobs[0].write.iops' out.json
52319.4
Advanced
Multi-device striping (split the workload across two block devices)
$ fio --rw=randrw --bs=4k --size=2G \
--filename=/dev/nvme0n1 --filename=/dev/nvme1n1 \
--numjobs=2
When NOT to use fio
fio is a benchmark tool — it generates synthetic workloads
and reports throughput / latency. If you want a single-shot
dd-style sequential write, or a one-line disk speed
number, fio is overkill. For those:
dd if=/dev/zero of=/tmp/test bs=1M count=1024 oflag=direct— fast sequential writesysbench fileio— simpler OLTP-style benchmarksbonnie++— classic FS-level benchmark
And if you need reproducible synthetic workloads at scale (CI / regression),
use --minimal --output-format=json and parse the JSON —
that's the test-driven fio workflow.