LWN:OSPM 2023 报告,第三部分!

OSPM2023会议涵盖了代理执行以解决优先级反转问题,Sched_ext允许通过BPF实现可插拔调度策略,以及优化的定时器模型和动态能源模型以提高能效。文章讨论了这些技术的挑战、潜在解决方案和性能影响。
摘要由CSDN通过智能技术生成

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

Reports from OSPM 2023, part 3

By Jonathan Corbet
June 23, 2023
OSPM
ChatGPT assisted translation
https://lwn.net/Articles/935180/

第五届 Linux 内核中的电源管理和调度会议(简称"OSPM")于 4 月 17 日至 19 日在意大利 Ancona 举行。遗憾的是,LWN 没有参与其中,但与会者已经汇集在一起,撰写了会议讨论的摘要,并且 LWN 有幸能够发布它们。以下是会议的第三天的报告。

Proxy execution

作者:John Stultz(视频 https://youtu.be/QEWqRhVS3lI )

OSPM 的最后一天以关于代理执行(proxy execution)的演讲和讨论开始,代理执行是一种广义的优先级继承形式。代理执行这个想法,多年来由几位核心内核贡献者共同努力推动,但并没有取得很大的进展。

Android 在应用程序方面不使用实时调度(realtime scheduling),但仍需要让前台(foreground)应用程序优先于后台(background)应用程序。通常通过 cgroup 机制来限制后台任务,使前台应用程序获得更多的 CPU 时间。不幸的是,跟 realtime 优先级情况类似,Android 设备也经常遇到优先级反转的问题。低优先级的后台任务有时可能占用了一个重要的前台任务所需要的互斥锁(mutex),但是后台任务被限制了,导致无法运行也就无法释放锁。

解决优先级反转的经典方法是通过 rt_mutexes 进行优先级继承,但这并没有帮助,因为完全公平调度器(CFS)不是严格地跟 realtime scheduling 一样来严格根据优先级顺序选择要运行的任务;在 SCHED_DEADLINE 中也存在相同的问题,需要继承 deadline 而不是优先级。因此需要一种更通用的优先级继承形式,这就是代理执行提供的功能。

代理执行的简单思想是,我们可以将调度器的任务选择算法视为黑盒,并在任何时候选择最重要的任务来运行。但是,我们希望在选择要运行的任务时,除了从当前可运行的任务中选择外,还要考虑被互斥锁阻塞的任务。然后,如果所选任务被阻塞在互斥锁上,我们将选择互斥锁的持有者作为所选任务的"代理",使用所选任务的调度器上下文来运行它。

然而,这个优雅而简单的想法不幸有一些需要解决的特殊情况。随着复杂性的增加,人们不再热衷于这种根据被阻塞任务的锁而选择运行的想法。可以理解为什么之前的开发人员在实现这个想法时遇到了困难,人们开始犹豫是否值得。

然而,Android 团队继续推动这一工作,原因是初步的数据来看是很有好处的,因为它避免了由于优先级反转而导致的长尾(long-tail)异常延迟,让前台应用程序的行为更可预测。

为了促进讨论,我记录了一些风险和问题,其中一些最近已得到解决,另一些尚待解决,并提出了一些关于避免一些复杂的迁移过程的初步想法。

Peter Zijlstra 提到,在 SCHED_DEADLINE 中进行拆分预留(split reservation)的工作,以及 CFS deadline server 方面的工作,它们将内核的任务的数据拆分为代理执行的独立调度器和执行上下文来并行维护,因此有可能共享一些逻辑和清理工作。类似地,在 pick_next_task()存在副作用这个问题上,返回的任务是会要运行的任务,所以副作用并不重要。Zijlstra 指出,核心调度代码也需要类似的更改,从而把 pick_next_task()和 set_next_task() 分离开。

Joel Fernandes 和 Steven Rostedt 还为如何避免迁移(migration)以及如何分摊 task-tree 迁移的开销提供了一些思路,希望避免一次性的过高开销。

此外,对于禁用乐观自旋锁(optimistic spinning)并对性能产生影响的问题,Zijlstra 建议我们在锁的持有者已经在某个 CPU 上运行的情况下,可以避免去迁移被阻塞任务以及恢复 optimistic spinning,毕竟这太复杂了。Zijlstra 还推动获取实际测试数据,以了解额外的 migration 和重新 selection 的开销是如何影响性能,以便我们可以了解真实存在问题,而不仅仅是停留在理论上的问题。这似乎与 SCHED_DEADLINE 的带宽继承(bandwidth-inheritance)工作相吻合。Dario Faggioli 指出,spin 对于某些 EDF 研究算法来说实际上是必要的,因为它消耗了等待任务的 CPU 时间,从而确保后续 deadline 不受影响。这对我来说还不太理解,因此计划在以后再进行跟进讨论。

(另请参阅:有关代理执行的这篇文章 https://lwn.net/Articles/934114/ 。)

Sched_ext:Pluggable scheduling with BPF

作者:David Vernet(视频 https://youtu.be/w5bLDpVol_M )

Sched_ext 是一种新的可扩展调度类,允许在 BPF 中实现全系统调度策略。演讲从比较高层的角度介绍了 sched_ext,并列举了开发它的原因。这些原因包括快速且安全地进行实验、为个别应用程序定制调度策略、支持快速推出 Spectre 缓解措施(例如对于 L1TF,CPU 调度器可以发挥作用)以及将一些复杂性移至用户空间。对于 Meta 来说,sched_ext 使得它可以尝试一些新功能,其中一些功能很快将发送上游以包含在 CFS 中。此外,它还使得 Meta 能够构建定制的调度器,提高了主要的 Web 工作场景的吞吐量以及 p99 latency。

此时,Zijlstra 指出,大多数 Spectre 缓解措施都跟 CPU 调度器无关,并质疑这个“快速实验”机制的价值。他得到的解释很明确,如果将来发现可以通过调度来缓解的漏洞,那么这种机制可能是有益的。另一位与会者问到,如果 Meta 可以运行自己的调度器,为什么要将其推送到上游的 CFS。回答是 Meta 是一家以 upstream 为主的公司,在其部署的内核中几乎没有使用内部 patch。此外,Meta 的许多内核工程师(包括出席会议的 Chris Mason)是长期的核心子系统维护者或贡献者,他们坚信开源具有普遍好处。

演讲继续介绍了 sched_ext 的接口,描述了 struct sched_ext_ops 这个回调功能以及和调度队列(DSQ, dispatch queue)抽象,详细信息请参阅 LWN 文章 https://lwn.net/Articles/922405/。

Zijlstra 表示,sched_ext 只是 debugfs 调度器开关的一个类似的很糟糕的版本,Oracle 等供应商会执行非标准操作,例如使用自己的调度器而不是使用 CFS。Mason 回应道,如果某个调度器具有引人注目的性能优势,并且如果 CFS 中缺少该特性,那么我们只需找出如何在 CFS 中启用它,就可以在不牺牲性能的情况下用上了。Steven Rostedt 指出,sched_ext 与 debugfs 开关不同,因为 sched_ext 位于 CFS 之内,因此不会对 Zijlstra 产生任何维护负担。

随着演讲的继续,观众提出了几个其他关注点。Thomas Gleixner 声称使用 BPF 可能会使调度器受到用户空间 API 稳定性约束的影响,因为 BPF 调度程序将接口暴露给其用户空间对应的程序的。回应指出 sched_ext 使用 struct_ops 接口,该接口完全是内核内部使用的,不提供 ABI 的保证。这一点与 Linus Torvalds 在 2022 年内核维护者峰会上的观点相吻合。

另一个担忧是 sched_ext 将会阻碍对 CFS 的上游贡献。Sched_ext 打算通过鼓励用户将其调度器上游到内核,也就是采用类似于内核 module 的方式,来解决这种问题。如果调度器的 struct_ops 接口发生变化,处于树外的调度器可能随时无法继续使用,而代码树内的调度器将进行更新从而避免构建问题和性能回退。跟对 CFS 的更改相比,将 sched_ext 调度器推送到 upstream 的门槛也可以更低。推送到 CFS 需要仔细地将功能集成到复杂的代码库中,并确保不会影响现有功能。对于 sched_ext,开发人员可以将其 BPF 调度器推到 upstream,然后在后续有空时将其功能添加到 CFS 中,等到证明这个工作量和维护成本是值得的时候。最后指出所有的 sched_ext 程序必须使用 GPLv2 许可,否则将被 BPF verifier 拒绝。

演讲以所有人一起外出享受浓缩咖啡的方式结束。

A push/pull model for timers

作者:Anna-Maria Behnsen(视频 https://youtu.be/OqedTYvdwE4 )

当定时器(timer)到期时,最好在一个当前活着的 CPU 上运行其处理程序函数,而不是唤醒一个空闲(idle)状态的 CPU。目前防止在空闲 CPU 上处理定时器的方法是在 enqueue 时使用启发式方法。该启发式方法计算出在定时器到期时不会处于空闲状态的最佳 CPU。这就是所谓的“push 模型”——在 enqueue 时将定时器推送到另一个 CPU 上。这个模型存在两个问题:启发式方法不可靠,并且大多数定时器在到期之前会被取消或修改过。这意味着在 enqueue 操作期间浪费 CPU 时间来生成一个可能不正确的解决方案,甚至这个解决方案很有可能根本不会被使用。

未来状态将是一个 pull 模型。为了支持这个模型,会在系统启动时随着 CPU 逐个上线来创建一个层次结构。当 CPU 空闲时,所有未被固定到该 CPU(且不可延迟)的定时器将被 enqueue 到这个层次结构中。该层级结构用于创建一些 group,其中会有一个 CPU 作为迁移者,确保排队进来的定时器能够及时到期并被“pull”到一个当前繁忙的 CPU 上。

验证这种方式的重要步骤之一就是测试。有几个人自愿将第六版(现在是第七版)的代码实现集成到他们的测试环境中。

观众和演讲者都提出了关于调度器行为的讨论;当一个定时器在远程 CPU 上到期时,最初启动定时器的 CPU 会被唤醒。这是由于完全公平调度器(completely fair scheduler)的原因,因为它假设上下文仍然是 cache-hot 的,并且出于性能原因来直接唤醒 CPU 而不是在一个实际上当前在繁忙的 CPU 上重新加载这个上下文。在讨论期间的结果是,这种行为可以改变,欢迎提交 patch 提案。

新方法中仍存在一个未解决的问题,即如何处理可延迟定时器(deferrable timer),其中大部分可以映射到非固定(non-pinned)定时器,但同时包含 pinned”标志和“deferrable”标志的定时器不能做这个简单对应。现场的一些人提供了支持,希望能消除那最后五个使用了 deferrable work 的地方。

Dynamic Energy Model

作者:Lukasz Luba(视频 https://youtu.be/2C-5uikSbtM )
这个演讲是关于将成为功耗模型(EM, energy model)框架组成部分的四个新功能。这些功能组成了一个集合,被称为“动态能量模型了(dynamic energy model)”。第一个功能允许用户在运行时修改模型的值来更好地反映当前硬件的情况;例如,由于游戏工作负载中 SoC 的温度升高而导致的静态功耗(leakage)增加。这组 patch set 可以在邮件列表上找到。该功能在 2022 年 Linux Plumbers Conference 上进行了介绍,但这次添加了一些显示 CPU 功耗随时间增加的图表。

第二个功能旨在改进 energy-aware scheduler(EAS)在唤醒期间进行任务安放时的模拟计算。演讲中描述的硬件依赖问题会导致两个非常小的 task 执行计算所使用的 energy 远高于内核中的模拟计算结果。这是由于 big.LITTLE 系统中的小核心和 DSU(dynamic shared unit, 包含 L3 cache)之间共享电压和频率导致的,它们都可以执行 DVFS (动态电压频率调整)以节省功耗,但 L3 cache 对于计算能力分为三档的 SoC(会有一个更大的“big”CPU 存在的 big.LITTLE 系统)来说是一个重要影响因素。

对于 big CPU 来说,L3 缓存的性能(latency 和 throughput)至关重要。为了保持该性能,系统可能会在即使 little CPU 不需要的情况下也会提升包含 little CPU 和 DSU 在内的频率(和电压)。目前的能量模型中没有对这种硬件行为进行建模,但新 patch 将改变这一点。简单实验的结果显示,在特定情况下,两个非常小的 task 的节能达到了约 50%,总共约 35mW。根据能量模型,约 40mW 的平均功耗就意味着一个 CPU 核心以 1GHz 的频率全速运行,因此不应被忽视。

第三个功能涉及对自 deep idle 状态的 CPU 唤醒开销进行建模。目前,EAS 不考虑 CPU 是否处于较深的 idle 状态,也不考虑为了执行一个小任务而将其唤醒是否值得。对于 big CPU 来说,这种唤醒的功耗成本可能并不小,最好能找另一个能够处理小任务的 CPU。

最后一个功能是在功耗模型中引入一个新的字段,反映每个频率下 CPU 的性能。CPU 的性能可能不随频率线性变化。它还可能因不同的工作负载而变化(例如整数型和浮点型密集型)。这与当前的软件模型不太匹配。Luba 还展示了以固定频率运行的 CPU 核的功耗变化的幻灯片。功耗在不同的基准测试中都有差异。

这两个信息就需要针对 CPU 引入各种功耗与性能曲线。这被称为“功耗和性能配置文件,power and performance profile”,可以有许多这样的配置文件。还提到了 Morten Rasmussen 在 2022 年 Linux Plumbers Conference 上的演讲,他展示了具有不同特性的四个功耗模型。通过对功耗模型进行运行时的修改,就可以插入一个新的功耗和性能配置文件,在长时间运行的应用程序(例如视频会议)中使用,从而改善 EAS 的决策,更好地利用硬件并节省电池电量。

Eco-friendly Linux kernel development: minimizing energy consumption during CI/CD

作者:Andrea Righi(视频 https://youtu.be/7wMnJrZDxBg )

在这个演讲中,Righi 介绍了 KernelCraft(现已更名为 virtme-ng),这是一个允许用户快速高效地构建和运行自定义的内核测试的工具。

过去,Righi 在同一台 PC 上进行内核开发和测试,出现过多次文件系统损坏和工作丢失的情况。通过虚拟化,他就能够更有效地测试内核,但重新部署和重新配置损坏的虚拟机仍然不是一个很好的做法。于是,Righi 发现了 virtme(由 Andy Lutomirski 编写的工具),它允许在虚拟机中运行一个内核把 host 上整个文件系统都虚拟化(使用 9p 文件系统以只读方式 export)。采用这种方式的话,如果发生了问题,可以避免重新部署这个用来测试的虚拟机的工作了。不幸的是,virtme 目前没有维护,所以 Righi 决定 fork 该项目并创建 KernelCraft。

该工具生成一个包含运行内核所需的最基本支持项的最小内核配置。然后,该工具会编译内核并使用 virtme 创建 host 系统的实时更新的 copy-on-write 快照(使用 overlayfs 和 tmpfs 来处理虚拟机内部的写操作)。

Zijlstra 建议读一下内核中的 kvm_guest.config 这个编译目标,而 Steven Rostedt 则建议查看内核源代码树中的 ktest.pl 来生成一个最小的.config 文件。

根据测试结果,Righi 只需要 82 秒的时间就能完成包括从头开始生成内核、在内核中运行一个简单的 uname -r 命令、并在收集结果的流程。而使用通常的基于 Ubuntu kernel 的编译、部署、测试工作流程则需要一个多小时。在这个过程中节省的功耗约为 10 倍。

总之,这个工具在 CI/CD 场景或进行内核二分法测试时是证明非常有用的,因为它能够节省大量的时间和能耗。此外,通过这个演讲,Righi 旨在分享他在内核开发和调试活动中使用的工具和环境。分享大家各自的工作流程是非常有价值的,因为即使是看似微小的细节也可以帮助或激励其他人来更多地参与内核开发。

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

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

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

format,png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值