xv6, line by line
lab 8
Lab 88 Stride scheduling with nice

Lab 8 · reveal · 16 steps · 5 commits

Stride scheduling with nice: the reference solution

The scheduler in this tree gives every runnable process the same treatment: each of the three harts walks the process table in slot order and runs whatever is RUNNABLE, one timer tick at a time. A compile job and an editor get the same share of the CPU, and there is no way to ask for more or less.

In this lab you give each process a number of tickets and replace round robin with stride scheduling: a process with twice the tickets should get twice the CPU, and the schedule should be deterministic, not a lottery. The rule fits in one sentence. The questions start when you try to apply it on three harts at once. How do you find “the process with the smallest value” when three schedulers scan the same table, each holding one lock at a time? What value should a process have when it wakes up after a long sleep, or when it has just been created? When should a process be charged for the CPU it uses? What happens when the counter wraps? And what can a proportional-share scheduler promise at all when there are as many harts as processes?

The reference solution is five small commits. You will measure round robin and stride scheduling side by side, on 1, 2 and 3 harts, with a CPU-time counter the kernel keeps for every process, and break the design five ways on purpose: one break leaves a process running on two harts at once, and in another two schedulers deadlock and the third hart hangs behind them.

Each step shows one change on the branch ext/08-stride, the code around it, and the state of the machine when that code runs.

The route
  1. 1Tickets live with the fields p->lock protects kernel/proc.h
  2. 2settickets, under the caller's own lock kernel/sysproc.c
  3. 3The instrument, CPU time per process kernel/proc.c
  4. 4fork passes the tickets on kernel/proc.c
  5. 5The test: CPU time in a window user/stridetest.c
  6. 6Sleepers that really sleep user/stridetest.c
  7. 7The checks, and round robin's result user/stridetest.c
  8. 8The scan: look at everyone, one lock at a time kernel/proc.c
  9. 9Re-check under the lock, charge, run kernel/proc.c
  10. 10Commit 3's fork copies the parent's pass kernel/proc.c
  11. 11Virtual time, and a lock of its own kernel/proc.c
  12. 12The scheduler moves virtual time kernel/proc.c
  13. 13A sleeper wakes at virtual time kernel/proc.c
  14. 14New processes start at virtual time, and so do killed sleepers kernel/proc.c
  15. 15Ctrl-P shows the passes kernel/proc.c
  16. 16The whole scheduler, and what it cost kernel/proc.c

Keys: ← → step · Home start