英语

调度器 Nice 设计

本文档解释了新 Linux 调度器中改进和精简的 nice 级别实现的设计思路。

在 Linux 下,Nice 级别一直比较弱,人们不断地要求我们让 nice +19 的任务占用更少的 CPU 时间。

不幸的是,这在旧调度器下不容易实现(否则我们早就做了),因为 nice 级别支持在历史上与时间片长度耦合,而时间片单位由 HZ 时钟驱动,因此最小的时间片是 1/HZ。

在 O(1) 调度器(在 2003 年)中,我们将负 nice 级别改为比 2.4 版本中更强(人们对这个改变感到满意),并且我们还有意地校准了线性时间片规则,以便 nice +19 级别_正好_是 1 个 jiffy。为了更好地理解,时间片图表如下所示(简陋的 ASCII 艺术警告!)

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

因此,如果有人真的想重新调整任务的 nice 值,+19 会比正常的线性规则产生更大的影响。(早期就放弃了更改 ABI 以扩展优先级的解决方案。)

这种方法在一段时间内有效,但后来随着 HZ=1000,1 个 jiffy 变成了 1 毫秒,这意味着 0.1% 的 CPU 使用率,我们觉得这有点过度。过度_不是_因为它是一个太小的 CPU 利用率,而是因为它会导致太频繁的(每毫秒一次)重新调度。(因此会破坏缓存等等。请记住,这是很久以前的事情,硬件较弱且缓存较小,并且人们正在以 nice +19 运行数值计算应用程序。)

因此,对于 HZ=1000,我们将 nice +19 更改为 5 毫秒,因为这感觉是正确的最小粒度 - 这转化为 5% 的 CPU 利用率。但是对于 nice+19 的基本 HZ 敏感属性仍然存在,我们从未收到过关于 nice +19 在 CPU 利用率方面太_弱_的任何投诉,我们只收到(仍然)它太_强_的投诉 :-)

总而言之:我们一直希望使 nice 级别更加一致,但在 HZ 和 jiffy 及其与时间片和粒度之间糟糕的设计级别耦合的约束下,这实际上是不可行的。

关于 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 分配与它是 +5 或 +10 时不同。

针对 Linux nice 级别支持的第三个抱怨是负 nice 级别不够“有力”,因此很多人不得不求助于在 RT 优先级(例如 SCHED_FIFO)下运行音频(和其他多媒体)应用程序。但这引起了其他问题:SCHED_FIFO 不是防饥饿的,并且有错误的 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 级别动态范围的自动副作用。