内核的deadline调度类提供了很多对实时任务(或者低延迟敏感)任务的解决方法。但他同时也无法解决优先级反转问题。 开发社区一直在寻求代理执行作为一些调度难题的解决方案,包括这个;这个问很困难,同时进度也很慢,LWN上一次关注代理执行是在6月份;在2023年Linux Plumbers Conference上,John Stultz概述了代理执行、工作的当前状态以及有待解决的问题。
目前的工作(至少部分)是由Android系统的需求驱动的,在Android系统中,运行一些具有实时优先级的任务是有用的。Android在尝试的过程中遇到了很多优先级反转的问题,然而,这些问题的经典解决方案(优先级继承)并不适用于Linux中的最后期限或非实时任务。因此,Android系统无法以任何有用的方式限制后台任务活动,而不会为用户当前实际关心的前台任务创建不一致的行为。
当一个低优先级的任务占用了一个高优先级任务所需的资源时,就会发生优先级反转;如果低优先级的任务无法获得CPU时间来运行,它可能会长时间占用该资源,从而阻止高优先级任务运行。解决方法通常包括让等待的任务把它的优先级借给拥有它所需要的资源的任务,这样拥有资源的任务就可以运行并释放资源。然而,Linux中的deadline任务没有优先级,因此需要一种不同的方法。
代理执行背后的核心思想是跟踪等待资源的任务和拥有该资源的任务之间的“阻塞”关系。在当前的内核中,等待资源的任务将从运行队列中删除;而在代理执行中,它将保留在队列中,就好像它仍然是可运行的一样。如果调度器实际上选择了阻塞的任务来运行,它将遵循阻塞的链接来运行资源的持有者。 实际上,等待任务贡献了一些运行时间,这些时间本来是要用于释放它所需要的资源的。
这个想法很简单,但实施起来却很复杂。持有一个资源的任务可能会被阻塞在第二个资源上,因此调度程序可能必须遵循任意长度的阻塞链,以获得一个可以实际运行的任务。被阻塞的链接可以跨CPU;在调度器可以运行由这样的链接指向的任务之前,它需要将被阻塞的任务迁移到持有者实际运行的CPU。可能是由于其他原因,位于阻塞链末端的资源持有者当前正在休眠(无法运行),这意味着在该任务再次运行之前无法取得任何进展。在这种情况下,原来阻塞的任务被加入到持有资源的睡眠任务中,这样它们就可以一起被唤醒。还有其他挑战。
即便如此,代理执行显示了一些真正的承诺。Stultz展示了来自工作负载的结果,这些工作负载在当前内核上由于优先级反转而偶尔经历较大的延迟。代理执行的加入使得这些延迟消失了。因此,stultz说代理执行对于Android用例“非常有吸引力”。
自从四月份在 OSPM 会议上提出以来,这项工作已经发布了三个版本。他一直在重新设计补丁系列,使其可以一分为二;补丁集的第 6 版于 11 月初发布。除此之外,该版本还部分修复了上一轮中引入的性能回归问题。
在他准备好的演讲接近尾声时,他说:“有几个突出的问题。”上面描述的休眠-拥有者问题的处理是很难正确处理的;其目的是将等待的(高优先级)任务加入到拥有任务的队列中,这样它们就可以一起唤醒,但这是很复杂的。Stultz担心实现这个解决方案可能会涉及到重新设计内核的运行队列。如果一个任务已经被迁移以将其执行时间借给资源持有者,那么一旦阻塞被解决,它就应该被迁移回来,但是这很慢并且涉及锁定挑战。版本5中引入的性能回归问题仍然没有完全解决。还有一个小问题,就是给调度程序增加了一些显著的复杂性,而调度程序已经是一个“非常微妙”和困难的内核子系统了。
Stultz最后说,他仍在努力寻找打破补丁系列的最佳方式。他想知道Android是否需要发布一个代理执行的内核,然后才会被认真考虑用于主线。这将显示工作的价值,但它也会增加Android和主线内核之间的分歧,这是Android项目希望避免的。他说,一旦一项功能被添加到Android中,它就很难被删除,因为厂商很快就会依赖它。他最后要求对代理执行补丁的设计和正确性进行更多的审查。
接下来的讨论主要集中在读写锁(rwlocks)上,代理执行补丁目前还没有处理这个问题。Thomas Gleixner说,优先级继承在过去已经被证明不是rwlocks的一个选项;它最终变得过于复杂。提升写锁的持有者(以响应更高优先级的需要该锁的读取者)是很容易的,因为只能有一个写者,但可以有多个读者,从而使情况复杂化。他说,让一个被锁住的写者试图提升整个读者群是无法扩展的,而且“会变得混乱”。
格莱克斯纳说,在实时树中,他们放弃了,只满足于提升作家;这改善了情况,但让读者得不到提升会导致作家挨饿。话虽如此,也许问题现在并不那么令人担忧。十五年前,内核中存在大量高度竞争的rwlock,但是许多rwlock的用户,特别是在网络子系统中,已经转而使用读取-复制-更新。最大的障碍是mmap_lock,但是需要该锁的代码已经在慢速路径中运行,可以等一会儿。他最近没有看到任何写者饥饿的问题。因此,他总结说,解决读写锁的真正办法就是简单地停止使用它们。