LWN:软中断处理的启发式规则!

文章探讨了Linux内核中软中断处理的机制,如何引发性能问题,以及针对这些问题的启发式解决策略。软中断用于处理硬件中断后的非紧急任务,但可能造成长时间的处理延迟。JakubKicinski提出的新启发式方法旨在减少软中断处理的延迟,以改善网络停顿和TCP重传等问题。然而,ThomasGleixner指出,更根本的解决方案可能是重新设计软中断系统,使其更可控和可调度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

Heuristics for software-interrupt processing

By Jonathan Corbet
March 13, 2023
DeepL assisted translation
https://lwn.net/Articles/925540/

内核的软中断机制("softirq", software-interrupt)机制是在 1.0 内核发布之前就加入了的,它其实实现了一个在 Linux 诞生时就已经出现很久的系统中的设计方案。在那段时间里,软中断机制一直是内核社区实现可扩展性和响应时间目标的一个障碍,但事实证明很难把这个障碍清除掉。最近提出的一个新的启发式方法(仅仅是调整它的操作参数)来减轻与软中断有关的性能问题的讨论,可能重新激发了对这个子系统整体的兴趣。

当系统中的某些组件需要 CPU 关注时就会产生硬件中断,例如,完成了一个 I/O 操作的时候。处理硬件中断是内核中优先级最高的任务之一。中断处理几乎会抢占其他所有正在运行的工作,所以中断处理程序的工作量尽量少,以避免对系统的其他部分产生不利影响。softirq 机制,就是设计出来把硬件中断处理程序的一部分不那么紧急的工作搁置起来,从而尽快完成当前硬件处理。

使用软中断的子系统包括了网络、定时器、块设备子系统、读-复制-更新(RCU)和 tasklet 任务等。当这些子系统中的有某个需要把工作委托给软中断处理程序时,它会设置一个特别的 bitmask 来 "发起(raise)"一个软中断。当内核运行到打算处理软中断的位置时(通常是在硬件中断处理结束时或从系统调用返回时),就会对发起的软中断进行处理,并为每个软中断来调用合适的处理程序。

在实践中,从硬件中断处理程序中引发的 softirq 通常会在该硬件处理程序结束后立即运行,但情况并不总是如此。Softirqs 也可以从任何一个内核上下文中发起,而不仅仅是在响应硬件中断的时候;比如,RCU softirq 就跟任何硬件中断都没有关系。

这里的问题是,软中断处理程序可能有很多工作要做。它们被调用的原因包括:从网络上收到的数据包和 RCU 的回调处理,在这个处理程序运行时,可能有成千上万的数据包在等待处理。因此,softirq 处理可能会持续很长时间,从而影响到系统要做的其他工作。如果在 Softirq 处理过程中出现了太多的工作,这个问题就会变得很严重,这种情况很容易发生。

Managing softirq handling

为了避免 softirq 处理让系统不堪重负的这个问题,随着时间的推移,已经在内核中添加了一些启发式机制,包括:

  • 通常处理软件中断的函数(__do_softirq())将传递所有提出的 softirqs 并处理它们。在完成之后,它将检查是否有更多的软中断在等待处理;如果是这样的话就回到起点,但最多也只能处理 10 次。如果超过了这个数字,内核就会停止处理 softirq,而唤醒每个 CPU 的内核线程 softirqd 来继续工作。

  • 同样地,如果 softirq 的处理持续超过(大约)2ms,那么剩余的工作也将被推给 softirqd 去做。

  • 当 ksoftirqd 线程在一个给定的 CPU 上运行时,内核甚至不会尝试处理那里的软中断;而是直接把它们留给线程处理。

  • 当内核处理软中断时,时不时地会检查当前进程(被抢占来处理 softirqs 的进程)的 TIF_NEED_RESCHED 标志,如果有置位的话,表明有一个更高优先级的进程已经准备运行。在这种情况下就会停止处理 softirqs,来尽快回到该进程执行。

一些使用软中断的子系统也在它们自己的处理程序中实现了一些限制,跟 softirq 代码集中处理的地方的逻辑没有关联(甚至都不一定知道这件事)。

