在 eBPF 中重新实现我的 Linux Rust 调度程序

1

   

概述

用 Rust 编写的 Linux 调度程序的主要瓶颈 scx_rustland 是内核和用户空间之间的通信。

BPF_MAP_TYPE_RINGBUF 即使使用环形缓冲区( / )可以大大改善通信本身,但 BPF_MAP_TYPE_USER_RINGBUF 多级队列不可避免地会导致调度程序以不太节省工作量的方式运行。

这具有双重效果,使得基于 vruntime 的调度策略更有效(能够积累更多任务并优先处理那些对延迟要求更严格的任务),但任务排队也有缺点,即不能充分利用 CPU 的能力,可能会导致吞吐量方面的倒退。

为了减少这种“缓冲区膨胀”效应,我决定在 BPF 中完全重新实现 scx_rustland,摆脱用户空间开销,并将这个新的调度程序命名为 scx_bpfland。

2

   

执行

scx_bpfland 使用与分类交互式任务和常规任务相同的逻辑 scx_rustland。它根据每秒自愿上下文切换的平均次数来识别交互式任务,当此平均值超过移动阈值时,将其分类为交互式任务。此外,明确唤醒的任务会立即标记为交互式任务,并且除非其平均自愿上下文切换次数低于阈值,否则将保持这种状态。

每个 CPU 都有队列,用于直接将任务分派到空闲 CPU。如果所有 CPU 都处于繁忙状态,则将任务分派到全局优先级队列或全局常规队列(取决于任务被归类为“交互式”还是“常规”)。

然后,首先从每个 CPU 队列中执行任务,然后从优先级队列中执行任务,最后从常规队列中执行任务。这意味着常规任务可能会被交互式任务所取代,因此为了防止无限期的饥饿,scx_bpfland 有一个“饥饿时间阈值”参数(可通过命令行配置),当超过阈值时,该参数强制调度程序从常规队列中至少执行一个任务。

对于被归类为“交互式”的任务,如果在全局常规队列之前使用单独的队列,则可以以类似中断的方式立即处理“交互式”事件。

最后,scx_bpfland 根据优先级和共享队列中等待的任务数量,为任务分配一个可变的时间片:等待的任务越多,时间片越短。这确保在最大时间片期间内,所有排队的任务都有机会运行(取决于它们的优先级和“交互性”)。

3

   

测试

调度程序的逻辑非常简单,但在实践中被证明非常有效。当然,它并不是在所有可能的情况下都表现良好,但调度程序的整个目的是高度专业化,优先考虑延迟敏感的工作负载,而不是 CPU 密集型工作负载。

因此,scx_bpfland 不应将其视为默认 Linux 调度程序 (EEVDF) 的替代品,它总体上仍然是最佳选择。

然而,在某些特殊情况下,当延迟很重要时, scx_bpfland 可以提供改进的、一致的响应水平。

这次运行的 Phoronix 测试套件精选测试 主要旨在测量延迟和响应时间,显示了对所执行的交互任务进行积极优先排序的一些好处 scx_bpfland。

4

   

结果

5e0cef64d1371d0c17b78f093cc3db99.png

与默认调度程序相比,PostgreSQL 和 Hackbench 都显示出显着的提升(PostgreSQL 的读/写延迟高达 39%),因为它们的工作负载纯粹受延迟限制。

FFMpeg 也显示出一些改进(实时流式传输提高 9%,上传配置文件提高 7%),主要是因为工作负载不仅仅是编码,还涉及消息传递(以生产者 - 消费者的方式)。

nginx 显示出 8.4% 的提升,这也是因为基准测试主要强调短暂连接(测量连接响应时间)。

与 EEVDF 相比, Apache 的性能下降了 9% scx_bpfland。

nginx 和 Apache 基准测试都依赖于 wrk,这是一个 HTTP 基准测试工具,具有多线程设计和通过 epoll 和 kqueue 可扩展的事件通知系统。

为了从调度程序的角度更好地理解正在发生的事情,我们可以查看在 30 秒的运行期间两种情况下客户端 (wrk) 的运行队列延迟(任务在调度程序队列中等待的时间)的分布:

