Last Minute Notes

CPU Scheduling

CPU scheduling from textbook to Linux: scheduling criteria, preemptive vs non-preemptive, FCFS, SJF, SRTF, priority, round robin, multilevel queues and MLFQ with fully worked Gantt charts, starvation and aging, multiprocessor scheduling and affinity, and how Linux CFS and EEVDF, nice values, and cgroup CPU limits work.

📘 CPU Scheduling

With more runnable tasks than CPU cores, the scheduler decides who runs next and for how long. This page covers the classic algorithms with worked examples (a favorite of written tests and interviews), then how real schedulers like Linux's work. All example numbers were computed with a small simulation script.

Table of Contents

  1. Terms and Criteria
  2. Preemptive vs Non-Preemptive
  3. The Example Workload
  4. FCFS
  5. SJF and SRTF
  6. Round Robin
  7. Priority Scheduling
  8. Multilevel Queues and MLFQ
  9. Comparison
  10. Multiprocessor Scheduling
  11. How Linux Schedules
  12. Questions

1. Terms and Criteria

TermDefinition
Arrival timeWhen the process becomes ready
Burst timeCPU time it needs
Completion timeWhen it finishes
Turnaround timeCompletion - arrival
Waiting timeTurnaround - burst (time spent ready but not running)
Response timeFirst run - arrival
ThroughputProcesses completed per unit time
CPU utilizationFraction of time the CPU is busy

Goals conflict: batch systems maximize throughput, interactive systems minimize response time, and every system wants fairness and no starvation.

Processes alternate between CPU bursts and I/O bursts. CPU-bound tasks have long bursts (video encoding); I/O-bound tasks have short bursts (editors, web servers). Good schedulers favor I/O-bound tasks briefly so devices stay busy and the system feels responsive.


2. Preemptive vs Non-Preemptive

Non-preemptivePreemptive
When the scheduler runsOnly when the running task blocks or exitsAlso on timer interrupts and when a higher priority task arrives
ResponsivenessPoor, one long job blocks everyoneGood
ComplexitySimpleNeeds synchronization for shared data (a task can be interrupted anywhere)
ExamplesFCFS, SJFSRTF, round robin, all modern OS schedulers

The dispatcher performs the actual switch; dispatch latency is the time it takes.


3. The Example Workload

All examples below use this set of processes (times in ms).

ProcessArrivalBurst
P108
P214
P329
P435

4. FCFS

First come, first served: run in arrival order, no preemption.

| P1        | P2    | P3           | P4      |
0           8       12             21        26
ProcessCompletionTurnaroundWaiting
P1880
P212117
P3211910
P4262318
Average15.258.75

Simple and fair in order, but suffers the convoy effect: short jobs wait behind one long job, like cars behind a truck.


5. SJF and SRTF

Shortest job first (non-preemptive): when the CPU frees up, pick the ready job with the shortest burst.

At time 0 only P1 is ready, so it runs to completion. At 8, P2 (4) is shortest, then P4 (5), then P3 (9).

| P1        | P2    | P4      | P3           |
0           8       12        17             26
ProcessCompletionTurnaroundWaiting
P1880
P212117
P3262415
P417149
Average14.257.75

Shortest remaining time first (preemptive SJF): whenever a job arrives, run whichever has the least remaining time.

At 1, P2 arrives with 4 < P1's remaining 7, so P2 preempts P1.

| P1 | P2    | P4      | P1          | P3           |
0    1       5         10            17             26
ProcessCompletionTurnaroundWaiting
P117179
P2540
P3262415
P41072
Average13.06.5

SRTF gives the minimum average waiting time of any algorithm, provably. Two problems:

  1. The OS does not know burst times in advance, so it predicts them with an exponential average of past bursts: next = a * last_actual + (1 - a) * last_prediction.
  2. Long jobs can starve if short ones keep arriving.

6. Round Robin

Each process gets a time quantum; when it expires, the process goes to the back of the ready queue. Convention: processes that arrive during a quantum join the queue before the preempted process.

With quantum 4:

| P1    | P2    | P3    | P4    | P1    | P3    | P4 | P3 |
0       4       8       12      16      20      24   25   26
ProcessCompletionTurnaroundWaiting
P1202012
P2873
P3262415
P4252217
Average18.2511.75

Round robin has worse average waiting time here but much better response time: every process starts within 12 ms, and no one starves.

Choosing the quantum:

QuantumEffect
Very largeDegenerates into FCFS
Very smallGreat responsiveness, but context switch overhead dominates
Rule of thumbAbout 80 percent of CPU bursts should finish within one quantum; typical values 1 to 100 ms

7. Priority Scheduling

Each process has a priority; the highest runs first (preemptive or not). SJF is priority scheduling where priority is the inverse of burst length.

ProblemSolution
Starvation: low priority tasks never runAging: gradually raise the priority of tasks that have waited long
Priority inversion: a high priority task waits on a lock held by a low priority task, while a medium priority task keeps the low one from runningPriority inheritance: the lock holder temporarily inherits the waiter's priority

Priority inversion famously reset the Mars Pathfinder lander repeatedly in 1997, and was fixed remotely by enabling priority inheritance on a mutex in VxWorks.


8. Multilevel Queues and MLFQ

