SMP affinity and interrupt handling in Linux

2023-12-29 11:40

本文主要是介绍SMP affinity and interrupt handling in Linux,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

本文是一篇译文,原文的地址为:http://www.alexonlinux.com/smp-affinity-and-proper-interrupt-handling-in-linux


Introduction

硬件中断是非常昂贵的,因为它会消耗大量的CPU处理能力。硬件和软件工程师已经做了很多工作试图改变这种状况,但硬件中断仍然会消耗大量CPU。

硬件中断对桌面系统的影响并不明显,具体信息可以通过/proc/interrupts文件来查看。这个文件中记录了所有的硬件设备以及它们在每个CPU上收到的中断数目。如果是在一个常规的桌面系统上,将会看到系统中处理的中断数目是相对较小的。即使是每秒处理百万数据包的超强服务器,一秒内也只需处理数万个中断。即便如此,通过恰当的方式降低中断所带来的CPU开销仍将毫无疑问的帮助提升系统性能。


But really, what can we do about interrupts?

事实上,还有很多事情可以做。许多Linux的发行版中都包含了能够明显改善这种情况的修改。一种有效的技术就是NAPI,它显著的降低了中断的数目和开销,因此现代服务器无需再忍受1Gbps的以太网链路。NAPI现在已经成为了内核的一部分。其他的技术还有像中断合并等。

在本文中,我将把注意力放在一个最有力的中断处理优化技术上。


SMP affinity

术语“SMP亲和性” 或 “处理器亲和性”有着广泛的含义,需要首先来解释一下。“亲和性”是指在多处理器系统中,将特定的任务放到特定的处理器上执行。例如,当进程Y运行在处理器X上时,它们之间就具有了亲缘关系,处理器会将进程的部分内存内容缓存在cache中,因此频繁的将进程调度到不同的处理器上是一种低效的方法。

考虑到中断的情况,“SMP 亲和性”是指特定的中断由哪个处理器来处理。与进程的情况不同,将中断绑定到特定的CPU上将会引起性能下降。下面就来说说为什么会这样。中断处理程序通常都非常小,因此它所占用的内存也很小,也就是说将中断保持在同一个CPU上不会改善缓存命中的情况。相反,过多的中断会使一个核心过载,而其他的核心却处在相对空闲的状态。调度程序却对此一无所知,它会假设我们的中断处理核心与其他核心一样繁忙,由此带来的结果就是你可能会面临一个瓶颈,这是由于某些进程或线程运行在了只有90%可用处理能力的核心上所造成的。

事情还可能会变得更加糟糕,因为在默认情况下core0会被用来处理所有中断。在一个繁忙的系统上,所有的中断加起来可能会消耗掉core0 30%的处理能力。假设所有核心都具有相同的处理能力,我们会发现我们的软件系统只能有效地利用CPU全部处理能力的70%。


Who's responsible

APIC or Advanced Programmable Interrupt Controller 已经集成到所有现代x86体系架构的系统中 --- 包括 SP(single-processor)和MP。APIC负责递交中断,并决定中断的去向(到哪个核心)。

默认情况下,APIC将所有中断递交到core0,这就是为什么在主流现代Linux操作系统上/proc/interrupts文件的输出内容看起来如下的原因:

         CPU0     CPU1     CPU2     CPU30:   123357        0        0        0   IO-APIC-edge  timer8:        0        0        0        0   IO-APIC-edge  rtc11:        0        0        0        0  IO-APIC-level  acpi
169:        0        0        0        0  IO-APIC-level  uhci_hcd:usb1
177:        0        0        0        0  IO-APIC-level  qla2xxx
185:        0        0        0        0  IO-APIC-level  qla2xxx
193:    12252        0        0        0  IO-APIC-level  ioc0
209:        0        0        0        0  IO-APIC-level  uhci_hcd:usb2
217:      468        0        0        0  IO-APIC-level  eth0
225:      285        0        0        0  IO-APIC-level  eth1
NMI:      120       66       76       45
LOC:   123239   123220   123187   123065
ERR:        0
MIS:        0

看到了吗,CPU0处理了所有的硬件中断,这就是你将在一个错误配置了中断SMP亲和性的系统上看到的情形。


Simple solution for the problem

