How to Check CPU Usage in Linux

A Linux server tells you what its CPUs are doing through several command-line tools, each with a different angle. top and htop show the live picture. mpstat and sar from the sysstat package report numeric samples that suit scripts and dashboards. vmstat from procps combines CPU, memory, and I/O statistics. ps attributes usage to specific processes, and uptime summarizes the load over the last fifteen minutes.
This guide explains how to read CPU usage from each of those tools, which one to reach for in which situation, and how to interpret common output fields.
Quick Reference
| Tool | Best for | Command |
|---|---|---|
top | Live snapshot, sort by CPU | top |
htop | Interactive, per-core view | htop |
mpstat | Per-core sampling for scripts | mpstat -P ALL 1 5 |
vmstat | System-wide CPU and memory | vmstat -y 1 5 |
sar | Current or saved CPU samples | sar -u 1 5 |
ps | Per-process attribution | ps -eo pid,user,%cpu,comm --sort=-%cpu | head |
pidstat | Per-process usage over an interval | pidstat -u 1 5 |
uptime | Load average summary | uptime |
nproc | Logical core count | nproc |
lscpu | CPU topology details | lscpu |
Method 1: top
The top command
is available on most Linux systems without any extra packages. Run it without arguments to open the live view:
topThe header summarizes the CPU lines:
%Cpu(s): 4.2 us, 1.3 sy, 0.0 ni, 93.8 id, 0.5 wa, 0.0 hi, 0.2 si, 0.0 stThe fields tell you where CPU time goes. us is user-space code, sy is kernel code, id is idle, wa is time waiting for I/O, and st is time stolen by the hypervisor on a virtual machine. A high wa value points at slow disks rather than a CPU bottleneck.
Press 1 while top is open to switch from the aggregate line to one row per logical CPU. Press P to sort processes by CPU usage, M to sort by memory, and q to quit.
Method 2: htop
htop
is an interactive replacement for top. It is available in the default repositories of most Linux distributions, but it may not be installed by default.
On Ubuntu, Debian, and Derivatives:
sudo apt install htopOn Fedora, RHEL, and Derivatives:
On RHEL and its derivatives, enable the EPEL repository first. Then run:
sudo dnf install htopRun it the same way:
htophtop shows a colored bar per CPU at the top, a memory and swap bar, and a sortable process table below. Click a column header or use the function keys to sort. Search for a process with F3, filter with F4, and send a signal to a selected process with F9.
If you prefer a more graphical dashboard with CPU history graphs, see the guide on btop .
Method 3: mpstat
mpstat is part of the sysstat package and is the right tool when you need numeric CPU samples per core. Install it once before using mpstat or sar.
On Ubuntu, Debian, and Derivatives:
sudo apt install sysstatOn Fedora, RHEL, and Derivatives:
sudo dnf install sysstatSample all cores at one-second intervals five times:
mpstat -P ALL 1 503:14:00 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
03:14:01 PM all 3.27 0.00 0.75 0.00 0.00 0.00 0.00 0.00 0.00 95.98
03:14:01 PM 0 4.95 0.00 0.99 0.00 0.00 0.00 0.00 0.00 0.00 94.06
03:14:01 PM 1 1.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00The all row is the aggregate. Each numbered row is a single logical CPU. Use this output when one core is pinned at 100 percent and the others are idle, which can happen when an application is single-threaded.
Method 4: vmstat
The vmstat command
is part of procps and combines CPU usage with memory, swap, and I/O. The first report normally shows averages since boot, so use -y when you want only interval samples. The columns at the right are the CPU summary:
vmstat -y 1 5procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
1 0 0 2708020 33996 1176632 0 0 0 0 1135 87 25 0 75 0 0 0
1 0 0 2708020 33996 1176632 0 0 0 0 1146 144 25 0 75 0 0 0r is the run queue length, which is how many processes are ready to use a CPU. A run queue consistently larger than the number of CPUs is a sign of CPU pressure. The cpu columns mirror the meaning of the top header. Newer procps releases also add a gu column. It shows the time spent running guest virtual machines.
In the output above, one process keeps the run queue at 1 and us sits at 25. On a four-core machine, that is one core running at full speed.
Method 5: sar
sar, also from sysstat, can print current samples and read saved activity logs. On Ubuntu 24.10 and newer, history collection is enabled when you install sysstat. On Debian and older Ubuntu releases, enable it manually:
sudo sed -i 's/^ENABLED="false"/ENABLED="true"/' /etc/default/sysstat
sudo systemctl enable --now sysstatThe collector setup differs between distributions. If sar shows no saved history, check your distribution’s sysstat service or timer configuration.
Show current CPU samples:
sar -u 1 503:15:01 PM CPU %user %nice %system %iowait %steal %idle
03:15:02 PM all 2.34 0.00 0.71 0.05 0.00 96.90
03:15:03 PM all 2.18 0.00 0.69 0.04 0.00 97.09Each row is a sample interval. Combine with -f to read an older log, for example sar -u -f /var/log/sysstat/sa10 for the tenth of the month. Ubuntu and Debian store the logs in /var/log/sysstat/. Fedora and RHEL use /var/log/sa/. This is the right tool when you need to confirm that a slowdown reported yesterday lined up with a CPU spike.
Method 6: ps
The ps command
lists every process and lets you sort by CPU percentage. The pattern most admins reach for is:
ps -eo pid,user,%cpu,%mem,comm --sort=-%cpu | head PID USER %CPU %MEM COMMAND
1437 dejan 23.5 4.2 firefox
2049 dejan 11.2 2.8 node
1102 root 4.7 0.9 systemd-journalThe output is a snapshot at the moment ps ran. The %CPU value is the average CPU usage over the lifetime of the process, not an instantaneous reading. For a live view, repeat the command with watch:
watch -n 2 'ps -eo pid,user,%cpu,%mem,comm --sort=-%cpu | head'watch reruns the command every two seconds. You get a refreshing list of the nine busiest processes without leaving the shell.
To measure per-process usage over an interval, use pidstat from the sysstat package. The following command samples every second, five times:
pidstat -u 1 5When the sampling ends, pidstat prints an average for each process that used CPU time:
Average: UID PID %usr %system %guest %wait %CPU CPU Command
Average: 1000 2978 100.00 0.00 0.00 0.00 100.00 - sh
Average: 1000 2980 0.00 0.33 0.00 0.00 0.33 - pidstatThe sh process used a full core for the whole interval. Unlike the ps value, this number reflects only the last five seconds.
Method 7: uptime and Load Averages
The uptime command
is the smallest of the lot. Without arguments it prints the system uptime and the load average:
uptime 15:04:23 up 3:17, 2 users, load average: 0.42, 0.35, 0.31The three numbers are the average number of processes that are runnable or in uninterruptible sleep over the last 1, 5, and 15 minutes. Compare them with nproc:
nproc8A load average consistently above the logical CPU count can indicate CPU contention, but it can also reflect processes blocked on I/O. A lower load does not rule out a bottleneck, such as one saturated CPU or a slow disk. Check the per-CPU usage and I/O wait alongside the load average. The 15-minute value is the trend; the 1-minute value reacts to short spikes. For a closer look at how to read these numbers, see the guide on load average in Linux .
Method 8: CPU Usage in a Script
Sometimes you need a single number, for example in a monitoring script or an alert. Take one mpstat sample and subtract both idle time and I/O wait from 100:
LC_ALL=C mpstat 1 1 | awk '$1 == "Average:" && $2 == "all" {print 100 - $6 - $NF}'25.19mpstat waits one second and prints an Average line. LC_ALL=C keeps the label in English and uses a decimal point regardless of your locale. awk selects the aggregate row and subtracts %iowait in the sixth field and %idle in the last field from 100.
If sysstat is not installed, read the counters from /proc/stat directly. The first line of that file holds the time each CPU state has used since boot. Both examples exclude idle time and I/O wait but include steal time on virtual machines. The script below reads the counters twice, one second apart, and calculates the share of the difference:
#!/bin/bash
read -r cpu user nice system idle iowait irq softirq steal _ < /proc/stat
total1=$((user + nice + system + idle + iowait + irq + softirq + steal))
idle1=$((idle + iowait))
sleep 1
read -r cpu user nice system idle iowait irq softirq steal _ < /proc/stat
total2=$((user + nice + system + idle + iowait + irq + softirq + steal))
idle2=$((idle + iowait))
echo "CPU usage: $(( 100 * ((total2 - total1) - (idle2 - idle1)) / (total2 - total1) ))%"Run the script with bash:
bash ~/cpu-usage.shCPU usage: 25%Bash arithmetic works with integers only, so the result is rounded down. A single reading from top in batch mode is less reliable for this job. The first frame it prints is not a fresh one-second sample.
Method 9: Capacity Context
Before you read CPU usage, know what the host has. lscpu summarizes the CPU model, sockets, cores, and threads. For a deeper hardware view, see the guide on checking CPU information in Linux
.
lscpuArchitecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 46 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Vendor ID: GenuineIntel
Model name: Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz
Thread(s) per core: 1
Core(s) per socket: 8
Socket(s): 1Thread(s) per core: 1 means hyper-threading is disabled or not present, so each logical CPU is a physical core. A high CPU usage on a chip with eight physical cores is different from the same number on a four-core chip with hyper-threading.
Troubleshooting
mpstat: command not found
The sysstat package is not installed. Install it with sudo apt install sysstat on Ubuntu, Debian, and Derivatives, or sudo dnf install sysstat on Fedora, RHEL, and Derivatives.
sar reports Cannot open /var/log/sysstat/
Sample collection is not enabled. Set ENABLED="true" in /etc/default/sysstat and enable the service with sudo systemctl enable --now sysstat. Wait at least one collection interval (10 minutes by default) before rerunning sar.
top shows more than 100% CPU for one process
The default mode shows percentage relative to a single CPU, so a multi-threaded process can exceed 100 percent. Press Shift+I to toggle Irix mode off, and the value normalizes across all CPUs.
Load average looks high but no process consumes CPU
Load includes processes in D state, which is uninterruptible sleep. Check ps -eo state,pid,comm | awk '$1 ~ /D/' to find processes blocked on I/O. The cause is usually a slow or stalled disk.
CPU bars are missing in htop
The CPU meters were removed from the htop configuration. Press F2, open Meters, and add the CPUs (1/1) meter to one of the columns. htop saves the change to ~/.config/htop/htoprc.
FAQ
Which tool should I check first?
Run top or htop for a live picture, then drop to mpstat and sar when you need numbers or history. ps answers the per-process question once you know there is a problem.
What does %steal mean?%steal is the time the hypervisor took from the guest VM to run something else. A consistent non-zero %steal value on a VM means the host is over-committed and the guest cannot get the CPU it asked for.
How do I count CPUs from a script?
Use nproc for the logical CPU count, or nproc --all to include offline CPUs. Both return a single integer and are stable across distributions.
Is high CPU always bad?
No. A batch job can use all available CPU capacity without causing a problem. High usage needs attention when it causes slow responses, missed deadlines, or sustained CPU queueing. Load average alone cannot tell you whether the CPU is the bottleneck because it also includes processes blocked on I/O.
Conclusion
Start with top or htop to find a busy process, then use pidstat to measure its CPU usage over an interval. If the slowdown has already passed, check the saved sar samples for that period.
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 1000+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page