TechEarl

iotop: Find Which Process Is Hammering Your Disk

sudo iotop -o sorts running processes by live disk I/O so you can see which one is hammering the drive, with the flags for batch mode, accumulated totals, and the read/write split.

Ishan Karunaratne⏱️ 10 min readUpdated
Share thisCopied
Use sudo iotop -o to find which process is hammering your disk. Live per-process read and write rates, -o to hide idle threads, -b batch mode for logging, and -a for accumulated I/O totals.

sudo iotop -o shows you, in real time, which process is doing disk I/O right now and how much. It is top for the disk: a live table sorted by I/O rate, with a per-process read column and a write column. The -o flag is the one you actually want, because it hides every thread that is not currently doing any I/O, so the screen shows only the culprits instead of a wall of idle kernel threads.

The thing to know up front: iotop needs root. It reads per-task I/O accounting out of the kernel's taskstats interface over a netlink socket, and that data is privileged, so a plain iotop as a normal user fails with a permission error. Run it with sudo. Everything else on this page is filtering and formatting: collapsing threads into processes, logging to a file instead of a live screen, and showing accumulated totals instead of an instantaneous rate.

The one-liner

bash
sudo iotop -o

That opens the interactive view and lists only processes with active disk I/O, refreshing once a second. The columns that matter are DISK READ and DISK WRITE (the current per-process rate, displayed as B/s, K/s, or M/s) and IO> (the percentage of time the process spent waiting on I/O). The two summary lines at the top show Total DISK READ / Total DISK WRITE (actual disk traffic) and Actual DISK READ / Actual DISK WRITE. Those two pairs differ because of the page cache and writeback: a process can "write" into cache faster than the kernel flushes it to the platter, so the totals and the actuals rarely line up exactly.

Inside the live view, press o to toggle the --only filter, r to reverse the sort, a to switch to accumulated mode, and q to quit. left/right arrows move the sort column.

Why -o is the flag you reach for first

Without -o, iotop lists every thread on the system, including the dozens of idle kernel worker threads. On a busy box that is several screens of noise with the one process you care about buried in it.

bash
sudo iotop -o -P

-P (--processes) collapses threads into their parent process, so you see one row per process instead of one row per thread. Combined with -o, that is the view I keep open when something is thrashing the disk: only active processes, one line each, sorted by I/O. If you need the thread-level breakdown (say, one thread of a multithreaded daemon is the problem), drop -P and iotop goes back to per-thread rows.

Logging I/O instead of watching it: batch mode

The interactive view is fine when you are at the keyboard. When you want to capture I/O over time, for a slow nightly job or an intermittent spike, use batch mode and redirect to a file.

bash
sudo iotop -boP -d 5 -n 12 > /tmp/io.log

That reads as: -b batch (non-interactive, plain text, no curses), -o only active, -P per-process, -d 5 a five-second delay between samples, -n 12 stop after 12 samples. Twelve samples at five seconds each is one minute of logging, then iotop exits on its own. Add -t to prefix every line with a timestamp, which you want in any log you are going to read later:

bash
sudo iotop -btoP -d 5 -n 12 > /tmp/io.log

Batch mode is also how you feed iotop output into anything else: grep for a process name, awk the write column, or pipe it into a quick chart. The curses view cannot do any of that. For recurring capture, drop a bounded batch run into cron (a short -n run appended to a dated log) rather than leaving an interactive session open.

Accumulated totals vs the instantaneous rate

By default each refresh shows the rate over the last interval. Sometimes you do not care about the rate, you care about who has written the most in total since iotop started. That is -a (--accumulated):

bash
sudo iotop -aoP

Now the DISK READ and DISK WRITE columns count total bytes since iotop launched, not a per-second rate. This is the mode for catching a process that writes in short bursts: a per-second rate flickers and is easy to miss, but the accumulated total just keeps climbing for the offender and stays flat for everything else. Press a in the interactive view to toggle it live.

A worked example: tracking down a runaway writer

Suppose iostat or a monitoring alert says the disk is pinned at 100% utilization but you do not know which process is responsible. Open the live view:

bash
sudo iotop -oP
code
Total DISK READ:         0.00 B/s | Total DISK WRITE:       118.42 M/s
Actual DISK READ:        0.00 B/s | Actual DISK WRITE:       121.06 M/s
    PID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
  31847  be/4  postgres   0.00 B/s  117.30 M/s  0.00 %  92.14 %  postgres: autovacuum worker
   2210  be/4  root       0.00 B/s    1.12 M/s  0.00 %   3.01 %  rsyslogd

The autovacuum worker is doing 117 MB/s of writes and spending 92% of its time blocked on I/O. That is the answer. The IO> column is the tell: a high percentage there means the process is genuinely I/O-bound, not just incidentally touching the disk. To confirm it is sustained and not a one-second blip, switch to accumulated mode (a) and watch the write total for that PID climb.

iotop vs pidstat vs iostat

These three tools overlap but answer different questions. Pick by what you actually need to know.

ToolGranularityAnswersNeeds root
iotopper process / per thread"Which process is doing the I/O right now?"Yes
pidstat -dper process"Which process, sampled over time, scriptable?"No (own processes); yes for all
iostat -xper device"Which disk is busy, and how saturated?"No

Reach for iotop when you want a live, sorted, interactive view and you are sitting at the terminal. Reach for pidstat -d when you want the same per-process I/O numbers in a clean, columnar, easily-parsed form for a script or a log, or when you do not have root, since pidstat reports your own processes without it. See the pidstat command guide for the per-process CPU, memory, and I/O breakdown. Reach for iostat -x when the question is about the device, not the process: queue depth, await time, and utilization per disk.

Caveats and distro differences

It is not installed by default. iotop ships in a package you usually have to add: apt install iotop on Debian and Ubuntu, dnf install iotop on Fedora and RHEL-family systems. Some recent distributions ship iotop-c (a C rewrite of the original Python tool) under the same iotop command name; the common flags shown here behave the same.

It needs a kernel built with task I/O accounting. iotop relies on CONFIG_TASK_DELAY_ACCT, CONFIG_TASKSTATS, and CONFIG_TASK_IO_ACCOUNTING being enabled in the kernel. Every mainstream desktop and server distro enables these, but a stripped-down or embedded kernel might not, in which case iotop starts and shows zeroes for everything. On some kernels delay accounting is off until you enable it with sysctl kernel.task_delayacct=1.

Containers and VMs see only their own view. Inside an unprivileged container iotop may fail on the netlink socket entirely, or only report processes in its own namespace. If you need the host's full I/O picture, run iotop on the host, not inside the container.

The page cache hides the truth, briefly. The gap between Total DISK WRITE and Actual DISK WRITE is the writeback delay. A process can appear to write huge amounts that have not hit the disk yet, or appear idle while the kernel flushes its earlier writes. For the real device-level number, cross-check with iostat -x.

See also

FAQ

Sources

Authoritative references this article was fact-checked against.

TagsiotopLinuxDisk I/OPerformanceSystem AdministrationCLIDevOps

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

How to Find the Largest Files on Disk (find, sort, du)

find / -xdev -type f -printf '%s %p\n' | sort -rn | head -20 gives you a ranked list of the biggest files on a full disk. The GNU one-liner, the BSD/macOS stat variant, why -xdev matters, human-readable output with numfmt, when to switch to du or ncdu for per-directory totals, and the mistakes that send a scan into /proc.

How to Find Duplicate Rows in MySQL

Find duplicate rows in MySQL with GROUP BY HAVING, a ROW_NUMBER window function, or a self-join. Includes NULL behaviour, soft duplicates, and the right index.