Linux 多核下绑定硬件中断到不同 CPU(IRQ Affinity)
中断定义
中断是一种比较好的CPU 和硬件沟通
的方式,还有一种方式叫做轮询
(polling),就是让 CPU 定时对硬件状态进行查询然后做相应处理,这种方式非常浪费(CPU)的时间,所以中断是硬件主动
的方式,比轮询(CPU 主动)更有效一些。
每个硬件设备都中断,那么如何区分不同硬件呢?不同设备同时中断如何知道哪个中断是来自硬盘、哪个来自网卡呢?系统上的每个硬件设备都会被分配一个IRQ
号,通过这个唯一的 IRQ 号就能区别是来自谁了。
在计算机里,中断是一种电信号
,由硬件产生,并直接送到中断控制器(如 8259A)上,然后再由中断控制器向 CPU 发送信号,CPU 检测到该信号后,就中断当前的工作转而去处理中断。然后,处理器会通知操作系统已经产生中断,这样操作系统就会对这个中断进行适当的处理。现在来看一下中断控制器,常见的中断控制器有两种:可编程中断控制器 8259A 和高级可编程中断控制器(APIC),中断控制器应该在大学的硬件接口和计算机体系结构的相关课程中都学过。传统的 8259A 只适合单 CPU 的情况,现在都是多 CPU 多核的 SMP 体系,所以为了充分利用 SMP 体系结构、把中断传递给系统上的每个 CPU 以便更好实现并行和提高性能,Intel 引入了高级可编程中断控制器(APIC)。
光有高级可编程中断控制器的硬件支持还不够,Linux 内核还必须能利用到这些硬件特质,所以只有 kernel 2.4 以后的版本才支持把不同的硬件中断请求(IRQs)分配到特定的 CPU 上,这个绑定技术被称为SMP IRQ Affinity
.
如何使用
系统上的中断是怎么分配在 CPU 上的,很显然 CPU0 上处理的中断多一些
cat /proc/interrupts
CPU0 CPU1
0: 61 0 IO-APIC-edge timer
1: 15 18 IO-APIC-edge i8042
4: 4650 0 IO-APIC-edge
6: 2 0 IO-APIC-edge floppy
8: 1 0 IO-APIC-edge rtc0
9: 0 0 IO-APIC-fasteoi acpi
12: 57 6 IO-APIC-edge i8042
14: 0 0 IO-APIC-edge ata_piix
15: 133 6919 IO-APIC-edge ata_piix
16: 1700 1900 IO-APIC-fasteoi vmwgfx, snd_ens1371
17: 36636 0 IO-APIC-fasteoi ehci_hcd:usb1, ioc0
18: 75 0 IO-APIC-fasteoi uhci_hcd:usb2
19: 67 18689 IO-APIC-fasteoi ens33
24: 0 0 PCI-MSI-edge PCIe PME, pciehp
25: 0 0 PCI-MSI-edge PCIe PME, pciehp
26: 0 0 PCI-MSI-edge PCIe PME, pciehp
27: 0 0 PCI-MSI-edge PCIe PME, pciehp
28: 0 0 PCI-MSI-edge PCIe PME, pciehp
29: 0 0 PCI-MSI-edge PCIe PME, pciehp
30: 0 0 PCI-MSI-edge PCIe PME, pciehp
31: 0 0 PCI-MSI-edge PCIe PME, pciehp
32: 0 0 PCI-MSI-edge PCIe PME, pciehp
33: 0 0 PCI-MSI-edge PCIe PME, pciehp
34: 0 0 PCI-MSI-edge PCIe PME, pciehp
35: 0 0 PCI-MSI-edge PCIe PME, pciehp
36: 0 0 PCI-MSI-edge PCIe PME, pciehp
37: 0 0 PCI-MSI-edge PCIe PME, pciehp
38: 0 0 PCI-MSI-edge PCIe PME, pciehp
39: 0 0 PCI-MSI-edge PCIe PME, pciehp
40: 0 0 PCI-MSI-edge PCIe PME, pciehp
为了把部分中断转移到 CPU1 上,ehci_hcd:usb1, ioc0
的中断转到 CPU1 上呢?先查看一下 IRQ 17 中断的 smp affinity,看看当前中断是怎么分配在不同 CPU 上的(ffffffff 意味着分配在所有可用 CPU 上)
[root@kolla ~]# cat /proc/irq/17/smp_affinity
00000000,00000000,00000000,00000001
[root@kolla ~]# cat /proc/irq/17/smp_affinity_list
0
以上可知中断使用的是cpu0.
在进一步动手之前我们需要先停掉 IRQ 自动调节的服务进程,这样才能手动绑定 IRQ 到不同 CPU,否则手动绑定做的更改将会被自动调节进程给覆盖掉。如果想修改 IRQ 17 的中断处理,绑定到第2个 CPU(CPU1):
systemctl stop irqbalance
systemctl disable irqbalance
echo 1 > /proc/irq/17/smp_affinity_list ##就是指cpu1
或者
echo "2" > /proc/irq/17/smp_affinity ###2也是代指cpu1,不过需要进行二进制到16转换
###之后会讲如何计算 SMP IRQ Affinity
查看结果
[root@kolla ~]# cat /proc/irq/17/smp_affinity
00000000,00000000,00000000,00000002
过段时间在看 /proc/interrupts,是不是 17 在 CPU1 上的中断增加了、在 CPU0 上的中断没变?不断打印 /proc/interrupts 就会发现 ehci_hcd:usb1, ioc0
在 CPU0 上的中断数始终保持不变,而在 CPU1 上的中断数是持续增加
watch -d cat /proc/interrupts
Every 2.0s: cat /proc/interrupts Tue Nov 16 22:20:06 2021
CPU0 CPU1
0: 61 0 IO-APIC-edge timer
1: 15 18 IO-APIC-edge i8042
4: 10665 0 IO-APIC-edge
6: 2 0 IO-APIC-edge floppy
8: 1 0 IO-APIC-edge rtc0
9: 0 0 IO-APIC-fasteoi acpi
12: 57 6 IO-APIC-edge i8042
14: 0 0 IO-APIC-edge ata_piix
15: 133 15721 IO-APIC-edge ata_piix
16: 1700 1900 IO-APIC-fasteoi vmwgfx, snd_ens1371
17: 37417 42 IO-APIC-fasteoi ehci_hcd:usb1, ioc0
18: 75 0 IO-APIC-fasteoi uhci_hcd:usb2
19: 67 28594 IO-APIC-fasteoi ens33
24: 0 0 PCI-MSI-edge PCIe PME, pciehp
作用
在网络非常 heavy 的情况下,对于文件服务器、高流量 Web 服务器这样的应用来说,把不同的网卡 IRQ 均衡绑定到不同的 CPU 上将会减轻某个 CPU 的负担,提高多个 CPU 整体处理中断的能力;对于数据库服务器这样的应用来说,把磁盘控制器绑到一个 CPU、把网卡绑定到另一个 CPU 将会提高数据库的响应时间、优化性能。合理的根据自己的生产环境和应用的特点来平衡 IRQ 中断有助于提高系统的整体吞吐能力和性能。
计算 SMP IRQ Affinity
“echo 2 > /proc/irq/17/smp_affinity”
中的 ”2“
是怎么来的,这其实是个二进制数字,代表 00000010,00000001 代表 CPU0 的话,00000010 就代表 CPU1, “echo 2 > /proc/irq/90/smp_affinity” 的意思就是说把17 中断绑定到 00000010(CPU1)上。所以各个 CPU 用二进制和十六进制表示就是:
Binary Hex
CPU 0 00000001 1
CPU 1 00000010 2
CPU 2 00000100 4
CPU 3 00001000 8
###cpu0比较特殊,并不是用全0表示,而是00000001,其余cpu则按照正常10进制转2进制进行转换
如果把 IRQ 绑定到 CPU2 上就是 00000100=4:
echo "4" > /proc/irq/17/smp_affinity
如果想把 IRQ 同时平衡到 CPU0 和 CPU2 上就是 00000001+00000100=00000101=5
echo "5" > /proc/irq/17/smp_affinity
需要注意的是,在手动绑定 IRQ 到 CPU 之前需要先停掉irqbalance
这个服务,irqbalance 是个服务进程、是用来自动绑定和平衡 IRQ 的:
还有一个限制就是,IO-APIC 有两种工作模式:logic
和physical
,在 logic 模式下 IO-APIC 可以同时分布同一种 IO 中断到8颗 CPU (core) 上(受到 bitmask 寄存器的限制,因为 bitmask 只有8位长。);在 physical 模式下不能同时分布同一中断到不同 CPU 上,比如,不能让 eth0 中断同时由 CPU0 和 CPU1 处理,这个时候只能定位 eth0 到 CPU0、eth1 到 CPU1,也就是说 eth0 中断不能像 logic 模式那样可以同时由多个 CPU 处理