fio
fio (Flexible I/O Tester) è lo strumento standard del settore per il benchmarking e lo stress testing dei sottosistemi di storage. Supporta pattern I/O configurabili, motori multipli (libaio, io_uring, sync), file di job e reporting dettagliato di latenza/throughput.
Installazione
# Ubuntu/Debian
sudo apt-get install fio
# RHEL/CentOS/Fedora
sudo dnf install fio
# macOS
brew install fio
# From source
git clone https://github.com/axboe/fio.git
cd fio
./configure
make -j$(nproc)
sudo make install
# Verify
fio --version
Random Read/Write
4K Random Read (Common SSD Test)
# 4K random read - IOPS test
fio --name=randread \
--ioengine=libaio \
--iodepth=32 \
--rw=randread \
--bs=4k \
--direct=1 \
--size=1G \
--numjobs=4 \
--runtime=60 \
--time_based \
--group_reporting \
--filename=/tmp/fio-test
4K Random Write
# 4K random write - IOPS test
fio --name=randwrite \
--ioengine=libaio \
--iodepth=32 \
--rw=randwrite \
--bs=4k \
--direct=1 \
--size=1G \
--numjobs=4 \
--runtime=60 \
--time_based \
--group_reporting \
--filename=/tmp/fio-test
Mixed Random Read/Write
# 70/30 read/write mix (typical database workload)
fio --name=randrw \
--ioengine=libaio \
--iodepth=32 \
--rw=randrw \
--rwmixread=70 \
--bs=4k \
--direct=1 \
--size=1G \
--numjobs=4 \
--runtime=60 \
--time_based \
--group_reporting \
--filename=/tmp/fio-test
Sequential I/O
Sequential Read (Throughput)
# Sequential read - bandwidth test
fio --name=seqread \
--ioengine=libaio \
--iodepth=16 \
--rw=read \
--bs=1M \
--direct=1 \
--size=4G \
--numjobs=1 \
--runtime=60 \
--time_based \
--group_reporting \
--filename=/tmp/fio-test
Sequential Write
# Sequential write - bandwidth test
fio --name=seqwrite \
--ioengine=libaio \
--iodepth=16 \
--rw=write \
--bs=1M \
--direct=1 \
--size=4G \
--numjobs=1 \
--runtime=60 \
--time_based \
--group_reporting \
--filename=/tmp/fio-test
Job Files
Basic Job File
; storage-bench.fio
[global]
ioengine=libaio
iodepth=32
direct=1
size=1G
runtime=60
time_based
group_reporting
filename=/tmp/fio-test
[4k-randread]
rw=randread
bs=4k
numjobs=4
[4k-randwrite]
rw=randwrite
bs=4k
numjobs=4
stonewall
[1m-seqread]
rw=read
bs=1M
numjobs=1
stonewall
[1m-seqwrite]
rw=write
bs=1M
numjobs=1
stonewall
# Run the job file
fio storage-bench.fio
Database Simulation Job
; database.fio - Simulates database I/O patterns
[global]
ioengine=libaio
direct=1
time_based
runtime=120
filename=/tmp/fio-db-test
[db-data-read]
rw=randread
bs=8k
iodepth=64
numjobs=8
size=4G
[db-log-write]
rw=write
bs=4k
iodepth=1
numjobs=1
size=512M
fsync=1
I/O Engines
# libaio - Linux native async I/O (most common for benchmarks)
fio --ioengine=libaio --iodepth=32 --rw=randread --bs=4k \
--direct=1 --size=1G --filename=/tmp/fio-test --name=test
# io_uring - Modern Linux I/O (kernel 5.1+, fastest)
fio --ioengine=io_uring --iodepth=128 --rw=randread --bs=4k \
--direct=1 --size=1G --filename=/tmp/fio-test --name=test
# sync - Synchronous I/O (simple, single-threaded baseline)
fio --ioengine=sync --rw=randread --bs=4k \
--direct=1 --size=1G --filename=/tmp/fio-test --name=test
# psync - POSIX sync (pread/pwrite, allows seeking)
fio --ioengine=psync --rw=randread --bs=4k \
--direct=1 --size=1G --filename=/tmp/fio-test --name=test
# mmap - Memory-mapped I/O
fio --ioengine=mmap --rw=randread --bs=4k \
--size=1G --filename=/tmp/fio-test --name=test
# List all available engines
fio --enghelp
Output Parsing
JSON Output
# Get JSON output for scripting
fio --name=test --ioengine=libaio --rw=randread --bs=4k \
--direct=1 --size=256M --iodepth=32 --output-format=json \
--filename=/tmp/fio-test > results.json
# Parse key metrics
python3 -c "
import json
with open('results.json') as f:
data = json.load(f)
job = data['jobs'][0]
read = job['read']
print(f'IOPS: {read[\"iops\"]:.0f}')
print(f'BW: {read[\"bw\"] / 1024:.1f} MB/s')
print(f'Lat avg: {read[\"lat_ns\"][\"mean\"] / 1000:.1f} us')
print(f'Lat p99: {read[\"clat_ns\"][\"percentile\"][\"99.000000\"] / 1000:.1f} us')
"
Terse Output
# Terse (semicolon-separated) output for scripting
fio --name=test --ioengine=libaio --rw=randread --bs=4k \
--direct=1 --size=256M --iodepth=32 --output-format=terse \
--filename=/tmp/fio-test
Profiles and Common Test Patterns
NVMe SSD Full Test
# Comprehensive NVMe SSD benchmark
# WARNING: Use a test file, not a raw device, unless you know what you're doing
# 1. Sequential read throughput
fio --name=seq-read --ioengine=io_uring --iodepth=64 --rw=read \
--bs=128k --direct=1 --size=4G --numjobs=4 --runtime=60 \
--time_based --group_reporting --filename=/tmp/fio-test
# 2. Sequential write throughput
fio --name=seq-write --ioengine=io_uring --iodepth=64 --rw=write \
--bs=128k --direct=1 --size=4G --numjobs=4 --runtime=60 \
--time_based --group_reporting --filename=/tmp/fio-test
# 3. Random 4K read IOPS
fio --name=rand-read --ioengine=io_uring --iodepth=256 --rw=randread \
--bs=4k --direct=1 --size=4G --numjobs=4 --runtime=60 \
--time_based --group_reporting --filename=/tmp/fio-test
# 4. Random 4K write IOPS
fio --name=rand-write --ioengine=io_uring --iodepth=256 --rw=randwrite \
--bs=4k --direct=1 --size=4G --numjobs=4 --runtime=60 \
--time_based --group_reporting --filename=/tmp/fio-test
Latency-Sensitive Test
# Measure latency at low queue depth (realistic for single-user apps)
fio --name=latency \
--ioengine=libaio \
--iodepth=1 \
--rw=randread \
--bs=4k \
--direct=1 \
--size=1G \
--numjobs=1 \
--runtime=60 \
--time_based \
--percentile_list=50:90:95:99:99.9:99.99 \
--filename=/tmp/fio-test
fio Plot
# Generate bandwidth/IOPS log for plotting
fio --name=test --ioengine=libaio --rw=randread --bs=4k \
--direct=1 --size=1G --iodepth=32 --runtime=60 --time_based \
--write_bw_log=results --write_iops_log=results --write_lat_log=results \
--log_avg_msec=1000 --filename=/tmp/fio-test
# Plot with fio_generate_plots (requires gnuplot)
sudo apt-get install gnuplot
fio_generate_plots results
# Log files generated:
# results_bw.log - Bandwidth over time
# results_iops.log - IOPS over time
# results_lat.log - Latency over time
Suggerimenti
# Always use --direct=1 to bypass OS page cache
# Always use --time_based with --runtime for consistent results
# Use --group_reporting to aggregate stats across jobs
# Run tests multiple times for reliable numbers
# Pre-condition SSDs with a full write before benchmarking
# Clean up test files
rm -f /tmp/fio-test