在 12 月底,Jakub Kicinski 发布了一组 patch set(标题为 "毫无争议的修改"),解决了上面列出的最后一个启发式方法中遇到的问题。我们之所以希望让内核在重新进行调度决策时来推迟 softirq 的处理,主要是为了让 event 处理能尽量低延迟。例如,如果有一些音频数据进来,那么需要能启动录音机程序并尽快记录数据。但是,如果在 reschedule 后运行的进程不是一个非常快捷的动作(也就是它持续占用 CPU 很长时间),那么它就会在这很长时间内一直阻止所有 softirq 的处理。这可能会导致一些问题,如网络会卡顿、TCP 重传等。

为了解决这个问题,Kicinski 提议增加另一种启发式方法。一旦 reschedule 导致的延迟发生,那么内核将只等待 2ms,然后会再开始处理 softirqs,而不管 softirqd 是否在运行;这就可以避免一个长期运行的进程阻塞了 softirq 的处理太久。类似的 timeout 也适用于由 softirq 的过度工作而引起的延迟,也就是上面列表中的前两项。在这种情况下,内核将在 100ms 后重新开始处理 softirq。他说,这些改动会导致网络停顿的次数减少到 1/10,TCP 重传减少 50%。

Addressing the real problem

Thomas Gleixner 似乎愿意接受这个新的 timeout 方案,尽管他补充说他 "不是非常喜欢这种搅在一起的很多启发式规则"。他指出了 timekeeping 的一些问题;它使用的是 jiffies 时间变量,分辨率为 1-10ms,用于很小的毫秒数上的。这可能会导致很大的结果差异。他后来意识到,这个问题在目前的内核中也存在。但没过多久,他就对整个方案提出了反对,他说,这只会让整个 softirq 问题变得更糟。

他说,Softirqs "只是一个至少有 50 年历史的操作系统设计方式的扩充"。它们的存在,是为了允许某些代码能规避资源管理(例如 CPU 调度),因此,使人们无法完全控制系统的运行。他抱怨说,当问题出现时(不可避免会有问题),通常的做法都是增加更多的启发式规则和开关。"他问道:"我们能不能不要到处调整参数,而是正确解决这全部问题?他还承认,他心中并没有一个完整的解决方案,但承诺在不久的将来会认真考虑这个问题。

Kicinski 说,网络开发人员正在努力将处理工作从软中断中移出来,但这是一个漫长而缓慢的过程。Frederic Weisbecker 则指出了软中断的真正问题:一次只能运行一个,而有一些内核代码依赖于这个特点所提供的独占能力。这么多年过去了,没有人真正知道哪些软中断处理代码可以安全地跟其他处理程序同时运行,哪些不能。因此,禁用软中断处理的作用就类似于之前那个名声很不好的大内核锁,而且,跟它一样很难被安全地移除。

他建议的解决办法是进行类似于为大内核锁所做的推倒重建工作。所有的软中断处理都可以被放到内核线程中去以正常的方式进行调度,但它们在运行时都会持有一个类似于 softirq-disable big lock 的锁。随着特定子系统的处理程序被证明是安全的,那么就可以不再使用这个锁,直到有一天,全部都移除。他说,这项任务不适合胆小的人:

当然,这个工作量相当巨大,但它的优点是可以迭代开发,从长远来看会有回报的。此外,我相信最常使用的地方会被很快处理掉。而其中大部分可能都是在网络代码的核心部分。

所需要的是有人来真正承担这些工作。

Matthew Garrett 曾经说过,"'heuristic, 启发式'是一个古老的非洲词,意思是'也许 bonghits 会让这个问题更难解决'"。当然,软中断一直是那种难以解决的问题,可以促使开发人员采取这种补救措施。也许,有一天,这个古老的子系统也会被清理掉,那些急切需要进行的处理将以一种可控的方式来完成,而启发式方法将不再被需要了。但现在它们仍然是必要的,而 Kicinski 的 patch 可能是一个创可贴,使的人们在解决真正的问题的时候能先让它正常工作起来。毕竟,即使开发社区这次真的决定会处理 softirqs 问题,那么这项工作也可能需要一段时间才能有结果。

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

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

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

format,png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值