4. 中断亲和性(IRQ Affinity):SMP IRQ Affinity 原理与配置
在多核(SMP)系统中,中断处理器的选择直接影响系统的实时性与吞吐量。中断亲和性(IRQ Affinity)允许将特定的硬件中断绑定到指定的 CPU 核心上,从而避免中断在不同核心间迁移带来的缓存污染和调度延迟。本章节深入剖析 SMP IRQ Affinity 的内核实现原理,并详细讲解通过 /proc/irq/ 接口进行配置的具体方法。
4.1 SMP IRQ Affinity 原理
在对称多处理(SMP)架构下,每个 CPU 核心都拥有独立的中断控制器接口(如 APIC)。内核通过中断分发机制决定将某个 IRQ 送达哪个核心。IRQ Affinity 的核心思想是:通过设置 CPU 位掩码(cpumask),限制特定中断只能由掩码中指定的核心处理。
- 减少缓存抖动:中断处理程序及其访问的数据结构始终在同一核心上运行,L1/L2 缓存命中率显著提升。
- 降低调度延迟:避免中断在多个核心间“乒乓”迁移,减少上下文切换和 TLB 刷新开销。
- 隔离关键负载:将高频率中断(如网卡 RX/TX)绑定到专用核心,保障业务线程在其余核心上的稳定运行。
内核中,每个 IRQ 描述符(struct irq_desc)都包含一个 irq_affinity 字段,类型为 struct cpumask。当硬件中断触发时,中断控制器驱动(如 IO-APIC、MSI)会查询该掩码,并通过 IPI(核间中断)或直接路由将中断信号发送到掩码中优先级最高的在线核心。
4.2 /proc/irq/ 接口详解
Linux 内核通过 /proc/irq/ 虚拟文件系统暴露每个中断号的状态与配置接口。每个注册的 IRQ 在 /proc/irq/ 下都有一个以中断号命名的目录。
| 文件/目录 | 类型 | 说明 |
|---|---|---|
/proc/irq/{N}/smp_affinity |
可读写 | 存储 IRQ N 的 CPU 位掩码(十六进制),写入新掩码即动态调整亲和性 |
/proc/irq/{N}/smp_affinity_list |
只读 | 以 CPU 列表形式(如 0-3,5)显示当前亲和性,便于人类阅读 |
/proc/irq/{N}/node |
只读 | 显示该中断所属的 NUMA 节点编号,用于跨 NUMA 优化 |
/proc/irq/{N}/actions |
只读 | 列出注册到该 IRQ 的所有设备驱动名称 |
/proc/interrupts |
只读 | 全局中断统计表,显示每个 CPU 上每个 IRQ 的中断计数 |
cat /proc/interrupts | grep {irq_number} 观察当前中断在各核心上的分布情况,确认是否存在不均衡。
4.3 设置中断亲和性的方法(echo mask)
设置 IRQ Affinity 的核心操作是向 /proc/irq/{N}/smp_affinity 写入十六进制 CPU 位掩码。位掩码的每一位对应一个 CPU 核心:最低位(bit 0)代表 CPU0,bit 1 代表 CPU1,以此类推。
4.3.1 位掩码计算规则
| 目标 CPU | 二进制掩码 | 十六进制掩码 | 说明 |
|---|---|---|---|
| 仅 CPU0 | 0000 0001 | 1 |
最低位置 1 |
| 仅 CPU1 | 0000 0010 | 2 |
bit 1 置 1 |
| CPU0 + CPU1 | 0000 0011 | 3 |
bit 0 和 bit 1 置 1 |
| CPU0 + CPU2 | 0000 0101 | 5 |
bit 0 和 bit 2 置 1 |
| 所有 CPU(4核) | 0000 1111 | f |
低 4 位全 1 |
| CPU2 + CPU3(4核) | 0000 1100 | c |
bit 2 和 bit 3 置 1 |
4.3.2 标准配置步骤
- 确认中断号:通过
cat /proc/interrupts找到目标设备对应的 IRQ 号(第一列)。 - 查看当前亲和性:
cat /proc/irq/{N}/smp_affinity cat /proc/irq/{N}/smp_affinity_list - 写入新掩码:
echo {hex_mask} > /proc/irq/{N}/smp_affinity例如,将 IRQ 130 绑定到 CPU0 和 CPU3:
echo 9 > /proc/irq/130/smp_affinity(二进制 1001 → CPU0 和 CPU3)
- 验证生效:
cat /proc/irq/{N}/smp_affinity # 观察 /proc/interrupts 中该 IRQ 的中断计数是否只在目标 CPU 上增长
- 写入
smp_affinity需要 root 权限。 - 对于 MSI-X 中断,每个队列可能有独立的亲和性设置,需通过
/proc/irq/{N}/smp_affinity分别配置。 - 部分老旧驱动或中断控制器可能不支持运行时动态修改,修改后需检查是否生效。
- 在 NUMA 系统中,建议将中断绑定到与设备所在 PCIe slot 同节点的 CPU 上,以降低跨 NUMA 访问延迟。
4.3.3 持久化配置
通过 echo 写入的方式在系统重启后会丢失。如需持久化,可使用以下方法之一:
- irqbalance 服务:配置
/etc/sysconfig/irqbalance或/etc/irqbalance.conf,通过--banirq或--hintpolicy策略实现。 - udev 规则:在
/etc/udev/rules.d/中创建规则,匹配设备后执行echo mask > /proc/irq/{N}/smp_affinity。 - 系统服务脚本:在
/etc/rc.local或 systemd 服务中写入配置命令。
4.4 实战案例:绑定网卡中断到指定核心
假设系统有 4 个 CPU 核心,网卡(eth0)使用 MSI-X 中断,IRQ 号为 130-133。目标是将所有网卡中断绑定到 CPU2 和 CPU3(掩码 0b1100 = 0xc)。
# 1. 查看当前中断分布
cat /proc/interrupts | grep eth0
# 2. 逐个绑定 IRQ 130-133
echo c > /proc/irq/130/smp_affinity
echo c > /proc/irq/131/smp_affinity
echo c > /proc/irq/132/smp_affinity
echo c > /proc/irq/133/smp_affinity
# 3. 验证绑定结果
cat /proc/irq/130/smp_affinity
# 输出应为: c
# 4. 观察中断计数变化(在高流量下测试)
watch -n 1 'cat /proc/interrupts | grep eth0'