
Linux SMP IRQ Affinity 实战指南用 /proc/irq 精确绑定中断到指定 CPU【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux导读本文基于 Linux 内核文档 Documentation/core-api/irq/irq-affinity.rst 展开系统讲解 SMP对称多处理系统中如何通过/proc/irq/接口将某个中断源IRQ绑定到指定的 CPU 集合从而优化网络、存储等设备的处理性能与缓存局部性。读完本文你将掌握smp_affinity、smp_affinity_list与default_smp_affinity三个核心文件的读写方法、位掩码与 CPU 列表两种格式的换算、如何用/proc/interrupts验证绑定效果以及哪些中断如 affinity-managed 中断不能通过用户空间修改。/proc/irq/ 下的亲和性接口格式与语义在 SMP 系统上内核为每个已注册的中断源在/proc/irq/IRQ#/目录下暴露了亲和性控制文件。核心文档指出/proc/irq/IRQ#/smp_affinity与/proc/irq/IRQ#/smp_affinity_list用于指定该 IRQ 允许投递到哪些目标 CPUsmp_affinity以位掩码形式表示允许的 CPU 集合每个 bit 对应一个 CPUsmp_affinity_list以CPU 列表形式如0-3,8表示同样的语义二者读写等价只是格式不同。从源码实现看这两个文件由 kernel/irq/proc.c 在register_irq_proc()中创建其权限位是动态决定的仅当irq_can_set_affinity_usr()返回真时才会加上写权限S_IWUSR否则该文件只读。而irq_can_set_affinity_usr()的定义在 kernel/irq/manage.c它在常规检查之外还要求该中断没有设置IRQD_AFFINITY_MANAGED标志——也就是说由内核管理的 affinity-managed 中断详见下文不允许用户空间改写。写入时内核分别调用cpumask_parselist_user()list 格式或cpumask_parse_user()位掩码格式解析输入见 kernel/irq/proc.c读取时通过cpumask_pr_args()打印其中位掩码以十六进制显示如0000000f。使用上有两条硬性约束文档明确给出不允许关闭所有 CPU即不能把亲和性掩码写为全 0如果中断控制器本身不支持 IRQ 亲和性那么写入不会生效文件内容始终停留在默认的“所有 CPU”值。default_smp_affinity新激活中断的默认掩码/proc/irq/default_smp_affinity指定应用于所有非活跃 IRQ的默认亲和性掩码。当某个 IRQ 被分配/激活后它的亲和性位掩码会被设置成该默认值之后才可以通过上述两个文件按需修改。内核默认值为0xffffffff即允许投递到所有 CPU。该文件由 kernel/irq/proc.c 中的register_default_affinity_proc()在CONFIG_SMP下创建读写分别对应default_affinity_show()打印全局变量irq_default_affinity见 kernel/irq/proc.c与default_affinity_write()同样经cpumask_parse_user()解析后更新全局默认掩码见 kernel/irq/proc.c。典型用法在系统启动早期、大量设备驱动尚未申请中断之前先设置一个合理的默认掩码让随后注册的中断自动落到期望的 CPU 集合上省去逐个调整的麻烦。实战示例一把 eth1 的 IRQ44 绑定到 CPU0-3核心文档给出的是一个 8-CPU SMP 主机上的完整演示。首先进入 IRQ44 的 proc 目录并查看当前亲和性[rootmoon 44]# cd /proc/irq/44 [rootmoon 44]# cat smp_affinity ffffffff初始值为ffffffff表示允许所有 8 个 CPUbit0–bit7 全为 1。接下来把掩码写成0f二进制00001111即 bit0–bit3 为 1把中断限制在前 4 个 CPU[rootmoon 44]# echo 0f smp_affinity [rootmoon 44]# cat smp_affinity 0000000f为了产生真实的中断负载示例使用ping -f hflood ping对目标主机h打流然后通过/proc/interrupts观察 IRQ44 在各 CPU 上的计数分布[rootmoon 44]# cat /proc/interrupts | grep CPU\|44: CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 44: 1068 1785 1785 1783 0 0 0 0 IO-APIC-level eth1可以看到 IRQ44 只投递到了 CPU0-3计数非零CPU4-7 的计数全为 0。这说明亲和性设置立即生效中断被严格限制在前 4 个处理器上。实战示例二切换到 CPU4-7 并验证接下来把同一 IRQ 改绑到后 4 个 CPU。位掩码f0二进制11110000对应 bit4–bit7[rootmoon 44]# echo f0 smp_affinity [rootmoon 44]# cat smp_affinity 000000f0 [rootmoon 44]# ping -f h ... [rootmoon 44]# cat /proc/interrupts | grep CPU\|44: CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 44: 1068 1785 1785 1783 1784 1069 1070 1069 IO-APIC-level eth1这一次CPU0-3 的计数与上一次完全相同1068/1785/1785/1783没有增长而 CPU4-7 出现了新的增量。这从计数器角度精确印证中断源在切换后只投递到新的 CPU 集合旧集合的计数器完全静止。实战示例三用 smp_affinity_list 绑定高位 CPU1024-1031当目标 CPU 编号很大时位掩码会变得冗长而难以阅读。例如要把 IRQ44 限制到 CPU1024-1031位掩码需要 32 个全 0 的十六进制位段之后才出现有效位极易出错此时应改用 CPU 列表格式[rootmoon 44]# echo 1024-1031 smp_affinity_list [rootmoon 44]# cat smp_affinity_list 1024-10311024-1031表示从 CPU1024 到 CPU1031 的连续区间。核心文档特别提示同样的目标如果用位掩码表达需要写出 32 个前置的零位段可读性与可维护性都很差——这正是smp_affinity_list存在的意义。在脚本或系统调优实践中涉及高位 CPU 时优先使用 list 格式。补充effective_affinity 与只读的 affinity_hint除了smp_affinity*两个可写文件/proc/irq/IRQ#/下还有两个关联文件在CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK与 SMP 配置下创建见 kernel/irq/proc.ceffective_affinity/effective_affinity_list显示中断当前实际生效的 CPU 掩码。由于硬件或中断控制器约束实际投递目标可能与smp_affinity中设置的允许集合不完全一致排查“设了却没生效”的问题时应同时对比这两个值affinity_hint只读0444由驱动提供的建议亲和性仅供查看参考不参与内核决策。在排障实践中一个常见误区是只cat smp_affinity就断言中断落在某 CPU 上正确做法是结合effective_affinity与/proc/interrupts的计数器共同确认。哪些中断改不了managed IRQ 与 isolcpus并非所有中断都允许用户空间调整亲和性。内核文档 Documentation/core-api/irq/managed_irq.rst 与 Documentation/core-api/irq/concepts.rst 对相关背景有更完整的阐述Affinity-managed 中断面向每队列一个中断向量的大型设备典型如 NVMe 的多 I/O 队列驱动通过pci_alloc_irq_vectors_affinity()配合PCI_IRQ_AFFINITY标志分配带亲和性约束的向量IRQ 核心据此将中断尽量均匀地散布到各 CPU。这类中断的亲和性完全由内核管理用户空间写smp_affinity会被拒绝源码层面的判定就是 kernel/irq/manage.c 中对IRQD_AFFINITY_MANAGED的检查对应irq_can_set_affinity_usr()返回 false、proc 文件只读。当亲和掩码内的 CPU 全部下线时中断会被关闭直到有 CPU 重新上线才恢复isolcpusmanaged_irq,引导参数让 managed 中断在分配时尽量避开指定 CPU 掩码。这是一种 best-effort 隔离如果所有非隔离 CPU 都离线中断仍会落到被隔离的 CPU 上。由于掩码内 CPU 实际仍属于中断的允许集合当非隔离 CPU 全部离线而隔离 CPU 在线时中断会被迁移到隔离 CPU另外irqaffinity引导参数可为非 managed 中断指定初始亲和集合。理解这些机制有助于判断为什么某些设备的中断在/proc/irq/下看起来“写不进去”——那不是权限问题而是内核主动管理的设计使然。验证与排障小结操作命令/文件说明查看允许集合位掩码cat /proc/irq/44/smp_affinity十六进制每 bit 对应一个 CPU设置允许集合位掩码echo 0f /proc/irq/44/smp_affinity禁止写全 0需中断控制器支持查看允许集合CPU 列表cat /proc/irq/44/smp_affinity_list格式如0-3,8设置允许集合CPU 列表echo 1024-1031 /proc/irq/44/smp_affinity_list高位 CPU 时更可读查看实际生效集合cat /proc/irq/44/effective_affinity_list实际投递目标可能不等于允许集合查看各 CPU 中断计数cat /proc/interrupts用计数器增量验证绑定效果设置新中断默认掩码echo ... /proc/irq/default_smp_affinity默认0xffffffff作用于未激活/新分配中断排障要点先确认中断控制器支持亲和性且该中断不是 managed 中断对应 proc 文件是否有写权限设置后用ping -f等流量手段制造中断再对比/proc/interrupts中目标 CPU 与非目标 CPU 的计数增量即可客观验证绑定是否生效。参考文档SMP IRQ affinity 原文档IRQ 基础概念什么是 IRQ 号Affinity managed interrupts 详解irq 文档索引相关实现源码kernel/irq/proc.c、kernel/irq/manage.c【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考