Sched Nice Design[译]

2015/10/29

Categories: Linux Tags: kernel scheduler

原文: Sched Nice Design

这份文档解释了在新的 Linux 调度器中更新和改善的优先级实现思想。

优先级曾经在 Linux 上一直非常薄弱,人们一直地纠缠我们,让我们实现优先级 +19 的任务能消耗更少的 CPU 时间。

不幸地,这在旧的调度器上并不容易实现,(否则很早以前我们就完成了)因为优先级支持在历史上是与时间片长度耦合的,并且时间片单位是由 HZ 嘀嗒驱动的,所以最小的时间片曾经是 1/HZ 。

在 O(1) 调度器(在 2003 年)我们改变了负优先级使之比之前在 2.4 中更健壮(并且大家都喜欢这个改变),并且我们有意地标准化线性时间片规则,因此 +19 优先级将真正是 1 时钟周期。 为了更好的理解这个,时间片图像这样(丑陋的 ASCII 艺术预警!):

                   A
             \     | [timeslice length]
              \    |
               \   |
                \  |
                 \ |
                  \|___100msecs
                   |^ . _
                   |      ^ . _
                   |            ^ . _
 -*----------------------------------*-----> [nice level]
 -20               |                +19
                   |
                   |

所以如果有人真地想重新安排任务的优先级,+19 将会给它一个比普通线性规则所给的还大很多的标记。 (改变 ABI 来扩展优先级的解决方案很早被否决了。)

这个方法有时候有点用,但是之后在 HZ=1000 的时候,它使得 1 时钟周期变成了 1 毫秒,这意味着我们所感受到的 0.1% CPU 使用量确实有点过多。 过多不是因为 CPU 利用率太低,而是因为它引起了太频繁的(一次一毫秒的)重新调度。 (并且例如,这会引起损坏缓存。记住,硬件非常落后,缓存非常小,并且人们把数学运算运行在优先级 +19,这已是很久以前。)

所以对于 HZ=1000 我们把优先级 +19 提升到 5 毫秒,因为这让人感觉是正确的最小尺度-并且这转化成了 5% 的 CPU 利用率。 但是优先级 +19 的根本的 HZ 敏感的属性继续保留着,并且我们从未得到一个关于优先级 +19 在 CPU 利用率上太差的单独的抱怨,我们只得到关于这个(仍然)太强大的怨念:-)

综上所述:我们一直希望让优先级更一致的,但是在 HZ 和时钟周期,及它们令人讨厌的与时间片和粒度耦合的设计等级约束下,这不是真正切实可行的。

第二个( 低频但是仍然周期性地发生)关于 Linux 的优先级支持的抱怨是它围绕(你可以看到上图的证据)起点的不对称,或者更如实地:优先级行为依据绝对的优先级的事实也是如此,然而优先级 API 是基本上“相关的”:

int nice(int inc);

asmlinkage long sys_nice(int increment)

(第一个是 glibc API,第二个是 syscall API。) 注意 inc 是与此时的优先级有关的。像 bash 的 nice 命令这种工具正是借鉴这个相关 API。

如果例如你用 +2 优先级开始一个优先任务,+1 优先级开始另一个任务,CPU 将会依据父 shell 的优先级分配这两个任务——如果这个 shell 在 -10 优先级,CPU 的分配是与它在 +5 或者 +10 优先级不一样的。

第三个关于 Linux 的优先级支持的抱怨是负优先级并不“足够简洁有力”,所以很多人不得不重排来运行音频(和其它多媒体)应用在如 SCHED_FIFO 这种 RT 优先级下。 但是这引发了另一个问题:SCHED_FIFO 并不能防范饿死,并且一个古怪的 SCHED_FIFO 应用也可以很好地锁住系统。

在 v2.6.23 上新的调度器解决了所有这三种抱怨:

为了解决第一个(关于优先级不够简洁有力的)抱怨,调度器与“时间片”、HZ 概念解耦,(并且粒度成为独立于优先级的概念), 并且因此,这让实现更好的、更一致的优先级 +19 支持成为可能:在新调度器下,优先级 +19 的任务获得一个 HZ 无关的 1.5%,而不是一个在旧的调度器下获得的 3%-5%-9% 之间的变量。

为了解决第二个(关于优先级不一致的)抱怨,新的调度器让 nice(1) 有相同的 CPU 利用率作用在各个任务上,不管它们优先级的绝对值。 所以在新的调度器,运行一个优先级 +10 和一个优先级 11 的任务有着相同的 CPU 利用率,就像运行一个优先级 -5 和一个优先级 -4 的任务。(一个会得到 55% 的 CPU,另一个 45%。) 这就是为什么优先级变成“倍增的”(或者指数的)——这种方式它无所谓优先级是从何开始的,“相关结果”永远是一样的。

第三个(关于负优先级不够简洁有力和强制音频应用运行在非常危险的 SCHED_FIFO 调度策略下)抱怨,几乎由新的调度器自动解决:更强的负优先级是,优先级重新校准的动态范围自动产生的一个副作用。