[nginx - EEVDF]


@usecs:
[1]                   21 |                                                    |
[2, 4)              1590 |@@@@                                                |
[4, 8)              6090 |@@@@@@@@@@@@@@@@@                                   |
[8, 16)            18371 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
[16, 32)            7527 |@@@@@@@@@@@@@@@@@@@@@                               |
[32, 64)            8514 |@@@@@@@@@@@@@@@@@@@@@@@@                            |
[64, 128)           1915 |@@@@@                                               |
[128, 256)          1695 |@@@@                                                |
[256, 512)          2029 |@@@@@                                               |
[512, 1K)           2148 |@@@@@@                                              |
[1K, 2K)            2234 |@@@@@@                                              |
[2K, 4K)            2114 |@@@@@                                               |
[4K, 8K)            1729 |@@@@                                                |
[8K, 16K)           1274 |@@@                                                 |
[16K, 32K)           740 |@@                                                  |
[32K, 64K)           251 |                                                    |
[64K, 128K)           31 |                                                    |
[128K, 256K)           8 |                                                    |
[256K, 512K)           1 |                                                    |
[512K, 1M)             0 |                                                    |
[1M, 2M)               0 |                                                    |
[2M, 4M)               0 |                                                    |
[4M, 8M)               0 |                                                    |
[8M, 16M)              1 |                                                    |
[16M, 32M)             1 |                                                    |


Total samples: 58,284
[nginx - scx_bpfland]


@usecs:
[2, 4)              5552 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@           |
[4, 8)              6944 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
[8, 16)             5813 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@         |
[16, 32)            4092 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                      |
[32, 64)            2433 |@@@@@@@@@@@@@@@@@@                                  |
[64, 128)           1840 |@@@@@@@@@@@@@                                       |
[128, 256)          1867 |@@@@@@@@@@@@@                                       |
[256, 512)          2499 |@@@@@@@@@@@@@@@@@@                                  |
[512, 1K)           3104 |@@@@@@@@@@@@@@@@@@@@@@@                             |
[1K, 2K)            1902 |@@@@@@@@@@@@@@                                      |
[2K, 4K)             936 |@@@@@@@                                             |
[4K, 8K)             432 |@@@                                                 |
[8K, 16K)            143 |@                                                   |
[16K, 32K)           104 |                                                    |
[32K, 64K)            63 |                                                    |
[64K, 128K)           37 |                                                    |
[128K, 256K)          37 |                                                    |
[256K, 512K)          14 |                                                    |
[512K, 1M)            22 |                                                    |
[1M, 2M)               8 |                                                    |
[2M, 4M)               1 |                                                    |
[4M, 8M)               2 |                                                    |
[8M, 16M)              2 |                                                    |
[16M, 32M)             1 |                                                    |
[32M, 64M)             1 |                                                    |


Total samples: 37,849
[Apache - EEVDF]


@usecs:
[1]                22688 |@@@@@@                                              |
[2, 4)            178176 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
[4, 8)             78276 |@@@@@@@@@@@@@@@@@@@@@@                              |
[8, 16)            96198 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@                        |
[16, 32)           24042 |@@@@@@@                                             |
[32, 64)            6795 |@                                                   |
[64, 128)           5518 |@                                                   |
[128, 256)          6581 |@                                                   |
[256, 512)          7415 |@@                                                  |
[512, 1K)           8184 |@@                                                  |
[1K, 2K)            8709 |@@                                                  |
[2K, 4K)            9001 |@@                                                  |
[4K, 8K)            5881 |@                                                   |
[8K, 16K)           2933 |                                                    |
[16K, 32K)          1255 |                                                    |
[32K, 64K)           364 |                                                    |
[64K, 128K)           72 |                                                    |
[128K, 256K)         111 |                                                    |
[256K, 512K)          50 |                                                    |
[512K, 1M)             8 |                                                    |
[1M, 2M)               0 |                                                    |
[2M, 4M)               1 |                                                    |