随着APIC的引入,这个问题已经有了多种解决方案。APIC包含了若干中断传递和指定模式,包括物理模式和逻辑模式,固定模式和低优先级模式,等等。一个重要的事实是它有能力将中断递送到任何一个核上,甚至在它们之间进行负载均衡。

APIC也有配置限制,它只能配置在前8个核心上。如果你有多于8个的核心,不要指望序号大于7的核心能够收到中断。

默认情况下,它的操作是physical/fixed的。也就是说,它会将特定的中断传递到特定的核心上(默认是core0),但你也可以方便的更改接收指定中断的核心号。

对于/proc/interrupts文件第一列中的每个IRQ号,在/proc/irq/目录下都有一个对应的子目录,其中包含了一个名为smp_affinity的文件,它可以用来修改处理这个中断的核心号。读这个文件可以获得一个由十六进制表示的掩码,其中的每一位代表一个核心。当特定位置位时,APIC会将这个中断传递到对应的核心。

让我们来看一个例子:

#
# cat /proc/interruptsCPU0     CPU1     CPU2     CPU30: 19599546        0        0        0   IO-APIC-edge  timer8:        0        0        0        0   IO-APIC-edge  rtc11:        0        0        0        0  IO-APIC-level  acpi
169:        0        0        0        0  IO-APIC-level  uhci_hcd:usb1
177:        0        0        0        0  IO-APIC-level  qla2xxx
185:        0        0        0        0  IO-APIC-level  qla2xxx
193:    95337        0        0        0  IO-APIC-level  ioc0
209:        0        0        0        0  IO-APIC-level  uhci_hcd:usb2
217:   100778        0        0        0  IO-APIC-level  eth0
225:    56651        0        0        0  IO-APIC-level  eth1
NMI:      466      393      422      372
LOC: 19600453 19600434 19600401 19600279
ERR:        0
MIS:        0
#
#
# echo "2" > /proc/irq/217/smp_affinity
# cat /proc/interruptsCPU0     CPU1     CPU2     CPU30: 19606722        0        0        0   IO-APIC-edge  timer8:        0        0        0        0   IO-APIC-edge  rtc11:        0        0        0        0  IO-APIC-level  acpi
169:        0        0        0        0  IO-APIC-level  uhci_hcd:usb1
177:        0        0        0        0  IO-APIC-level  qla2xxx
185:        0        0        0        0  IO-APIC-level  qla2xxx
193:    95349        0        0        0  IO-APIC-level  ioc0
209:        0        0        0        0  IO-APIC-level  uhci_hcd:usb2
217:   101027       49        0        0  IO-APIC-level  eth0
225:    56655        0        0        0  IO-APIC-level  eth1
NMI:      466      393      422      372
LOC: 19607629 19607610 19607577 19607455
ERR:        0
MIS:        0
#

可以看到,当我们输入了这个神奇的命令后,CPU1将代替CPU0,开始从eth0接收中断。用于完成这件事情的echo命令非常有趣,如果我们将“4”写入这个文件中,那么CPU2将代替CPU1来处理eth0的中断,就像之前已经提到的,它采用了位掩码的方式,每一位与一个单独的CPU关联。

那么写入“3”又会怎么样呢?理论上,这时APIC应该将中断传递到CPU0和CPU1上,不幸的是,这里的情况会更复杂一些。具体的行为依赖于APIC是否工作在 physical "destination mode" 以及 low priority "delivery mode"模式下。如果是的话,那么你不太可能看到CPU0处理所有中断,这是因为当APIC工作在 physical / low priority模式下的时候,会自动在前8个核心之间进行负载均衡。

因此,如果在你的系统上CPU0默认处理了全部的中断,这可能暗示了APIC的配置问题。


Ultimate solution

首先,不幸的是,别无选择,除非替换内核。配置APIC是内核的工作,如果我们想改变现状就只能在内核里修改它,那么唯一的问题就是,用什么来替换内核?

我在OpenSuSE 10.2(内核版本2.6.18)上进行了测试,使用OpenSuSE的默认内核配置(/proc/config.gz)安装2.6.24.3版本的内核(当时最新的版本)来修正这个问题。在这个内核上,事情看起来正确了:

