ยง10.3โ€“10.7Cache Affinity โ€ฆ Summary

Part I OSTEP pp. 107โ€“112 ยท ~8 min read

  • cache affinity
  • sqms
  • mqms
  • load imbalance
  • migration
  • work stealing

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 , 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 โ€” 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:

SQMS: five jobs, four CPUs, one shared queue โ€” everyone bounces
t =
CPU 0
CPU 1
CPU 2
CPU 3
tick 1 / 5 ยท one time slice per tickjob Ajob Bjob Cjob Djob E

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:

SQMS with an affinity patch: Aโ€“D stay home; only E migrates
t =
CPU 0
CPU 1
CPU 2
CPU 3
tick 1 / 5 ยท one time slice per tickjob Ajob Bjob Cjob Djob E

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 . 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 :

MQMS after C finishes: Q0 = {A}, Q1 = {B, D} โ€” load imbalance
t =
CPU 0
CPU 1
tick 1 / 8 ยท one time slice per tickjob Ajob Bjob Cjob Djob E

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 . For the idle-CPU case, one migration (move B or D over) fixes everything. The subtler A-alone case needs migration that never stops:

Continuous migration fixes the A-alone case: work moves until load balances
t =
CPU 0
CPU 1
tick 1 / 12 ยท one time slice per tickjob Ajob Bjob Cjob Djob E

Start: A alone on CPU 0; B and D alternate on CPU 1.

But when to migrate? The standard mechanism is work stealing :

Q0 (source โ€” low on jobs)AQ1 (target โ€” fuller)BDE1. occasionally peek2. notably fuller? steal a jobpeek too often โ†’ the overhead you built MQMS to avoid ยท too rarely โ†’ imbalance persists ยท the threshold: a black art

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:

Three Linux multiprocessor schedulers โ€” no consensus (click cells for detail)
queue designpolicy familycharacter
O(1)multi-queuepriority-based (MLFQ-like)constant-time decisions
CFSmulti-queueproportional share (stride-like)the mainline default
BFSSINGLE queueproportional share (EEVDF)simplicity for desktops
Dotted-underlined cells have explanations โ€” click one.

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

  1. 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?

5 questions