Total samples: 462,258
[Apache - scx_bpfland]


@usecs:
[2, 4)              1153 |@                                                   |
[4, 8)              6057 |@@@@@@@@@                                           |
[8, 16)             5591 |@@@@@@@@                                            |
[16, 32)            4188 |@@@@@@                                              |
[32, 64)            5526 |@@@@@@@@                                            |
[64, 128)          12015 |@@@@@@@@@@@@@@@@@@                                  |
[128, 256)         25987 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@            |
[256, 512)         33505 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
[512, 1K)           9405 |@@@@@@@@@@@@@@                                      |
[1K, 2K)             575 |                                                    |
[2K, 4K)             585 |                                                    |
[4K, 8K)             838 |@                                                   |
[8K, 16K)            900 |@                                                   |
[16K, 32K)          1166 |@                                                   |
[32K, 64K)          1061 |@                                                   |
[64K, 128K)          423 |                                                    |
[128K, 256K)          61 |                                                    |
[256K, 512K)          25 |                                                    |
[512K, 1M)            13 |                                                    |
[1M, 2M)               5 |                                                    |
[2M, 4M)               3 |                                                    |
[4M, 8M)               1 |                                                    |
[8M, 16M)              2 |                                                    |


Total samples: 109,085

首先让我们看一下样本量(通过 bpftrace 在每次任务切换时收集)。我们可以看到,Apache 的任务切换次数比 nginx 高得多(大约 10 倍)。

考虑到客户端是相同的(wrk),差异显然是在服务器上,实际上 Apache 以阻塞方式处理响应,而 nginx 以非阻塞方式处理响应。

top 的输出也证实了这一点,我们可以看到 nginx 使用的 CPU 比客户端 (wrk) 多得多,而在 Apache 的情况下则相反。

因此,在 Apache 场景中,客户端和服务器均被归类为“交互式” scx_bpfland,因为它们具有阻塞特性;而在 nginx 场景中,客户端 (wrk) 被归类为交互式,而服务器 (nginx) 被归类为 CPU 密集型,因此客户端的优先级更高。这有助于提高生产者/消费者管道的整体性能,在使用 scx_bpfland 时在基准测试中获得更好的分数。

从客户端运行队列延迟的分布也证实了这一点:使用 nginx 时,任务在调度程序队列中花费的时间较少 scx_bpfland,而在 Apache 场景中则相反。

显然,运行队列延迟只是一个指标,并不总是准确代表实际性能:任务可能会在调度程序的队列中花费更多时间,但仍能实现整体性能的提高,例如,如果生产者/消费者管道得到更好的优化。然而,在这种情况下,它似乎准确地解释了两个调度程序之间的性能差距。

那么,我们如何才能改进,scx_bpfland 以便在 Apache 场景中也能更好地工作呢?通过不要过于激进地缩减服务员函数中任务的可变时间片,可以缓解性能下降。

通过调整这个逻辑,我们也可以改善这个特定的场景,可能会退化其他场景,但这就是好处 sched_ext:允许快速实施和开展实验并实施专门的调度策略。

Apache 的回归表明它 scx_bpfland 总体上不是一个更好的调度程序,但它强调了一个事实,即可以利用它 sched_ext 来快速实现和测试专门的调度程序。

5

   

结论

总之, 使用 Rust 在用户空间中设计新的调度程序原型,然后在 BPF 中重新实现它们可以成为设计新的专用调度程序的有效工作流程。

此类技术提供的快速编辑/编译/测试周期 sched_ext 对于快速迭代这些原型非常有价值,使开发人员能够在更短的时间内获得有意义的结果。

scx_bpfland 是这种方法的一个实际示例,展示了如何将灵活的 Rust 用户空间环境中的初始开发有效地过渡到 BPF 以增强性能。

这个实验不仅强调了 sched_ext 和 eBPF 在实现高效和适应性调度程序开发方面的强大组合,而且还表明这 sched_ext 可能是实现 Linux 中可插入模块化调度的基本一步。

推荐

运维技能大合集


随手关注或者”在看“,诚挚感谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值