# cat /proc/interruptsCPU0     CPU1     CPU2     CPU30:   728895   728796   728624   728895  IO-APIC-edge     timer8:        0        0        0        0  IO-APIC-edge     rtc11:        0        0        0        0  IO-APIC-fasteoi  acpi16:        0        0        0        0  IO-APIC-fasteoi  uhci_hcd:usb119:        0        0        0        0  IO-APIC-fasteoi  uhci_hcd:usb224:    14090    14090    14327    14056  IO-APIC-fasteoi  ioc049:        7        9        7        8  IO-APIC-fasteoi  qla2xxx50:        8       12       11       10  IO-APIC-fasteoi  qla2xxx77:     2849     2759     2841     2827  IO-APIC-fasteoi  eth078:    25072    25138    24996    24980  IO-APIC-fasteoi  eth1
NMI:        0        0        0        0
LOC:  2915270  2915256  2915228  2915092
ERR:        0

看起来不错不是吗?所有的核心都在处理中断,工作效率也因此得到了最大化。

还有一个内核的配置选项横在我们的道路上,一旦移除掉它就能够在所有晚于2.6.10版本的内核上获得类似的效果。这个选项就是CONFIG_HOTPLUG_CPU,它增加了对CPU热插拔的支持。关掉这个选项,并正确的配置APIC。

实际上这很好理解,APIC被告知使用哪个CPU来接收中断,你需要增加一段代码来告知APIC如何处理CPU的移除事件 --- 而CPU的移除事件正是CONFIG_HOTPLUG_CPU允许你做的事,我假定这个功能在较早时被内核遗忘了,并在2.6.24.3版本之后被添加了进来。


Conclusion

我们已经看到,通过修改内核的配置可以获得实实在在的改进。在一个繁忙的系统中,通过一个小小的改动就可以成倍的提升服务器的生产力。

希望你能够认同这篇文章的内容,并将这些技术用到实际中去。


转载于:https://my.oschina.net/u/2310891/blog/379247

这篇关于SMP affinity and interrupt handling in Linux的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/549330

相关文章

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

linux系统上安装JDK8全过程

《linux系统上安装JDK8全过程》文章介绍安装JDK的必要性及Linux下JDK8的安装步骤,包括卸载旧版本、下载解压、配置环境变量等,强调开发需JDK,运行可选JRE,现JDK已集成JRE... 目录为什么要安装jdk?1.查看linux系统是否有自带的jdk:2.下载jdk压缩包2.解压3.配置环境

Linux搭建ftp服务器的步骤

《Linux搭建ftp服务器的步骤》本文给大家分享Linux搭建ftp服务器的步骤,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录ftp搭建1:下载vsftpd工具2:下载客户端工具3:进入配置文件目录vsftpd.conf配置文件4:

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

Linux系统管理与进程任务管理方式

《Linux系统管理与进程任务管理方式》本文系统讲解Linux管理核心技能,涵盖引导流程、服务控制(Systemd与GRUB2)、进程管理(前台/后台运行、工具使用)、计划任务(at/cron)及常用... 目录引言一、linux系统引导过程与服务控制1.1 系统引导的五个关键阶段1.2 GRUB2的进化优

Linux查询服务器 IP 地址的命令详解

《Linux查询服务器IP地址的命令详解》在服务器管理和网络运维中,快速准确地获取服务器的IP地址是一项基本但至关重要的技能,下面我们来看看Linux中查询服务器IP的相关命令使用吧... 目录一、hostname 命令:简单高效的 IP 查询工具命令详解实际应用技巧注意事项二、ip 命令:新一代网络配置全

linux安装、更新、卸载anaconda实践

《linux安装、更新、卸载anaconda实践》Anaconda是基于conda的科学计算环境,集成1400+包及依赖,安装需下载脚本、接受协议、设置路径、配置环境变量,更新与卸载通过conda命令... 目录随意找一个目录下载安装脚本检查许可证协议,ENTER就可以安装完毕之后激活anaconda安装更

Linux查询服务器系统版本号的多种方法

《Linux查询服务器系统版本号的多种方法》在Linux系统管理和维护工作中,了解当前操作系统的版本信息是最基础也是最重要的操作之一,系统版本不仅关系到软件兼容性、安全更新策略,还直接影响到故障排查和... 目录一、引言:系统版本查询的重要性二、基础命令解析:cat /etc/Centos-release详