LWN:利用BPF控制CPU调度器!
共 2946字,需浏览 6分钟
·
2021-11-14 00:08
关注了就能看到更多这么棒的文章哦~
Controlling the CPU scheduler with BPF
By Jonathan Corbet
October 21, 2021
DeepL assisted translation
https://lwn.net/Articles/873244/
虽然 BPF 虚拟机在 Linux 出现以来不久之后就存在了,但在大部分时间里,它的作用仅限于(正如其全名 Berkley packet filter 所暗示的那样)过滤数据包。2012 年,随着 seccomp() 过滤功能的引入,这种情况开始发生变化,2014 年,随着 extended BPF 虚拟机的到来,变革的步伐加快了。此时,BPF hook 在许多内核子系统中都已经存在了。不过,有一个领域仍然没有 BPF 的身影,那就是 CPU scheduler。如果 Roman Gushchin 的这个 patch set 今后有机会进入 mainline 的话,情况就会得以改变。
内核中有几个 CPU 调度器,每个都适合一些特定类型的 workload。不过在没有 realtime 实时进程的系统中,几乎所有的调度工作都是由完全公平调度器(CFS,Completely Fair Scheduler)完成的,以至于大多数人提到调度器的时候都是在指它。CFS 是一个非常复杂的机制。它实现了一套努力学习(hard-learned)的启发式规则,希望能使各种 workload 场景下的性能最大化,并有一些控制开关用在这些启发式规则需要一些调整的情况下。不过,CPU 调度是一项复杂的任务,因此 CFS 的结果也同样并不是被所有用户认为总是最佳方案。
Gushchin 在 patch set 的 cover letter 中一开始就提到,他对 CFS 各种控制开关的效果进行了深入的研究,发现绝大多数对 workload 的性能没有什么影响。最后,总结了几个相对简单的决定:
换句话说,我们的一些 workload 是希望让那些长期运行的任务被短暂运行的任务抢占从而提升性能,而一些只有短暂运行的任务的 workload 则是希望永远不要被抢占,才能提升性能。
在不同的 workload 之中都需要有不同的最佳调度策略,所以很有必要能根据需要来调整策略。Gushchin 指出,大多数 workload 目前使用 CFS 都已经挺不错的了,因此不应该仅仅针对其他一些过小众的 workload 来对 CFS 进行更多调整。
这正是 BPF 在内核其他部分得以存在的典型情况。因为它可以为用户提供了能够改变策略的灵活性,既能满足他们的需要,同时速度又足够快,因此可以用在像 CPU 调度器这样的非常关注性能的子系统中,而且在不使用它的系统中也不会增加开销。直到现在还没有人认真尝试将 BPF 集成到调度器中,其实这种事情早该出现了。
Gushchin 的 patch set 为影响 CPU 调度器决策的 BPF program 创建了一个新的 BPF program type(BPF_PROG_TYPE_SCHED)。这些程序有三个挂载点(attachment point):
cfs_check_preempt_tick,在处理调度器的周期性 timer tick 时被调用。加载到这里的 BPF 程序可以查看有哪个进程正在运行。如果应该允许该进程继续运行的话,这个 hook 就可以返回一个负数来避免发生抢占。相反,正数的返回值则会通知调度器应该把它切换到另一个进程,也就是应该发生抢占。如果返回值为 0 的话,则由调度器决定该怎么做,就好像这个 hook 从来没有被运行一样。
cfs_check_preempt_wakeup,当一个进程被内核唤醒时会被调用。负数返回值将阻止这个进程抢占当前运行的进程,正数返回值将强制抢占,而 0 则由调度器自己决定。
cfs_wakeup_preempt_entity,与 cfs_check_preempt_wakeup 类似,但是当一个新的进程被选择执行时,它才会被调用,并且可以影响这里的决定。负数返回值表示没有抢占,正数返回值则会强制抢占,返回值为 0 则由调度器的其他决策部分来决定。
Gushchin 指出,在 Facebook 第一次使用这些 hook 的实验 "看起来很有效果"。他现在来公开 patch set,主要是希望能开始讨论如何在调度器中使用 BPF。
整体来说,这个目标似乎并没有实现。围绕这些 patch 的对话相对来说比较平淡。最重要的评论来自 Qais Yousef,因为他来自移动场景这个领域,所以对调度器问题有不同的看法。他指出,在 mobile 场景,厂商倾向于大量修改 CPU 调度器(见 https://lwn.net/Articles/820825/ 介绍的某个厂商的调度器改动)。Yousef 希望看到调度器能够被改进到不再需要这些厂商改动为止,他担心如果增加 BPF hook 的话,就会阻碍这一努力:
所以我担心的是,这个改动会打开使用 hook 的方式这扇大门,今后也许不再是用来进行平台特有的微小优化。而且,这将阻止人们来正确讨论如何真正解决调度器中的那些真实存在的问题,因为开发者可以有更简单的方法了,就是在用户空间中直接实现他想做的改动。我不确定我们大家是否能控制好这些钩子的使用。
Yousef 后来承认,这个功能可能有价值,但建议应该严格控制。他说,其他先不说,这里用作调度器 hook 的 BPF 程序应该需要位于在内核代码 tree 之内,凡是 out-of-tree 的 hook 都要作为 kernel 被 taint 的标志,就跟 loadable module 那边的工作方式一致。
Gushchin 希望能通过让改动调度器代码的工作更加容易,从而使得这个新的 BPF hook 可以用来加速调度器的开发,而不是拖慢开发节奏。同时,他建议要让供应商将他们的调度器改动采用 BPF program 的方式来实现,这可能比他们现在创建的各种 patch 改动方式要更好。
除了这次交流之外,这个 patch set 还没有收到来自调度器的核心开发者或 BPF 社区的任何重要反馈意见。如果这项工作要被考虑合入 mainline 内核的话,这种讨论程度肯定是不够的。允许用户空间 hook 到调度器中,这可能确实是比较难以推销的一个想法,但这个想法似乎不太可能很快消失。不管是好是坏,Linux 内核应该为各种各样的用户服务,要想为每一个用户都提供最好的解决方案,这总是一个很大的挑战。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~