调度器 Nice 设计¶
本文档解释了新的 Linux 调度器中改进和精简的 nice 级别实现的设计思路。
在 Linux 下,nice 级别一直都相当弱,人们不断地催促我们使 nice +19 任务占用更少的 CPU 时间。
不幸的是,这在旧的调度器下不容易实现(否则我们早就做了),因为 nice 级别支持在历史上与时间片长度相关联,并且时间片单位由 HZ 时钟驱动,因此最小的时间片是 1/HZ。
在 O(1) 调度器(2003 年)中,我们将负 nice 级别更改为比 2.4 中强得多(人们对该更改感到满意),并且我们还故意校准了线性时间片规则,使得 nice +19 级别_恰好_为 1 个时钟滴答。为了更好地理解它,时间片图看起来像这样(俗气的 ASCII 艺术警告!):
A
\ | [timeslice length]
\ |
\ |
\ |
\ |
\|___100msecs
|^ . _
| ^ . _
| ^ . _
-*----------------------------------*-----> [nice level]
-20 | +19
|
|
因此,如果有人真的想重新设置任务的 nice 值,+19 会比正常的线性规则产生更大的影响。(早期就放弃了更改 ABI 以扩展优先级的解决方案。)
这种方法在一段时间内在某种程度上有效,但后来当 HZ=1000 时,导致 1 个时钟滴答为 1 毫秒,这意味着 0.1% 的 CPU 使用率,我们认为这有点过分。过分_不是_因为它 CPU 利用率太小,而是因为它会导致过于频繁的(每毫秒一次)重新调度。(因此会破坏缓存等。请记住,这是很久以前的事情了,当时硬件较弱,缓存较小,人们在 nice +19 下运行数值计算应用程序。)
因此,对于 HZ=1000,我们将 nice +19 更改为 5 毫秒,因为这感觉像是正确的最小粒度 - 这转化为 5% 的 CPU 利用率。但是 nice+19 的基本 HZ 敏感属性仍然存在,我们从来没有收到过任何关于 nice +19 在 CPU 利用率方面太_弱_的投诉,我们只收到了关于它(仍然)太_强_的投诉 :-)。
总而言之:我们一直希望使 nice 级别更加一致,但是在 HZ 和时钟滴答以及它们与时间片和粒度之间的不良设计级别耦合的限制下,这实际上是不可行的。
关于 Linux 的 nice 级别支持的第二个(不那么频繁但仍然周期性发生)的抱怨是它围绕原点的非对称性(您可以在上图中看到演示),或者更准确地说:nice 级别行为取决于_绝对_ nice 级别,而 nice API 本身从根本上是“相对的”
int nice(int inc);
asmlinkage long sys_nice(int increment)
(第一个是 glibc API,第二个是 syscall API。)请注意,'inc' 相对于当前的 nice 级别。像 bash 的 “nice” 命令之类的工具会反映此相对 API。
使用旧的调度器,如果您例如启动一个 nice +1 的任务和一个 nice +2 的任务,那么两个任务之间的 CPU 分配将取决于父 shell 的 nice 级别 - 如果它的 nice 级别为 -10,则 CPU 分配与 nice 级别为 +5 或 +10 时不同。
针对 Linux 的 nice 级别支持的第三个抱怨是负 nice 级别不够“有力”,因此许多人不得不求助于在诸如 SCHED_FIFO 之类的 RT 优先级下运行音频(和其他多媒体)应用程序。但是这引起了其他问题:SCHED_FIFO 不是防饥饿的,并且有 bug 的 SCHED_FIFO 应用程序也可能使系统永久锁定。
v2.6.23 中的新调度器解决了所有三种类型的抱怨
为了解决第一个抱怨(nice 级别不够“有力”),调度器与“时间片”和 HZ 概念解耦(并且粒度成为了一个独立于 nice 级别的概念),因此可以实现更好、更一致的 nice +19 支持:使用新的调度器,nice +19 任务获得了与 HZ 无关的 1.5%,而不是它们在旧调度器中获得的 3%-5%-9% 的可变范围。
为了解决第二个抱怨(nice 级别不一致),新的调度器使 nice(1) 对任务具有相同的 CPU 利用率效果,而不管其绝对 nice 级别如何。因此,在新调度器上,运行 nice +10 和 nice 11 任务具有与运行 nice -5 和 nice -4 任务之间相同的 CPU 利用率“分割”。(一个将获得 55% 的 CPU,另一个将获得 45%。)这就是为什么将 nice 级别更改为“乘法”(或指数)的原因 - 这样无论您从哪个 nice 级别开始, “相对结果”将始终相同。
第三个抱怨(负 nice 级别不够“有力”并且迫使音频应用程序在更危险的 SCHED_FIFO 调度策略下运行)几乎由新调度器自动解决:更强的负 nice 级别是重新校准的 nice 级别动态范围的自动副作用。