LWN:补全EEVDF调度器!

文章讲述了Linux内核6.6引入的EEVDF调度器的最新进展,包括行为调整、修复工作和新功能,如帮助延迟敏感任务的功能,以及时间片控制的改进。作者PeterZijlstra回归后提交的补丁旨在使调度更加公平且对延迟敏感任务更友好。
摘要由CSDN通过智能技术生成

关注了就能看到更多这么棒的文章哦~

Completing the EEVDF scheduler

By Jonathan Corbet
April 11, 2024
ChatGLM translation
https://lwn.net/Articles/969062/

最早虚拟截止时间优先(EEVDF, Earliest Virtual Deadline first)调度器已作为 6.6 内核的一个选项合并了。这代表了对 Linux 系统中 CPU 调度方式的重大改变,但自那以后,EEVDF 相关领域一直相对安静。然而,调度器开发者 Peter Zijlstra 在长时间离开后回归,就带来了一系列补丁,旨在完成 EEVDF 工作。除了一些修复工作外,这项工作还包括一个显著的行为改变和一个旨在帮助对延迟(latency)敏感的任务的新功能。

快速回顾 EEVDF

EEVDF 调度器的工作是将可用的 CPU 时间平均分配给系统中所有可运行的任务(假设所有任务具有相同的优先级)。如果有四个相同优先级的任务争夺 CPU,那么每个任务都将获得 25%的份额。每个任务被分配一个虚拟运行时间,表示其分配的 CPU 份额;在四个任务的例子中,虚拟运行时间可以被视为以 25%的墙上时钟速度运行的时钟。当任务运行时,内核计算任务的虚拟运行时间与实际运行时间之间的差值;其结果被称为“滞后(lag)”。滞后值是正数就意味着任务缺少了 CPU 时间,而负值则表示任务获得了超出其份额的时间。

如果一个任务的滞后值为零或更大,则被视为“可运行(eligible)”;每当 CPU 调度器必须选择要运行的任务时,它会从可运行任务集里面进行选择。对于这些任务中的每一个,都会计算一个虚拟截止时间(virtual deadline),方法是将其剩余的时间片(time slice)加到其成为可运行状态的时间上。虚拟截止时间最早的任务将被选择运行。由于较长的时间片会导致虚拟截止时间较晚,因此具有较短时间片的任务(通常是延迟敏感的)倾向于首先运行。

举个例子可能有助于理解滞后是如何在决策中起作用的。假设有三个 CPU 密集型任务,分别称为 A、B 和 C,它们都在同一时间开始。在它们中任何一个运行之前,它们的滞后值都为零:


ABC
Lag:0ms0ms0ms

由于没有任务的 lag 值为负,所有任务都是可运行的。如果调度器选择 A 作为第一个运行的任务,并且使用 30 毫秒的时间片(随便选择一个数字),如果 A 运行直到时间片用尽,滞后情况将如下所示:


ABC
Lag:-20ms10ms10ms

在这 30ms 内,每个任务都本应得到 10ms(总时间的三分之一)的 CPU 时间。A实际上获得了 30ms,因此它积累了-20ms 的滞后值;其他两个任务由于没有获得任何 CPU 时间,所以滞后了 10ms,反映了它们应该获得的 10ms CPU 时间。

任务 A 不再是可运行的,所以调度器将不得不选择其他任务中的一个。如果给 B 一个 30ms 的时间片,并且 B 使用它,情况变为:


ABC
Lag:-10ms-10ms20ms

再次,每个任务都赚得了对应于其应得 CPU 时间的 10ms 的滞后值,并且 B 运行了 30ms。现在只有 C 是可运行的,所以调度器的下一个决定是很容易的。

可以从上面的表格中看到 EEVDF 调度器的一个特性,即系统中所有滞后值的总和始终为零。

滞后和睡眠

滞后计算仅跟可运行的任务相关;如果一个 task 睡眠了一天,那实际上也并没有错过它的虚拟运行时间(因为它没有),因此它不会积累出巨大的滞后值。然而,当任务入睡时,调度器会保留任务的当前滞后值,并在任务唤醒时从该值开始继续。因此,如果一个任务在入睡前已经超出了其分配的时间,那么它将在之后被唤醒时为此付出代价。

然而,会有这样一种情况,此时保留任务的滞后值可能没有意义。那个刚睡了一天的任务真的应该因为昨天被允许运行得有点超过其分配而受到惩罚吗?很明显,迟早,任务的滞后值应该恢复为零。但是何时恢复并不完全清楚。正如 Zijlstra在这个系列的补丁中指出的,在睡眠时立即把滞后值忘掉,就能使任务能够在时间片结束时(其滞后可能为负)短暂入睡,结果是它们获得了更多的 CPU 时间。简单地随时间来对滞后值进行衰减也不会有多大作用,他总结说,因为滞后值与虚拟运行时间相关,而虚拟运行时间以不同(并且变化的)速度在流逝。

解决方案是在虚拟运行时间内对正在睡眠的任务的滞后值进行衰减。在补丁集中,这个想法的实现挺有趣的。当一个任务入睡时,它通常会从运行队列中被删除,以便调度器无需再考虑它。但是,通过这个新的补丁,一个去睡觉的/不合格的/进程将会留在队列中,但被标记为“延迟出队(deferred dequeue)”。由于它是不合格的,所以它不会被选择执行,但它的滞后值将根据经过的虚拟运行时间而增加。一旦滞后变为正数,调度器将注意到任务并将其从运行队列中移除。

这个实现的结果是,短暂入睡的任务将无法摆脱负的滞后值,但长时间入睡的任务最终将被免除其滞后值的债务。有趣的是,正的滞后值将被无限期地保留,直到任务再次运行。

时间片控制

如上所述,具有较短时间片的任务将具有更早的虚拟截止时间,导致调度器更早地选择它们。但是,在当前的内核中,当调度器寻找要运行的新任务时,这种隐式的优先级只有在实际任务醒来时才会生效。如果一个具有较短时间片的延迟敏感任务醒来,它可能仍然必须等待当前任务用尽其时间片(可能很长)才能运行。然而,Zijlstra 的补丁系列通过允许一个任务在其虚拟截止时间更早时抢占另一个任务来改变这一点。这种改变为短时间片任务执行节奏的一致性更好,同时可能稍微降低了长时间运行任务的速度。

然而,还有一个问题:如何指定某个任务应该获得较短的时间片?在当前的内核中,非实时进程无法告诉内核其时间片应该是多少,因此这组补丁系列添加了这个能力。具体来说,一个任务可以使用sched_setattr()系统调用,在 sched_attr 结构的 sched_runtime 字段中传递所需的片段时间(以纳秒为单位)。在当前的内核中,这个字段只用于截止时间调度。通过这个补充,任何任务都可以请求更短的时间片,这将导致它更早地运行,可能更频繁地运行。然而,如果请求的时间片太短,任务将经常被抢占,总体运行速度会变慢。

时间片的允许范围为 100 微秒到 100 毫秒。对于感兴趣的人来说,Zijlstra 已经用 ASCII-art 图在这个补丁的变更日志中说明了各种时间片选择的结果。

这些改动处于相对早期阶段,似乎需要修订几版才能被合并。问题的之一是尚未处理与控制组的交互,这方面可能完全无法正常工作。但是一旦细节得到处理,EEVDF 调度器应该能准备好来供更广泛的使用了。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

7fd13f47f1ffa84ca4f1136703555318.jpeg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值