Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Analyse disk performance on Linux

By updated

Improve this page

A service is slow and you suspect the disk? Before concluding, you have to measure. This guide shows how to assess the three indicators that really matter (throughput, IOPS, latency) with fio and iostat, check the health of the hardware with smartctl, and above all interpret the results without falling into the trap of the cache or of a test that is too short. It is aimed at intermediate to advanced administrators on Linux (Debian, Ubuntu, RHEL).

What you will learn

  • Tell throughput, IOPS and latency apart, and know which one to look at
  • Measure a disk's real performance with fio
  • Observe live activity with iostat and iotop
  • Avoid hasty conclusions (cache, test too short, misleading %util)

Prerequisites

  • A Linux machine with a sudo account
  • The fio, sysstat (for iostat) and smartmontools tools installed
  • Understand the notion of file system and mounting
Terminal window
sudo apt install fio sysstat smartmontools

Throughput, IOPS, latency: the three metrics

The first mistake is to talk about a disk's "speed" as a single figure. Three different quantities describe storage, and a slow service almost never suffers from all three at once.

MetricWhat it measuresWhen it matters
Throughput (MB/s)volume transferred per secondlarge files, backups, video
IOPSnumber of operations per seconddatabases, many small files
Latency (await, ms or µs)response time of one operationuser experience, interactive applications

The type of disk radically changes the orders of magnitude. A hard disk (HDD) tops out around 100-200 IOPS because of the mechanical head; a SATA SSD reaches tens of thousands of IOPS; an NVMe exceeds a million. Comparing the latency of an NVMe (a few tens of µs) with that of an HDD (several ms) makes no sense: they are different worlds.

Check health before measuring

No point benchmarking a dying disk. smartctl (smartmontools package) reads the S.M.A.R.T. data the disk keeps about itself:

Terminal window
sudo smartctl -a /dev/sda

Three attributes warn of an approaching end of life:

  • Reallocated_Sector_Ct: faulty sectors already replaced.
  • Current_Pending_Sector: unstable sectors waiting for reallocation.
  • Wear_Leveling_Count (SSD): wear of the memory cells.

A counter that climbs is a replacement signal. Also run a non-destructive self-test:

Terminal window
sudo smartctl -t short /dev/sda # short test (a few minutes)
sudo smartctl -l selftest /dev/sda # read the result

Observe real activity with iostat

iostat (sysstat package) shows what the disks are doing live. It is the tool to see whether a disk is saturated while the problem is happening:

Terminal window
iostat -dx 1

The -d option targets disks, -x adds the extended columns, and 1 refreshes every second. Here is an excerpt of the key columns (the full output has more):

Device r/s rkB/s r_await w/s wkB/s w_await aqu-sz %util
dm-0 55.93 1167.49 0.69 30.58 493.59 1.29 0.08 1.55

What to read:

  • r/s and w/s: read and write operations per second (the real IOPS).
  • rkB/s and wkB/s: read and write throughput.
  • r_await and w_await: the average latency in milliseconds, split by direction. It is the most telling indicator of a bottleneck.
  • aqu-sz: average queue size; when high, it reveals an overwhelmed disk.
  • %util: percentage of busy time.

To know which process generates the I/O, iotop lists the culprits in real time:

Terminal window
sudo iotop -oP

The -o option hides idle processes, -P groups by process. That is how you spot a log service or a backup hammering the disk.

Benchmark with fio

iostat observes the real load; fio (Flexible I/O tester) provokes it in a controlled way to measure what the disk is capable of. It is the reference tool for storage benchmarking.

To measure random 4 KB IOPS, the critical case for databases:

Terminal window
fio --name=randread --directory=/var/tmp --rw=randread \
--bs=4k --size=1G --runtime=30 --time_based \
--ioengine=libaio --direct=1 --group_reporting
read: IOPS=22.3k, BW=87.2MiB/s (91.5MB/s)(2617MiB/30001msec)
lat (usec): min=21, max=3954, avg=44.07, stdev=44.74

The line gives everything: 22,300 IOPS, a throughput of 87.2 MiB/s, and an average latency of 44 µs, measured with fio 3.36 on the NVMe of a workstation, with no virtualisation. To measure sequential throughput (large transfers), change the pattern and the block size:

Terminal window
fio --name=seqread --directory=/var/tmp --rw=read \
--bs=1M --size=2G --runtime=30 --time_based \
--ioengine=libaio --direct=1 --group_reporting
read: IOPS=2850, BW=2850MiB/s (2989MB/s)(83.5GiB/30001msec)

The decisive parameters: --rw (randread, randwrite, read, write, randrw), --bs (4k for random, 1M for sequential), and above all --direct=1, explained right after.

Avoid hasty conclusions

This is where most analyses go wrong. Four classic traps, each of which can turn a measurement into a wrong conclusion.

The cache distorts everything. Without --direct=1, you mostly measure RAM, not the disk: Linux serves reads from its page cache. A naive dd shows flattering GB/s that reflect nothing:

Terminal window
# Misleading: reads/writes in the cache
dd if=/dev/zero of=/var/tmp/test bs=1M count=1024
# More honest: forces the physical write
dd if=/dev/zero of=/var/tmp/test bs=1M count=1024 oflag=direct

With fio, --direct=1 bypasses the cache: it is non-negotiable to measure the disk itself.

A test that is too short lies. A few seconds measure a peak, not sustained behaviour. An SSD with a good start can collapse once its SLC cache is full. Use --runtime=30 --time_based at the very least.

%util at 100% is not proof on SSD/NVMe, as seen above: look at the latency.

Measuring with no load makes no sense. The only test that counts is under a load close to reality: same type of access (random or sequential), same block size as your application.

Troubleshooting

A disk performance diagnosis rarely picks the wrong tool, it picks the wrong reading. Before any action, cross-check the latency (await) with the S.M.A.R.T. health state and the type of disk:

SymptomLikely causeLead
High await (> 20 ms on SSD)disk saturated or failingcheck smartctl, spread the I/O load
%util at 100% but app slowfalse positive on parallel SSD/NVMelook at await and aqu-sz, not %util
Very low random IOPSHDD, or expected cache disabledcompare with the disk type, check --direct
Unrealistic fio throughput (GB/s)cache not bypassedadd --direct=1
A single process saturates the diskbadly tuned service (logs, backup)identify it via iotop -oP (iotop-c on RHEL 10) or pidstat -d, adjust its pace

Put it into practice

After measurement comes optimisation: a heavily read volume wastes I/O writing access dates. In this lab, you add the noatime option on a read-heavy mount, enable it live and write it into /etc/fstab so that the performance setting stays in place after a reboot.

Key points

  • Three distinct metrics: throughput (MB/s), IOPS, latency (await). A slow database = IOPS/latency, not throughput.
  • fio measures what the disk is capable of; iostat observes the real load.
  • --direct=1 is essential: without it, you measure the cache, not the disk.
  • On SSD/NVMe, %util at 100% proves nothing; svctm is gone from sysstat 12.
  • Check S.M.A.R.T. health before benchmarking, and test on a file, never on a disk in service.

Knowledge check

Check that the essentials of this guide are acquired. The questions only cover what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn