Hardware keeps caches coherent, locks keep updates safe โ one performance truth remains before we can pick a scheduler architecture.
10.3 One Final Issue: Cache Affinity
A process running on a CPU builds up state in that CPUโs caches and TLB. Run it there again and it flies; run it elsewhere and it must reload everything (correct either way โ coherence guarantees that โ just slow). That preference is cache affinity cache affinity A process runs faster on the CPU whose caches/TLB already hold its state; schedulers should prefer keeping it there. defined in ch. 10 โ open in glossary , and a multiprocessor scheduler should honor it when it can.
10.4 Single-Queue Scheduling (SQMS)
The obvious first design: keep one queue of ready jobs โ single-queue multiprocessor scheduling sqms Single-queue multiprocessor scheduling โ one shared queue feeds all CPUs; simple and balanced, but lock-limited and affinity-blind. defined in ch. 10 โ open in glossary โ and have each of N CPUs pick the next best job. Maximum reuse of everything from chapters 7โ9. Two problems, though. Scalability: the shared queue needs a lock, and lock contention grows with CPU count โ the machine spends ever more time on overhead. And affinity:
Each CPU grabs the next job from the shared queue: A, B, C, D run; E waits.
Most SQMS implementations patch this with an affinity mechanism โ keep most jobs home, migrate a chosen few:
Same five jobs โ but now the scheduler tries to preserve affinity.
Workable, but complex โ and the lock problem remains untouched.
10.5 Multi-Queue Scheduling (MQMS)
The alternative: one queue per CPU โ multi-queue multiprocessor scheduling mqms Multi-queue multiprocessor scheduling โ per-CPU queues scheduled independently; scalable and affine, but prone to load imbalance. defined in ch. 10 โ open in glossary . An arriving job is placed on one queue (randomly, or the shortest) and scheduled there independently: no shared lock, and affinity comes free โ jobs simply stay put. But a new, fundamental problem appears the moment jobs finish unevenly โ load imbalance load imbalance Some CPUs oversubscribed while others idle โ MQMS's fundamental failure mode when jobs finish unevenly. defined in ch. 10 โ open in glossary :
Each queue schedules independently (round robin here).
The Crux: How To Deal With Load Imbalance
How should a multi-queue multiprocessor scheduler handle load imbalance, so as to better achieve its desired scheduling goals?The answer is to move jobs โ migration migration Moving a job between CPUs to rebalance load โ sometimes once, sometimes continuously. defined in ch. 10 โ open in glossary . For the idle-CPU case, one migration (move B or D over) fixes everything. The subtler A-alone case needs migration that never stops:
Start: A alone on CPU 0; B and D alternate on CPU 1.
But when to migrate? The standard mechanism is work stealing work stealing A low-occupancy queue occasionally peeks at a fuller one and steals jobs; peek frequency trades overhead against imbalance. defined in ch. 10 โ open in glossary :
Work stealing: low-occupancy queues occasionally inspect fuller ones and take jobs. The peek frequency is yet another voo-doo constant.
10.6 Linux Multiprocessor Schedulers
Tellingly, the Linux community never converged on one answer:
| queue design | policy family | character | |
|---|---|---|---|
| O(1) | multi-queue | priority-based (MLFQ-like) | constant-time decisions |
| CFS | multi-queue | proportional share (stride-like) | the mainline default |
| BFS | SINGLE queue | proportional share (EEVDF) | simplicity for desktops |
Both multi-queue (O(1), CFS) and single-queue (BFS) approaches shipped and succeeded โ architecture is a trade-off, not a theorem.
10.7 Summary
SQMS: easy to build and balances load naturally, but locks limit scaling and affinity suffers. MQMS: scales and preserves affinity, but must fight load imbalance with migration machinery. No simple answer exists โ building a general-purpose scheduler remains daunting, where small code changes yield large behavioral differences. Undertake it only if you know exactly what youโre doingโฆ or are being paid handsomely.
And with that, CPU virtualizationโs mechanisms and policies are complete โ from limited direct execution through single-CPU policies to multiprocessors. The Part I finale: two short dialogues, then on to memory.
Homework: multi.py
A multiprocessor scheduler simulator with caches: watch a jobโs cache warm up (-C), pin jobs to CPUs to engineer affinity (-A a:0,b:1,c:1), compare centralized vs per-CPU queues (-p, with the peek interval -P), and hunt for super-linear speedup โ three jobs whose working sets fit per-CPU caches can run MORE than 3ร faster on 3 CPUs than on- Get it at ostep-homework.
Check yourself
1.Why does a process run faster on the CPU it ran on last time โ and is running it elsewhere incorrect?
2.SQMS reuses the single-CPU framework with one shared queue. What are its TWO core weaknesses?
3.In MQMS with Q0 = {A} and Q1 = {B, D}, what goes wrong โ even though every CPU is busy?
4.Why does the A-alone imbalance require CONTINUOUS migration rather than one move?
5.Work stealing balances MQMS load. What tension governs how often a queue should peek at others?