Two real cores, four hopeful processes
RUNNING is the only row that is physically real. Everything else is bookkeeping the kernel keeps in RAM.
Core 0 idle
Core 1 idle
Timer chip — programmed to fire an interrupt every few milliseconds. This is the OS's grip on the machine: no matter what user code does, the kernel always gets the CPU back.
Ready queue runnable right now, waiting for a core
Blocked waiting on I/O — not runnable, not the scheduler's problem
Terminated called exit(); the kernel reclaims its memory
A process is never "a bit running". It is in exactly one of these states, and only the kernel may move it.
Fictional addresses, real DRAM
4 KB pages. A virtual address is just page number + offset; the page table says where that page really lives.
Process A — virtual address space
Process B has an identical-looking space, also starting at 0. Same numbers, different reality.
MMU · TLB · page table
MMU
hardware, in the core
Idle. Every load and store in the machine passes through here.
virtual addr—
page number—
offset (12 b)—
physical addr—
VPN
maps to
V
perm
TLB — cache of recent translations
(empty)
idle
Physical DRAM — 12 page frames
Swap on disk — pages the kernel pushed out to make room. Slot 0x2A10 holds A's heap page VPN 5.
read(fd, buf, 4096) — the whole journey
Your process may not talk to the disk. It may only ask. Follow the dot across the privilege boundary.
User mode · ring 3unprivileged
Your programn = read(fd, buf, 4096)
libc wrapperrax=0 rdi=fd rsi=buf
privilege boundary — the only legal door
Kernel mode · ring 0can touch anything
Syscall table~350 entries → sys_read
VFS + page cachefd → inode → block
Schedulerblock / wake / dispatch
NVMe driversubmission queue + doorbell
DMA enginedevice → DRAM, no CPU
Interrupt handlercompletion IRQ
NVMe SSD~90 µs for a 4 KB read
DRAM · page cache pagewhere the 4096 bytes land
Why this boundary exists: the CPU refuses privileged instructions in ring 3. Not "the OS forbids it" — the
silicon faults. That is why a buggy program can crash itself but not the machine.
Wall clock
0.000 ms
nothing dispatched yet
Context switches
0
~1–10 µs each, pure overhead
| Process | State | CPU time used |
|---|
What a context switch actually costs: save every register into the kernel's task struct, load the next
process's registers, swap the page-table root (
CR3) and flush TLB
entries, then run with cold caches until the new working set warms up. The bookkeeping is ~1–10 µs;
the lost cache warmth often costs more.
TLB hits
0
translation ~free
TLB misses
0
walk the page table
Page faults
0
trap to the kernel
Faulting / accessed address—
Resolved frame—
Cost of this access—
Who is in controlprocess A (user mode)
The TLB is the whole trick. A page-table walk is 4 dependent DRAM reads on x86-64. The TLB caches the
answer, so 99%+ of translations cost effectively nothing — the same locality bet the caches make in
Part 3.
Elapsed
0 ns
before the call
Privilege
USER
ring 3
Where the dot isyour program
Your process stateRUNNING
Who owns the coreyour process
Bytes delivered0 / 4096
Forward reference → Part 9
This orchestration is exactly what HFT refuses to pay for. A tick-to-trade path polls the NIC from user space
with kernel bypass — no syscall, no mode switch, no interrupt, no scheduler. It skips this entire diagram,
and buys back several microseconds.
Scheduler trace
Step 0 / 0