想准确查看每个 IRQ 编号的触发次数与变化频率,/proc/interrupts 是最直接、最常用的入口,但前提是你得真正看懂它:第一列是 IRQ 编号,中间各列表示不同 CPU 上的中断计数,最后一列则是设备或控制器标识(例如 eth0、PCI-MSI)。这里有一个很常见的误解:计数为 0 并不代表设备没有工作,很多时候只是因为系统启用了 NAPI 或轮询模式。仅凭总次数无法判断系统中断是否异常,通常需要配合多种方法一起分析——用 watch 观察计数增量,通过 smp_affinity_list 检查中断绑定关系,再结合 trace-cmd 抓取 handler 执行耗时。一旦单次 delta 超过 100μs,就需要重点排查。

直接查看 /proc/interrupts,确实可以知道每个 IRQ 编号累计被触发了多少次,但如果你想搞清楚“具体的系统中断请求”到底是什么情况,就不能只看一个总数——还要进一步拆分分析:到底是哪个设备在触发、落在哪个 CPU 上、触发频率有多高、单次处理耗时多久。
怎么看 /proc/interrupts 里每一行的真实含义
执行 cat /proc/interrupts 之后,每一行的基本结构通常是:IRQ编号 + 各个 CPU 的计数列 + 设备或控制器标识。例如:
42: 12456789023 0 11234PCI-MSI 0000:03:00.0
这表示 IRQ 42 在 CPU0 上触发了 124 万次,CPU1 是 9 千次,CPU2 是 0 次,设备对应的 PCIe 地址为 0000:03:00.0(一般可能是网卡、NVMe 固态盘等设备)。最后一列不是随意显示的名字,而是内核在注册中断时写入的标签,像 eth0、nvme0n1、i915 这类名称通常最有参考价值;如果看到 IO-APIC 或 IR-PCI-MSI,说明系统启用了中断重映射,此时 IRQ 编号和物理引脚已经没有直接对应关系,不能再按传统经验去推断硬件来源。
- 数值显示为 0,并不意味着设备空闲——启用 NAPI 或轮询模式后(如
ethtool -C eth0 rx off),硬中断计数可能几乎不变,但业务流量依然通过软中断正常处理 - 如果某一整行全是 0,先确认究竟是真的没有触发,还是该中断被屏蔽、未启用,或者 BIOS 中关闭了对应 PCIe 设备的 MSI 功能
- 如果看到
cascade、rescheduling之类的名称,通常属于内核内部中断,绝大多数场景下不需要重点关注;而timer和irqbalance相关项则要留意,它们本身未必是问题根源,却可能掩盖真实瓶颈
怎么快速定位“谁在猛打中断”
只看静态累计值,往往很容易误判。真正需要关注的不是“总量大不大”,而是“增长是否过快、分布是否失衡、是否缺乏对应业务负载”。
- 可以使用
watch -n 1 'cat /proc/interrupts | grep -E "(eth|nvme|usb)"'实时观察关键设备,重点看某一列是否每秒持续跳增几百次甚至更多 - 也可以按设备名做聚合统计:
awk '{print $(NF)}' /proc/interrupts | sort | uniq -c | sort -nr | head -10,但排在最前面的不一定就是异常源,很多时候只是正常高吞吐设备(例如 10G 网卡),因此仍然要结合增量分析 - 查看某个设备绑定了哪些 IRQ:
grep eth0 /proc/interrupts | awk '{print $1}',得到 IRQ 编号后再继续检查对应亲和性,避免漏看多队列网卡对应的多组中断 - 如果在虚拟机环境中看到大量
IR-IO-APIC,通常意味着 KVM 正在进行中断注入,这时/proc/interrupts里的 IRQ 编号对宿主机不具备直接物理意义,应转到 guest 系统内部继续排查
为什么不能只信 /proc/interrupts 的数字
/proc/interrupts 只记录“中断触发了多少次”,并不会告诉你“每次处理耗时多久”“是否有排队积压”“有没有延迟执行”。如果系统已经明显卡顿,但这里的计数看起来很平稳,那么问题大概率不在次数,而在 handler 的执行时间。
- 建议使用
trace-cmd record -e irq:irq_handler_entry -e irq:irq_handler_exit -T 5抓取单次中断处理的完整生命周期,分析时重点关注delta字段(单位为纳秒),如果持续超过 100μs,就要怀疑驱动是否在中断上下文里做了 memcpy、长时间持有 spin_lock,或者调用了慢速 I/O perf record -e irq:*通常不推荐用于这个场景——因为它并不能保证入口和出口事件一一配对,采样精度也不足,难以准确计算真实的 handler 耗时- 排查前还要先确认当前内核是否支持:
grep CONFIG_IRQSOFF_TRACER /boot/config-$(uname -r),必须返回y或m,否则trace-cmd很可能无法正常工作 - 如果中断计数突然暴涨,但系统里并没有对应的活跃进程,十有八九是硬件异常(例如网卡丢包重试、PCIe 设备误报)或者驱动缺陷,而不是正常业务负载升高
怎么查中断绑在哪个 CPU 上
不要直接操作 smp_affinity(十六进制掩码),因为 x86 和 ARM 在位宽上并不完全一致,写错后可能直接导致中断无法正常触发。更稳妥的方式是统一查看和使用 smp_affinity_list——它输出的是十进制 CPU 编号,可读性更高,也更适合跨架构使用。
- 查看网卡中断绑定关系:
grep eth0 /proc/interrupts | awk '{print $1}' | xargs -I{} sh -c 'echo {}:/proc/irq/{}/smp_affinity_list' | while read l; do echo "$l: $(cat ${l##*:} 2>/dev/null)"; done - 如果发现
/proc/irq/*/effective_affinity与smp_affinity_list的结果不一致,说明当前存在irqbalance或内核自动调度机制在介入,此时手动修改smp_affinity_list很可能会被重新覆盖 - 如果某个 IRQ 在
/proc/interrupts中主要集中在 CPU0,但smp_affinity_list明明显示允许 CPU0-CPU3 共同处理,那么问题往往不在中断绑定,而在设备自身能力上,例如网卡没有开启 RSS,或者驱动本身没有实现多队列支持
真正难处理的情况,往往不是“不会查”,而是查完之后发现所有指标看起来都正常——中断次数合理、CPU 分布均衡、handler 耗时也没有明显异常,但系统抖动依旧存在。到了这一步,就需要换一个排查方向:比如软中断(/proc/softirqs)或 RCU callback 是否正在悄悄堆积;又或者,中断本身只是表象,真正的问题其实藏在内存带宽瓶颈、PCIe 降速,甚至 BIOS 中某个被误关闭的节能选项里。
