wisconsin
Lecture 4 - Advanced Scheduling

Lecture 4 - Advanced Scheduling

Curated by Last modified: 7 min read

Instructor: Tej Chajed Topics: Proportional share scheduling, CFS, weighted fair scheduling, multiprocessor scheduling


Proportional Share Scheduling

Goal: give each of N processes 1/Nth of the time on a CPU

  • 1 process: 100% of CPU
  • 3 processes: each get 1/3rd of CPU

Answers how much time a process gets but not when a process runs.

Fairness: each process gets the same amount — contrast with MLFQ’s goals.


Completely Fair Scheduler (CFS)

Concept

Idea: give each of N processes 1/Nth of the time on a CPU

  • Consider ideal multitasking CPU with infinitesimally small timeslice
    • Context switch instantly after each instruction
  • N processes: each progresses uniformly at 1/Nth rate

Lecture Note

With 1 process, it gets 100% progression speed. With 3 processes, each makes 1/3rd progress.

Design

Goal: give each of N processes 1/Nth of the time on a CPU

How (generally):

  • Keep track of CPU time usage of a process (runtime)
  • Always run the process with the lowest runtime

How it works:

  • I/O bound processes haven’t run in a while, so they are behind and get to catch up quickly
    • Low response time
  • CPU bound processes have run recently, so they get preempted

Fair Scheduling Example

JobArrival(s)Run time (s)Completion time
A05085
B101540
C151030
B501060

Example

At time 15, runtime values are A: 10, B: 5, C: 0. C has the lowest runtime so it runs next. Between times 20-30, A, B, and C all have similar runtimes and rapidly alternate. The scheduler always picks whichever process has the lowest runtime value.

Average Turnaround Time: (85-0) + (40-10) + (30-15) + (60-50) / 4 = 35

Average Response Time: 0 (every job runs immediately upon arrival since new jobs have the lowest runtime)


Problems with Basic CFS

  • Frequent context switches add overhead (~1 us each)
  • Equal isn’t always best: need to weight processes differently
  • Long sleeping tasks: what runtime value when waking up?

Reducing Context Switches

Context switching frequently is inefficient.

Solution: Maximum overrun, C

  • How much ahead of the lowest-time thread can you get, C?
  • Run process Pa if Pa.vruntime < Pb.vruntime - C

Equivalent to a minimum timeslice.

Fair Scheduling Example with C=5

JobArrival(s)Run time (s)Completion time
A05085
B101535
C151025
B501060

Lecture Note

At time 15, runtimes are A: 10, B: 5, C: 5. At time 25, A: 10, B: 10. With C=5 the scheduler switches less often, improving turnaround time to 32.5 while response time remains 0.

Average Turnaround Time: (85-0) + (35-10) + (25-15) + (60-50) / 4 = 32.5

Average Response Time: 0


Weighted Fair Scheduling

What if some processes are more important than others?

  • Add weight to each process. More weight → more runtime
  • Processes run in proportion to weights
    • A: 4, B: 2, C: 1 → runtime proportions 4:2:1

Calculate virtual runtime = real runtime / weight

  • Run the process with the lowest virtual runtime

Overrun uses virtual runtime.

Weighted Fair Scheduling Example (C=5)

JobArrival(s)Run time (s)Weight
A0504
B10152
C15101
B70102

Lecture Note

A has weight 4, so its virtual runtime increases at 1/4 the rate of real time. B at 1/2 rate, C at full rate. A gets proportionally more real CPU time because its virtual runtime grows slower.

Graphical View

Virtual runtime for a process advances when it runs:

  • Shallower slope for processes with larger weight
  • Steeper slope for processes with lower weight

The step between segments shows the maximum overrun.

Lecture Note

vruntime = runtime / weight. In the graph, gcc (higher weight) has a shallower line and bigsim (lower weight) has a steeper line. The weights of the two processes can be inferred from their slopes.


Problem: Long-Sleeping Tasks

What happens when a sleeping task wakes?

JobArrival(s)Run time (s)Weight
A051
B51001
A50501

A runs for 5s (vruntime = 5), then sleeps for 45s. Meanwhile B runs and accumulates vruntime = 45. When A wakes at time 50, its vruntime (5) is far below B’s (45), so A monopolizes the CPU until it catches up.

Key Insight

A sleeping task retains its old (low) vruntime. When it wakes, it unfairly dominates the CPU because the scheduler always picks the lowest vruntime process.

Solution: Reset Vruntime

Calculate minimum vruntime for all running processes.

  • If P.vruntime > minimum → do nothing (short sleep)
  • If P.vruntime < minimum → set P.vruntime = minimum - threshold D
    • D: preemption threshold (>= C)

Example

With D = C: A wakes at time 50 with vruntime reset to min(B.vruntime) - C = 45 - 5 = 40. Now A and B alternate fairly: A runs 50-60 (vruntime 50), B runs 60-70 (vruntime 55), etc.


Multiprocessor Scheduling

Thus far, assumed a single CPU core. With multiple CPUs, things get a lot more complicated.

Symmetric Multiprocessing (SMP)

SMP: 2 or more homogeneous processors (may be in separate physical packages), shared main memory and system bus, single OS that treats all processors equally.

Lecture Note

L3 cache is shared across cores within a CPU package. Each core has its own L1 and L2 caches.

Hyperthreading

Two threads on a single CPU core.

  • Non-hyperthreaded core: Thread 1 alternates between CPU Busy and Memory Stall — CPU is idle during stalls
  • Hyperthreaded core: Thread 2 runs during Thread 1’s memory stalls, filling idle gaps and improving throughput

CPU Caches and Locality

Process performance is linked to locality:

  • Ideally, a process should be placed close to its data

Shared data is problematic due to cache coherency:

  • P3 writes variable x, new value is cached in CPU 2
  • P2 in CPU 1 reads x, but value in main memory is stale

Cache hits are fast. A process has fast access to data on its own CPU, but access to another CPU’s cached data is slow. Memory fetches are slow.

NUMA and Affinity

NUMA (Non-Uniform Memory Access): Architecture where memory access time depends on the location of the data relative to the requesting process.

Cache affinity: try to run processes close to their cached data.


Single Queue Scheduling (SQMS)

SQMS (Single Queue Multiprocessor Scheduling): Most basic design — all processes go into a single queue.

  • CPUs pull tasks from the queue as needed
  • Good for load balancing (CPUs pull processes on demand)

Problems with SQMS

  • The process queue is a shared data structure
    • Necessitates locking, or careful lock-free design
  • SQMS does not respect cache affinity
    • Worst case: processes rarely run on the same CPU

Multi-Queue Scheduling (MQMS)

MQMS (Multiple Queue Multiprocessor Scheduling): Each CPU maintains its own queue of processes. CPUs schedule their processes independently.

Advantages of MQMS

  • Very little shared data — queues are (mostly) independent
  • Respects cache affinity — processes stay on the same CPU

Shortcomings of MQMS

MQMS is prone to load imbalance due to:

  • Different number of processes per CPU
  • Variable behavior across processes

Can lead to idle CPUs or unfair CPU usage.

Process Migration

Must deal with load imbalance through process migration:

  • Push migration: overloaded CPU sends a process to another CPU
    • “I have too many processes, take one”
  • Pull migration (work stealing): underloaded CPU takes a process from another CPU’s queue
    • “I don’t have enough processes, give me one”

Summary

  • Proportional share (fair) scheduling: give processes equal CPU time
  • Pragmatics of fair scheduling: overrun, weighting, reset for sleeping
  • Multiprocessor scheduling: cache locality, affinity, and migration

Linked to this page