# Lecture 4 - Advanced Scheduling Source: https://wisconsin.twango.dev/sp26-cs537/lectures/lecture-04 # Lecture 4 - Advanced Scheduling **Instructor:** Tej Chajed **Topics:** Proportional share scheduling, CFS, weighted fair scheduling, multiprocessor scheduling > [!abstract]- Learning Outcomes > - Compare and contrast basic scheduling (e.g., MLFQ) with fair scheduling (e.g., CFS) > - Analyze limitations of fair scheduling > - Articulate the challenges of 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 > [!note] 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 | Job | Arrival(s) | Run time (s) | Completion time | |-----|------------|---------------|-----------------| | A | 0 | 50 | 85 | | B | 10 | 15 | 40 | | C | 15 | 10 | 30 | | B | 50 | 10 | 60 | > [!example] 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 | Job | Arrival(s) | Run time (s) | Completion time | |-----|------------|---------------|-----------------| | A | 0 | 50 | 85 | | B | 10 | 15 | 35 | | C | 15 | 10 | 25 | | B | 50 | 10 | 60 | > [!note] 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) | Job | Arrival(s) | Run time (s) | Weight | |-----|------------|---------------|--------| | A | 0 | 50 | 4 | | B | 10 | 15 | 2 | | C | 15 | 10 | 1 | | B | 70 | 10 | 2 | > [!note] 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. > [!note] 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? | Job | Arrival(s) | Run time (s) | Weight | |-----|------------|---------------|--------| | A | 0 | 5 | 1 | | B | 5 | 100 | 1 | | A | 50 | 50 | 1 | 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. > [!tip] 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] 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. > [!note] 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 --- ## Related - **Navigation:** [[lecture-03|← Lecture 3]] · [[lecture-05|Lecture 5 →]] - **Exam:** [[exams/midterm-1/index|Midterm 1]] - **Course:** [[README|CS 537 Map of Content]]