[LWN 新闻] sched_ext 子调度器让单一系统运行多个 CPU 调度器

2026年3月18日 34 次阅读 0 条评论 0 人点赞

作者:Jonathan Corbet | 2026年1月29日

可扩展调度器类(sched_ext)允许安装由一组 BPF 程序构建的自定义 CPU 调度器。它在 6.12 内核中的合并使内核摆脱了此前采用的"一种调度器适用于所有场景"的方法;现在任何系统都可以拥有针对其工作负载优化的自定义调度器。

然而,在任何给定的机器上,仍然是"一种调度器适用于所有场景";整个系统只能加载一个调度器。Tejun Heo 发布的 sched_ext 子调度器补丁系列旨在改变这一状况,允许在单个系统上运行多个 CPU 调度器。

调度器的局限性与子调度器的诞生

Sched_ext 的设计理念是:没有任何调度器能够针对所有可能遇到的工作负载进行优化。子调度器工作进一步扩展了这一理念,指出即使是 sched_ext 调度器也无法为给定系统可能运行的所有工作负载获得最佳性能。

"应用程序通常具有通用调度器无法拥有的领域特定知识。数据库系统了解查询优先级和锁持有者的关键性。虚拟机监视器可以与客户机调度器协调,智能地处理 vCPU 定位。游戏引擎知道渲染期限以及哪些线程是延迟关键型的。"

运行单一工作负载的系统也可以运行针对该工作负载优化的专用调度器。但系统所有者倾向于保持系统繁忙,这意味着在同一台机器上运行多个工作负载。如果同一系统上的两个工作负载受益于不同的调度算法,至少其中一个最终会得到次优性能。

子调度器的工作原理

解决方案是允许 sched_ext 调度器附加到控制组(cgroup)。系统中的每个任务都将受附加到其控制组(或最近的祖先组)的调度器管理。

内核长期以来一直支持 CPU 控制器,允许管理员在控制组之间分配 CPU 资源。有趣的是,子调度器功能并不依赖于 CPU 控制器;而是直接依赖于控制组机制。因此,CPU 控制器仍然负责每个组获得多少 CPU 时间,而子调度器则管理这些 CPU 时间如何在其各自组内的进程中使用。

附加了调度器的控制组可以嵌套最多四层。任何要在控制组层次结构中作为另一个的父级的调度器都必须考虑到这一责任。将子调度器附加到控制组只有在父控制器允许的情况下才会成功。父调度器还控制何时调用子调度器的 dispatch() 回调。

这个回调指示调度器选择下一个要运行的任务并将其添加到特定 CPU 的调度队列中。换句话说,父调度器控制何时可以运行给定的工作负载(由控制组表示),子调度器控制构成该工作负载的进程如何访问 CPU,而 CPU 控制器负责控制它们可以运行多少 CPU 时间。

安全与隔离

内核导出了大量 kfunc,允许 sched_ext 程序在调度器及其下运行的进程上操作。这些 kfunc 需要进行泛化,使其不是针对调度器操作,而是针对适当的子调度器操作。

运行多个调度器的系统还必须格外小心,确保这些调度器不会相互干扰。例如,代表给定调度器运行的 BPF 程序应该无法影响甚至查看可能存在的任何其他调度器。因此,sched_ext kfunc 的泛化必须以保留整个系统的安全性和健壮性的方式进行。

为此,许多 kfunc 都增加了隐式参数,使它们能够访问与运行任务关联的 bpf_prog_aux 结构;从中它们可以获取指向应该处理其工作的子调度器数据的指针。BPF 程序本身无需指定它们正在哪个调度器上操作,也没有能力在任何附加的调度器之外的调度器上操作。内核能够确保它们始终绑定到正确的子调度器。

绕过模式与未来展望

Sched_ext 的设计目的是防止有缺陷的调度器造成过多损害。当检测到运行中的调度器出现问题(例如,可运行任务在合理时间内未被调度到 CPU)时,该调度器将进入"绕过模式"。在有意关闭调度器时也会进入此模式。在绕过模式下,调度器被停用,其下运行的所有任务都被放置在简单的 FIFO 调度器下。

在内核中,绕过调度器是全局的。但在具有多个调度器的系统中,允许一个子调度器将进程扔进全局 FIFO 队列可能会导致与其他子调度器的干扰。因此,当使用子调度器时,如果存在父调度器,父调度器将从进入绕过模式的子调度器继承任务。另一个方向是,如果父调度器进入绕过模式,其下面的任何调度器也将被放置在绕过模式下。

当前的补丁集(版本 1,2025年9月也有 RFC 版本)还不是完整的实现。它主要涵盖调度路径——即给定调度器将任务发送到 CPU 执行的位置。

虽然还有工作要做,但现在已经足够展示整个功能的预期工作方式。有一个修改版的 scx_qmap 调度器能够同时作为父调度器和子调度器运行;它以相对简单的形式展示了调度器本身需要进行的更改。

如前所述,这是早期阶段的工作,尚未完成。因此,不应该期望很快在内核中看到子调度器支持。不难看出这一功能对于运行各种工作负载的系统有多大用处,因此将会有明确的动力推动其完成。到那时,"一种调度器适用于所有场景"的模型将远远落后。


编译来源: 本文基于 LWN.net 文章《Sub-schedulers for sched_ext》翻译整理。

文章评论(0)