CPU: Reading Load, Utilization & Run Queues

System Monitoring & Performance Diagnosis

Chapter 2 · CPU: Reading Load, Utilization & Run Queues

Chapter 1 left one number deliberately unexplained: a load average of 8.42 in that chapter's top snapshot. This chapter explains exactly what load average measures (and what it surprisingly includes), why it means nothing at all without knowing the machine's core count, and how to read the rest of the CPU line — including two fields, wa and st, that can mean "slow" isn't really a CPU problem at all.

Load Average vs. CPU Utilization: Two Different Numbers

CPU utilization (the percentage figures in top's %Cpu(s) line) describes how busy the CPU is right now, over a very short interval. Load average is a different measurement entirely: a running average, over 1, 5, and 15 minutes, of the number of processes that were either using the CPU or waiting for something.

Load average includes more than just CPU-hungry processes
On Linux, a process waiting on disk I/O — not just one waiting for a CPU core to become free — counts toward load average too. This is a genuinely common source of confusion: a high load average doesn't necessarily mean the CPU is the bottleneck at all. Chapter 4 covers disk I/O in depth, but it's worth knowing now that this chapter's own load-average number can be telling a disk story as easily as a CPU one — which is exactly why the rest of this chapter's fields matter.

What "Normal" Load Actually Depends On: Core Count

A load average of 8 means something completely different on a 4-core machine than on a 16-core one — the raw number is meaningless without knowing how many cores are actually available to share the work.

$ nproc 4
Load average ÷ core countWhat it suggests
Well under 1.0Comfortably idle — plenty of spare capacity
Around 1.0Fully utilized, but not yet queueing — every core is busy, nothing is waiting
Well over 1.0Genuinely overloaded — more work wants to run than the machine can currently handle, and some of it is waiting

Chapter 1's own example machine has 4 cores. A load average of 8.42 divided by 4 is just over 2.1 per core — meaning, on average, roughly twice as much work wants to run as the machine can actually handle at once. That's a genuine, meaningful overload signal, not a false alarm.

The %Cpu(s) Line In Depth

Chapter 1's snapshot also showed: 87.3 us, 9.1 sy, 0.0 ni, 2.1 id, 0.0 wa, 0.0 hi, 1.5 si, 0.0 st. Each field means something specific:

FieldWhat it measures
usTime spent running normal application ("user-space") code
syTime spent in the kernel — system calls, scheduling, and similar overhead
niUser-space time specifically from processes running at a lowered ("niced") priority
idGenuinely idle — nothing to do
waiowait — the CPU is idle, but specifically because it's waiting on a disk (or other I/O) operation to finish, not because there's no work
hi / siHardware and software interrupt handling
stSteal time — on a virtual machine, time this VM wanted to run but the hypervisor gave the physical CPU to a different tenant instead

In Chapter 1's snapshot, wa and st are both 0.0, and us alone accounts for 87.3% — confirming this genuinely is a CPU-bound problem, not a disk bottleneck wearing a CPU-shaped disguise, and not a cloud tenant losing CPU time to a noisy neighbor.

High wa means go check Chapter 4, not this chapter
If a system shows a high load average alongside a high wa figure, the CPU itself usually isn't the actual bottleneck — it's sitting idle, waiting on disk. Treating that as a CPU problem and looking for a runaway process will come up empty; the real evidence lives in disk I/O metrics instead.
Steal time is a real cause you can't fix locally
On a cloud or virtualized server, a nonzero st figure means the physical hardware underneath this machine is genuinely oversubscribed by the hosting provider — no amount of tuning inside this particular system will fix it, because the CPU time is being taken away one layer below where this system has any control. Recognizing steal time early avoids a long, fruitless search through this machine's own processes for a cause that isn't there.

Run Queue: Processes Actually Waiting for a Turn

vmstat shows a more direct number: the r column, the count of processes literally waiting for a CPU core right now — a narrower, more specific signal than load average's broader, I/O-inclusive definition.

$ vmstat 1 3 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 7 0 1935872 422528 145200 4523000 0 0 2 8 980 2100 85 9 4 2 0 8 0 1935872 415200 145200 4519200 0 0 0 4 975 2050 88 8 3 1 0 6 0 1935872 409600 145200 4517800 0 0 0 0 960 1980 86 9 4 1 0

An r value consistently well above the core count (6–8, on a 4-core machine) across several samples confirms the same story load average already suggested: genuine, sustained CPU contention, not a brief one-off spike.

Windows doesn't have a direct equivalent to load average
Windows relies primarily on CPU utilization percentage, viewed in Task Manager or Resource Monitor, rather than a load-average-style rolling number. Performance Monitor's Processor Queue Length counter is the closest analogue to vmstat's r column — the number of threads actually waiting for CPU time — but there's no built-in figure that mirrors Linux's 1/5/15-minute averaged load number.

Working Example: Fully Reading Chapter 1's Snapshot

Put together: a load average of 8.42 on a 4-core machine is roughly 2.1 per core — genuinely overloaded. The %Cpu(s) line's 0.0 wa and 0.0 st rule out both disk I/O and hypervisor steal time as explanations. 87.3% us confirms the time is being spent running actual application code, not the kernel or interrupt handling. A follow-up vmstat check showing r consistently at 6–8 confirms this isn't a passing blip. Every piece of evidence agrees: this machine has a genuine CPU bottleneck, and the next step is identifying which specific process is responsible — Chapter 8's own territory.

Hands-On Exercises

Exercise 1

Explain why a load average of 8 could be either a genuine problem or completely normal, depending on one specific piece of information this chapter says is required to interpret it.

📄 View solution
Exercise 2

A machine shows a high load average alongside a high wa figure in top. Explain why this chapter says that's misleading to treat as a CPU problem, and where the real evidence would actually be found.

📄 View solution
Exercise 3

Explain what "steal time" specifically measures, and why this chapter says it can't be fixed by anything done inside the affected virtual machine itself.

📄 View solution

Chapter 2 Quick Reference

  • Load average includes processes waiting on I/O, not just CPU-hungry ones — it can reflect a disk problem, not just a CPU one
  • Always divide load average by core count (nproc) before judging it — the raw number alone is meaningless
  • %Cpu(s) breakdown: us (app code), sy (kernel), wa (iowait — a disk story, not CPU), st (steal time — a hypervisor-level cause you can't fix locally)
  • vmstat's r column is a more direct, narrower measure of processes actually waiting for a CPU core right now
  • Windows has no direct load-average equivalent — CPU utilization % and Processor Queue Length are the closest counterparts
  • Next chapter: Memory: Used, Free, Cached & the "Available" Metric