Multilevel queue: separate ready queues by class (system, interactive, batch), each with its own algorithm, and a rule between queues (strict priority or time slices).

Multilevel feedback queue (MLFQ) lets processes move between queues based on behavior, so the scheduler learns which tasks are interactive without being told.

MLFQ rules:

  1. Higher queue always runs first; round robin within a queue.
  2. New tasks start at the top.
  3. Using up the time allotment at a level moves the task down (count total time at a level, not per burst, so tasks cannot game it by yielding just before the quantum ends).
  4. Periodically boost everyone to the top, so CPU-bound tasks do not starve and tasks that became interactive recover.

Windows and classic Unix schedulers were MLFQ variants.


9. Comparison

AlgorithmPreemptiveAvg waiting (example)StarvationBest for
FCFSNo8.75NoBatch, simplicity
SJFNo7.75YesBatch with known lengths
SRTFYes6.5 (optimal)YesTheory baseline
Round robin (q=4)Yes11.75NoTime sharing, response time
PriorityEitherDependsYes, without agingMixed importance
MLFQYesAdaptiveNo, with boostsGeneral purpose OS

10. Multiprocessor Scheduling

ConceptMeaning
Per-CPU run queuesEach core has its own queue to avoid a global lock; Linux does this
Load balancingPeriodically migrate tasks from busy to idle cores (push and pull migration)
Processor affinityKeep a task on the same core to reuse warm caches; soft by default, hard with taskset / sched_setaffinity
NUMA awarenessPrefer the core near the memory a task uses; remote memory access is slower
SMT / hyper-threadingTwo hardware threads share one core's execution units; schedulers prefer idle physical cores first
Heterogeneous coresPerformance and efficiency cores (Apple silicon, Intel P and E cores, ARM big.LITTLE); schedulers use hints (Intel Thread Director) to place tasks
Gang schedulingRun cooperating threads at the same time on different cores

11. How Linux Schedules

Linux has scheduling classes, checked in priority order:

ClassPoliciesUse
Stop / deadlineSCHED_DEADLINE (earliest deadline first with runtime budgets)Hard periodic real-time work
Real-timeSCHED_FIFO, SCHED_RR (static priority 1 to 99)Audio, control loops; a runaway FIFO task can freeze a core
FairSCHED_NORMAL (SCHED_OTHER), SCHED_BATCH, SCHED_IDLEAlmost everything
sched_extScheduling policies written as eBPF programs (merged in 6.12)Experimentation, workload-specific schedulers

CFS and EEVDF

From 2007 to 2023, the fair class used CFS (Completely Fair Scheduler):

  • Each task has a virtual runtime (vruntime): actual CPU time, scaled by weight.
  • Pick the task with the smallest vruntime, kept in a red-black tree (O(log n) insert, O(1) pick of the leftmost).
  • No fixed quantum: time slices come from a target latency divided among runnable tasks.
  • A task that sleeps (I/O-bound) falls behind in vruntime and runs soon after waking, which makes it feel responsive.

Since Linux 6.6 (2023), the fair class uses EEVDF (Earliest Eligible Virtual Deadline First). It keeps the fairness idea but gives each task a virtual deadline, so latency-sensitive tasks can request shorter slices and get scheduled sooner, with fewer heuristics than CFS.

Nice values and weights

  • nice ranges from -20 (highest priority) to 19 (lowest); default 0.
  • Each step is about a 10 percent change in CPU share (weight ratio about 1.25).
  • nice -n 10 ./backup.sh, renice -n 5 -p 1234; only root can lower the nice value.

Containers and CPU limits

cgroups control CPU for groups of tasks:

SettingMeaningKubernetes mapping
cpu.weight (shares)Relative share when there is contentionCPU requests
cpu.max (quota / period)Hard cap, e.g. 50 ms per 100 ms = half a coreCPU limits

The quota is enforced per 100 ms period, so a multi-threaded app with a 1-core limit can burn its quota in 25 ms on 4 threads and then be throttled for 75 ms. This causes mysterious latency spikes; many teams set CPU requests but no CPU limits for latency-sensitive services, and watch nr_throttled in cpu.stat. Runtimes must also respect container limits when sizing thread pools (the JVM and Go runtime detect cgroup limits; Go 1.25 made GOMAXPROCS container-aware by default).


12. Questions

QuestionShort answer
Turnaround vs waiting vs response time?Completion - arrival; turnaround - burst; first run - arrival
Which algorithm minimizes average waiting time?SRTF (preemptive SJF)
Why is SJF hard in practice?Burst length unknown; predict with exponential averaging
What is the convoy effect?Short jobs stuck behind a long one in FCFS
How do you pick an RR quantum?Large enough that most bursts fit, small enough for responsiveness; too small wastes time switching
Starvation and its fix?Low priority never runs; aging or periodic boosts
What is priority inversion?High waits on low holding a lock while medium runs; priority inheritance
How does MLFQ learn task types?Demote tasks that use full quanta, keep ones that block early, boost periodically
How does Linux CFS pick the next task?Smallest vruntime from a red-black tree; replaced by EEVDF in 6.6
What does nice do?Changes the weight, about 10 percent CPU share per step
Why do containers get throttled with idle CPUs on the host?cgroup CPU quota per period is exhausted, regardless of host idle time

Next: Synchronization and Deadlocks.

On this page