sched-design-CFS.txt 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. This is the CFS scheduler.
  2. 80% of CFS's design can be summed up in a single sentence: CFS basically
  3. models an "ideal, precise multi-tasking CPU" on real hardware.
  4. "Ideal multi-tasking CPU" is a (non-existent :-)) CPU that has 100%
  5. physical power and which can run each task at precise equal speed, in
  6. parallel, each at 1/nr_running speed. For example: if there are 2 tasks
  7. running then it runs each at 50% physical power - totally in parallel.
  8. On real hardware, we can run only a single task at once, so while that
  9. one task runs, the other tasks that are waiting for the CPU are at a
  10. disadvantage - the current task gets an unfair amount of CPU time. In
  11. CFS this fairness imbalance is expressed and tracked via the per-task
  12. p->wait_runtime (nanosec-unit) value. "wait_runtime" is the amount of
  13. time the task should now run on the CPU for it to become completely fair
  14. and balanced.
  15. ( small detail: on 'ideal' hardware, the p->wait_runtime value would
  16. always be zero - no task would ever get 'out of balance' from the
  17. 'ideal' share of CPU time. )
  18. CFS's task picking logic is based on this p->wait_runtime value and it
  19. is thus very simple: it always tries to run the task with the largest
  20. p->wait_runtime value. In other words, CFS tries to run the task with
  21. the 'gravest need' for more CPU time. So CFS always tries to split up
  22. CPU time between runnable tasks as close to 'ideal multitasking
  23. hardware' as possible.
  24. Most of the rest of CFS's design just falls out of this really simple
  25. concept, with a few add-on embellishments like nice levels,
  26. multiprocessing and various algorithm variants to recognize sleepers.
  27. In practice it works like this: the system runs a task a bit, and when
  28. the task schedules (or a scheduler tick happens) the task's CPU usage is
  29. 'accounted for': the (small) time it just spent using the physical CPU
  30. is deducted from p->wait_runtime. [minus the 'fair share' it would have
  31. gotten anyway]. Once p->wait_runtime gets low enough so that another
  32. task becomes the 'leftmost task' of the time-ordered rbtree it maintains
  33. (plus a small amount of 'granularity' distance relative to the leftmost
  34. task so that we do not over-schedule tasks and trash the cache) then the
  35. new leftmost task is picked and the current task is preempted.
  36. The rq->fair_clock value tracks the 'CPU time a runnable task would have
  37. fairly gotten, had it been runnable during that time'. So by using
  38. rq->fair_clock values we can accurately timestamp and measure the
  39. 'expected CPU time' a task should have gotten. All runnable tasks are
  40. sorted in the rbtree by the "rq->fair_clock - p->wait_runtime" key, and
  41. CFS picks the 'leftmost' task and sticks to it. As the system progresses
  42. forwards, newly woken tasks are put into the tree more and more to the
  43. right - slowly but surely giving a chance for every task to become the
  44. 'leftmost task' and thus get on the CPU within a deterministic amount of
  45. time.
  46. Some implementation details:
  47. - the introduction of Scheduling Classes: an extensible hierarchy of
  48. scheduler modules. These modules encapsulate scheduling policy
  49. details and are handled by the scheduler core without the core
  50. code assuming about them too much.
  51. - sched_fair.c implements the 'CFS desktop scheduler': it is a
  52. replacement for the vanilla scheduler's SCHED_OTHER interactivity
  53. code.
  54. I'd like to give credit to Con Kolivas for the general approach here:
  55. he has proven via RSDL/SD that 'fair scheduling' is possible and that
  56. it results in better desktop scheduling. Kudos Con!
  57. The CFS patch uses a completely different approach and implementation
  58. from RSDL/SD. My goal was to make CFS's interactivity quality exceed
  59. that of RSDL/SD, which is a high standard to meet :-) Testing
  60. feedback is welcome to decide this one way or another. [ and, in any
  61. case, all of SD's logic could be added via a kernel/sched_sd.c module
  62. as well, if Con is interested in such an approach. ]
  63. CFS's design is quite radical: it does not use runqueues, it uses a
  64. time-ordered rbtree to build a 'timeline' of future task execution,
  65. and thus has no 'array switch' artifacts (by which both the vanilla
  66. scheduler and RSDL/SD are affected).
  67. CFS uses nanosecond granularity accounting and does not rely on any
  68. jiffies or other HZ detail. Thus the CFS scheduler has no notion of
  69. 'timeslices' and has no heuristics whatsoever. There is only one
  70. central tunable:
  71. /proc/sys/kernel/sched_granularity_ns
  72. which can be used to tune the scheduler from 'desktop' (low
  73. latencies) to 'server' (good batching) workloads. It defaults to a
  74. setting suitable for desktop workloads. SCHED_BATCH is handled by the
  75. CFS scheduler module too.
  76. Due to its design, the CFS scheduler is not prone to any of the
  77. 'attacks' that exist today against the heuristics of the stock
  78. scheduler: fiftyp.c, thud.c, chew.c, ring-test.c, massive_intr.c all
  79. work fine and do not impact interactivity and produce the expected
  80. behavior.
  81. the CFS scheduler has a much stronger handling of nice levels and
  82. SCHED_BATCH: both types of workloads should be isolated much more
  83. agressively than under the vanilla scheduler.
  84. ( another detail: due to nanosec accounting and timeline sorting,
  85. sched_yield() support is very simple under CFS, and in fact under
  86. CFS sched_yield() behaves much better than under any other
  87. scheduler i have tested so far. )
  88. - sched_rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler
  89. way than the vanilla scheduler does. It uses 100 runqueues (for all
  90. 100 RT priority levels, instead of 140 in the vanilla scheduler)
  91. and it needs no expired array.
  92. - reworked/sanitized SMP load-balancing: the runqueue-walking
  93. assumptions are gone from the load-balancing code now, and
  94. iterators of the scheduling modules are used. The balancing code got
  95. quite a bit simpler as a result.