处理器调度问题

操作系统具有在中断后选择任何进程执行的权利

  • 那应该选哪个比较好……呢?
Context *on_interrupt(Event ev, Context *ctx) {
  if (!current) {
    current = &tasks[0];  // First trap
  } else {
    current->context = ctx;
    current = current->next;  // Round-robin 轮转调度
  }
  return current->context;
}

1950-1960s 操作系统研究的重要话题

  • (因此出现在操作系统书上)

调度是一个很复杂的问题

三个本质问题

  • 到下次中断有 10,000,000 个时钟周期,分配给哪个线程?
  • 学校预算 10,000,000 科研经费,怎么分给院系?
  • 发改委下拨 1000,000,000,000 经费,怎么分给全中国?

设计空间

  • 建模 (理解和总结 “过去发生了什么”)
  • 预测 (试图预知未来可能发生什么)
  • 决策 (在预测下作出对系统最有利的选择)

允许用户定制处理器调度

UNIX niceness

  • -20 .. 19 的整数,越 nice 越让别人得到 CPU
    • -20: 极坏; most favorable to the process
    • 19: 极好; least favorable to the process
  • 基于优先级的调度策略
    • RTOS: 坏人躺下好人才能上
      • 好人流下了悔恨的泪水
    • Linux: 10 nice ≈ CPU 资源获得率相差 10 倍
  • 不妨试一试: nice/renice
    taskset -c 0 nice -n 19 yes > /dev/null &
    taskset -c 0 nice -n  9 yes > /dev/null &
    

Round-Robin 的缺陷

系统里有两个进程

  • 交互式的 Vim,单线程
  • 纯粹计算的 mandelbrot.c, 32 个线程

Round-Robin

  • Vim 花 0.1ms 处理完输入就又等输入了
    • 主动让出 CPU
  • Mandelbrot 使 Vim 在有输入可以处理的时候被延迟
    • 必须等当前的 Mandelbrot 转完一圈
    • 数百 ms 的延迟就会使人感到明显卡顿
  • 你们会在 L2 里遇到这样的问题
    • 表现形式:tty 卡顿

策略:动态优先级 (MLFQ)

不会设置优先级?让系统自动设定!

  • 设置若干个 Round-Robin 队列
    • 每个队列对应一个优先级
  • 动态优先级调整策略
    • 优先调度高优先级队列
    • 用完时间片 → 坏人
      • Mandelbrot: 请你变得更好
    • 让出 CPU I/O → 好人
      • Vim: 你可以变得更坏
  • 阅读教科书

策略:Complete Fair Scheduling (CFS)

试图去模拟一个 “Ideal Multi-Tasking CPU”:

  • “Ideal multi-tasking CPU” is a (non-existent :-)) CPU that has 100% physical power and which can run each task at precise equal speed, in parallel, each at 1/n. For example: if there are 2 tasks running, then it runs each at 50% physical power — i.e., actually in parallel.

“让系统里的所有进程尽可能公平地共享处理器”

  • 为每个进程记录精确的运行时间
  • 中断/异常发生后,切换到运行时间最少的进程执行
    • 下次中断/异常后,当前进程的可能就不是最小的了

CFS: 实现优先级

操作系统具有对物理时钟的 “绝对控制”

  • 每人执行 1ms,但好人的钟快一些,坏人的钟慢一些
    • vruntime (virtual runtime)
    • vrt[i] / vrt[j] 的增加比例 = wt[j] / wt[i]
const int sched_prio_to_weight[40] = {
  /* -20 */ 88761, 71755, 56483, 46273, 36291,
  /* -15 */ 29154, 23254, 18705, 14949, 11916,
  /* -10 */  9548,  7620,  6100,  4904,  3906,
  /*  -5 */  3121,  2501,  1991,  1586,  1277,
  /*   0 */  1024,   820,   655,   526,   423,
  /*   5 */   335,   272,   215,   172,   137,
  /*  10 */   110,    87,    70,    56,    45,
  /*  15 */    36,    29,    23,    18,    15,
};