Home / Alt manpages / proc_pid_io(5)

  • proc_pid_io(5)
  • File format
  • linux

Read Per-Process I/O Counters from /proc/pid/io

A process looks busy but you cannot tell if it is actually hitting disk: /proc/<pid>/io gives you the seven cumulative counters that settle it. The examples use the installed proc_pid_io(5) page from Linux man-pages 6.7, package version 6.7-2.

Allow about ten minutes. You need a shell and a process ID that still exists. This is observation only: the commands do not restart services, alter files or require sudo when you inspect your own process. Access to another user's process can be denied by the kernel's ptrace access check, so elevated privileges are not a universal workaround and should not be your first response.

1. Choose a live process

Start with the shell running your commands. $$ is the shell's process ID in a normal POSIX shell. Check that the procfs file exists before reading it:

$ pid=$$
$ printf 'checking PID %s\n' "$pid"
checking PID 12345
$ test -r "/proc/$pid/io" && echo readable
readable

The number differs on your machine. Do not copy the displayed PID literally. A PID can be reused after a process exits, so resolve it immediately before collecting a sample rather than keeping an old number in a script or notebook.

Checkpoint

You have a live PID and /proc/$pid/io is readable. If the test fails, choose a process you own or stop and check whether procfs is mounted. Do not make a service change merely to obtain statistics.

2. Read the seven counters

Read the file as one small, labelled report:

$ cat "/proc/$pid/io"
rchar: 2153311
wchar: 7385
syscr: 139
syscw: 10
read_bytes: 0
write_bytes: 0
cancelled_write_bytes: 0
  • rchar and wchar count bytes returned by successful read-like and write-like system calls.
  • syscr and syscw count the corresponding file-read and file-write calls, including the read and write families, sendfile(2), copy_file_range(2) and the documented Btrfs encoded I/O ioctls.
  • read_bytes and write_bytes count bytes really fetched from, or sent to, the storage layer, which is not the same thing as bytes the application asked for. A cache hit can raise rchar without touching read_bytes, and buffered writes can move the two write views out of step.

The values above are an example shape, not a promise about your process.

3. Compare a pair of samples

The counters are normally useful as deltas, not absolute totals. Take two readings around the workload you care about:

$ pid=$$
$ before=$(awk '$1 == "rchar:" {print $2}' "/proc/$pid/io")
$ printf 'sample text\n' > /dev/null
$ after=$(awk '$1 == "rchar:" {print $2}' "/proc/$pid/io")
$ printf 'rchar delta: %s bytes\n' "$((after - before))"
rchar delta: 13 bytes

The exact delta depends on the shell and command sequence, so treat this as a method demonstration rather than an expected number. The first sample must be captured before the workload, and both reads must refer to the same PID. For a long-running service, record a timestamp with each sample and calculate the change over a fixed interval: a rate is your calculation, not a field procfs supplies.

Do not assume a zero storage counter means the program did no work. The data may have come from cache, the process may have written through a different mechanism, or filesystem accounting may not expose the detail you expected. Check the related fields and the workload's own logs before drawing a conclusion.

4. Account for children and cancelled writes

The manpage describes these statistics as covering the process and its waited-for children. That makes the file useful for some command wrappers, but it also means a parent's totals can include work done by children it has waited for. For per-process attribution, sample the worker PID itself and keep parent and child PIDs separate.

cancelled_write_bytes records writeback that was later saved by truncation. Data written to a regular file and then removed before writeback can stay in the write accounting while the kernel avoids sending it to storage. This value applies to I/O already counted in write_bytes, so the effective storage write delta can look negative. That is an accounting result, not evidence the disk returned bytes to the process.

5. Handle permissions and unstable reads

Access to /proc/<pid>/io is governed by the ptrace PTRACE_MODE_READ_FSCREDS check. A permission error for another user's process is expected security behaviour, not a bug. Confirm the target first:

$ ps -p "$pid" -o pid=,comm=
12345 bash
$ cat "/proc/$pid/io"
cat: /proc/12345/io: Permission denied

Use a process you are allowed to inspect, or follow your organisation's approved monitoring path. Avoid broad permission changes and avoid putting sensitive process data into world-readable logs.

The counters are not atomic. On systems where 64-bit operations can tear, a read concurrent with an update can produce an incorrect intermediate value. For trend work, take repeated samples and treat an isolated implausible jump as suspect rather than a precise transaction boundary.

Done means

  • Selected a live PID and checked access to its procfs I/O file.
  • Told apart logical bytes, syscall counts and storage-layer bytes.
  • Calculated a delta from two samples of the same process instead of treating a total as a rate.
  • Accounted for waited-for children, cache effects and cancelled writes.
  • Kept the inspection read-only and treated permission errors as an access boundary.