Sample output
$ time du -sh /usr
858M /usr
real 0m0.537s
user 0m0.030s
sys 0m0.440s
$ time du -sh /usr
858M /usr
real 0m0.211s
user 0m0.013s
sys 0m0.198s
Add user and sys and compare the total to real. On the first run the CPU accounts for 0.47 of 0.54 seconds, so roughly 0.07 seconds went to waiting on the disk. On the second run the directory data is already in the page cache, the waiting disappears, and real collapses to almost exactly sys: du is now pure kernel work. When real is far larger than user plus sys, the command is waiting, and a faster CPU will not help.
When you would reach for it
A build, a backup, or a report script takes longer than it should and you want to know where to look before you start optimizing. The three numbers sort the problem into one of three shapes: real much bigger than user plus sys means it is blocked on I/O, the network, or a lock; real roughly equal to user plus sys means it is CPU-bound on one core; user plus sys bigger than real means it is already spreading across several cores. It is also the quickest honest benchmark for comparing two ways of doing the same job.
Gotchas
- The timing goes to the shell’s stderr, not the command’s, so
time du -sh /usr 2> err.txtstill prints the numbers on your terminal. To capture them, group the command first:{ time du -sh /usr; } 2> timing.txt. - zsh, the default shell on macOS, prints a single line instead of three:
du -sh /usr 0.03s user 0.44s system 87% cpu 0.537 total. The numbers mean the same thing. Same keyword, different shell, different format, which matters if a script parses the output. /usr/bin/timeis a different tool with different flags.time -vin bash fails with-v: command not found, because the keyword only understands-pand treats anything else as the command to run; the GNU program needs its full path,/usr/bin/time -v, and on Debian it is not installed until youapt install time. macOS ships a BSD/usr/bin/timethat uses-linstead of-v. In dash, Debian’s/bin/sh, there is no keyword at all, sotimein a#!/bin/shscript fails withtime: not foundunless that package is installed.- The second run is almost always faster, because the first one warmed the page cache. Benchmark with a warm cache unless the cold start is the thing you care about, and say which one you measured.
Variants
$ time xz -T0 -c backup.tar | wc -c
Prove a tool is really using all your cores. Here a 50 MB file took 7.1 seconds of real time and 14.2 seconds of user time, so xz kept about two cores busy. The keyword times the whole pipeline, including wc
$ TIMEFORMAT='%R real, %U user, %S sys, %P%% cpu'; time du -sh /usr
bash only. Reformat the output on one line and add %P, the CPU percentage, which is (user + sys) / real. Well under 100 means waiting, near 100 means one busy core, above 100 means parallel work
$ { time ./nightly-report.sh; } 2>> timings.log
Append each run’s timing to a log so you can see when the job started getting slower. The braces make the keyword’s output part of the group’s stderr, so the log also collects anything the script itself writes there