Context Switching

Every 4 milliseconds (by default), the Linux scheduler runs and may switch the CPU from one process to another. This context switch saves the current process's state, restores another's, and resumes it. It takes microseconds — but with thousands of switches per second on a busy system, the overhead adds up.

What Is a Context Switch?

What exactly gets saved and restored during a context switch? The CPU's complete execution state: general-purpose registers (RAX-R15), instruction pointer (RIP), stack pointer (RSP), flags register (RFLAGS), floating-point/SIMD state (x87/SSE/AVX registers), and memory management state (CR3 register — the page table pointer, which causes a TLB flush when changed). The kernel stores this in the process's task_struct.
Context switch sequence: Process A running on CPU 0 | Timer interrupt fires (every 4ms, configurable via CONFIG_HZ) | Scheduler decides to run Process B | switch_to(A, B): 1. Save A's registers to A's kernel stack 2. Save A's CR3 (page table pointer) 3. Save A's FPU state (if used FP instructions) 4. Load B's kernel stack pointer 5. Load B's CR3 (new page tables!) - CR3 change flushes the TLB (expensive!) 6. Restore B's FPU state 7. Restore B's registers from B's kernel stack 8. Jump to B's saved RIP (where B was interrupted) | Process B continues running

The TLB Cost — Why Context Switches Are Expensive

What makes context switching expensive beyond saving registers? The TLB (Translation Lookaside Buffer) caches virtual-to-physical address translations. When you switch to a different process with a different address space, you load their page tables (by changing CR3). This invalidates TLB entries from the previous process. The next process starts with a cold TLB — every memory access for a while needs a full page table walk instead of a cached translation. This is the dominant cost of context switching.
# PCID (Process-Context Identifiers) — reduce TLB flush cost # Modern CPUs (Sandy Bridge+): TLB entries tagged with PCID # Different processes can coexist in TLB without interfering # CR3 switch doesn't flush all TLB entries, only process's own # Linux uses PCID since kernel 4.14 (if CPU supports it) # Check if PCID is in use: dmesg | grep -i pcid # PCID disabled because TLB_HARDIRQ_CPU is set # or: PCID enabled and supported # Voluntary vs involuntary context switches: cat /proc/1234/status | grep ctxt # voluntary_ctxt_switches: 9876 (process called sleep/wait/IO) # nonvoluntary_ctxt_switches: 234 (preempted by scheduler) # High involuntary = CPU contention (process wants to run but preempted)

Thread Switching vs Process Switching

# Thread context switch (within same process): # - Save/restore registers: YES # - Change page tables (CR3): NO (same address space) # - TLB flush: NO (same PCID/address space) # - Switch kernel stack: YES (each thread has its own) # Cost: ~1-3 microseconds # Process context switch: # - Save/restore registers: YES # - Change page tables (CR3): YES # - TLB flush: YES (or PCID tag switch) # - Switch kernel stack: YES # Cost: ~3-10 microseconds (cold TLB effects linger much longer) # Why goroutines/green threads are faster: # Go runtime scheduler manages 1000s of goroutines on N OS threads # Goroutine switch = save/restore 7 registers (no syscall, no TLB flush) # OS thread switch needs kernel involvement # Goroutine switches take ~100ns vs 3000ns for OS thread switch

Measuring Context Switches

# System-wide context switch rate: vmstat 1 # r b swpd free buff cache si so bi bo in cs us sy id wa # 2 0 0 2048M 512M 8192M 0 0 0 0 512 1234 5 2 93 0 # ^^ cs = context switches/sec # Per-process: pidstat -w 1 # PID cswch/s nvcswch/s Command # 1234 45.0 2.3 nginx # Total context switches since boot: grep ctxt /proc/stat # ctxt 123456789 # Monitor in real time: watch -n1 "grep ctxt /proc/stat" # High context switch rate causes: # 1. Many threads competing for CPU # 2. Frequent I/O (blocking, then unblocking) # 3. Over-threading (more threads than CPUs, each getting tiny slices)

Frequently Asked Questions

What will I learn here?

This page covers the core concepts and techniques you need to understand the topic and progress confidently to the next lesson.

How should I use this page?

Start with the overview, then follow the section links to deepen your understanding. Use the table of contents on the right to jump to specific sections.

What should I read next?

Use the navigation below to continue to the next lesson or explore related topics.