直接看 /proc/interrupts 是唯一轻量、可信起点,但需结合列(irq号、各cpu计数、设备名)、动态监控(如 watch -n 1 'grep eth0 /proc/interrupts')及 trace-cmd 耗时分析才能准确定位中断异常源。

直接看 /proc/interrupts 就是唯一轻量、可信的起点,但光 cat 一下容易误判——它只记次数,不告诉你谁在打、打得多快、每次花了多久。
怎么看懂 /proc/interrupts 的行和列
执行 cat /proc/interrupts 后,第一列是 IRQ 编号(比如 42、25),后续每列对应一个 CPU(CPU0、CPU1…),最后一列是中断源描述。常见形式有:
-
IO-APIC 16:传统中断控制器,编号基本绑定物理引脚 -
PCI-MSI 0000:01:00.0:PCIe 设备用 MSI 方式申请的中断,编号与设备地址强关联 -
IR-PCI-MSI 32768:虚拟化环境启用中断重映射后,IRQ 编号已和物理引脚解耦,不能按编号猜硬件 -
eth0、nvme0n1、i915:内核驱动注册时填的设备名,最直观的归属线索
注意:0 不等于“没工作”——网卡启用 NAPI 或轮询模式(如 ethtool -C eth0 rx off)后,中断计数归零,但流量照常。
怎么快速定位正在猛打 CPU 的中断源
别扫全屏,用过滤+动态观察盯跳变速度:
- 按设备名实时监控:运行
watch -n 1 'grep -E "(eth|enp|ens|eno|nvme)" /proc/interrupts',把eth换成你实际的网卡名(如ens33)或 NVMe 名(如nvme0n1) - 重点看某一行中某一列(如
CPU0)是否每秒涨几百甚至上千;其他列几乎不动,就是它在单核上“堵车” - 看到末尾带
rx-0、tx-1这种后缀,说明是网卡多队列中断,有多个 IRQ 可调;如果只有一行且没后缀,大概率网卡没开多队列 - 若
RES(重调度)、CAL(IPI)、TIMER持续飙升,不是硬件问题,而是内核调度或 busy-loop 引起的,别往驱动上扯
为什么改了 smp_affinity 却没生效
手动写入后几秒又变回去?基本是 irqbalance 在后台覆盖你:
- 先确认是否真被接管:查
/proc/irq/<irq_num>/effective_affinity</irq_num>,如果它和smp_affinity_list不一致,说明irqbalance或内核自动管理在干预 - 别直接写
smp_affinity(十六进制掩码)——x86 和 ARM 位宽不同,写错直接导致中断不触发;优先用smp_affinity_list(输出十进制 CPU 编号,人眼可读) - 某些中断(如 BMC、老 RAID 卡)固件锁定,写入会报
Operation not permitted;先ls -l /proc/irq/<irq_num>/</irq_num>看有没有smp_affinity*文件再动手 - NUMA 架构下,网卡 IRQ 应优先绑到直连该网卡的 CPU 节点,用
lscpu和lspci -vv -s $(ethtool -i eth0 | grep 'bus-info' | awk '{print $2}')交叉验证 NUMA node
中断耗时必须用 trace-cmd,不是 perf
/proc/interrupts 只给总量,卡顿或抖动必须看单次 handler 入口到出口的纳秒级耗时:
- 先确认内核支持 ftrace:
grep CONFIG_IRQSOFF_TRACER /boot/config-$(uname -r)返回y或m - 抓 5 秒:
trace-cmd record -e irq:irq_handler_entry -e irq:irq_handler_exit -T 5 - 分析时盯
delta字段(单位纳秒),超过100μs就值得怀疑驱动在中断上下文里干了不该干的事(比如memcpy大块数据) - 别用
perf record -e irq:*——它不保证入口/出口配对,采样精度也不够,没法算真实 handler 耗时
真正难的不是找到哪行数字涨得快,而是判断这个涨背后是硬件抖动、驱动 bug,还是配置失当——三者现象相似,但修复路径完全不同。比如 nvme0n1 中断暴涨,可能是 PCIe 链路误报,也可能是驱动未启用 polling mode,还可能是 SSD 固件异常。得靠 trace-cmd + /proc/softirqs + smartctl 交叉印证,缺一不可。











