最准方法是直接查看 /proc/interrupts,用 grep -e "(eth|enp|ens|eno)" 定位网卡中断行,观察各 cpu 列计数是否不均;若仅一行匹配且 ethtool -l 显示 combined: 1,则需先启用多队列(如 sudo ethtool -l enp0s3 combined 4),再通过 smp_affinity_list 绑定不同中断号到不同 cpu。

怎么看网卡中断在哪些CPU上“扎堆”
直接看 /proc/interrupts 是最准的入口,不需要装额外工具。重点不是找“有没有中断”,而是看“谁在替网卡干活、干了多少”。
执行:cat /proc/interrupts | grep -E "(eth|enp|ens|eno)"(把 eth 换成你实际网卡名,比如 ens33 或 enp0s3)
输出中每行开头是中断号(如 45),后面是各 CPU 列的计数(CPU0、CPU1…),末尾带 rx-0、tx-1 这类后缀的,基本就是网卡队列中断。
- 如果某一行里
CPU0的数字远大于其他列(比如 120 万 vs 其他都是几百),说明这个中断全压在 CPU0 上 - 如果只有一行匹配(比如只有
45: … eth0),大概率网卡没开多队列,所有包都走同一个中断号 - 用
watch -n1 'cat /proc/interrupts | grep enp0s3'动态观察,更能确认是不是“实时增长不均”
为什么 top 里 ksoftirqd/0 占满 CPU0 却看不到对应中断
因为 ksoftirqd/0 是软中断线程,它处理的是硬中断“交过来”的后续任务。硬中断本身可能已经绑死在 CPU0,但软中断不会自动跨核迁移——它默认跟着硬中断跑。
所以你看到 ksoftirqd/0 高,90% 是因为网卡硬中断全打在 CPU0,导致软中断也全挤在这儿排队。
- 查证:运行
top -H,按Shift+P排序,找ksoftirqd/X线程的 CPU 使用率 - 注意:不要只看
%si(软中断占比),它反映的是全局比例,掩盖了单核过载的真实压力 - 如果
ksoftirqd/0和ksoftirqd/1都高,但其他核为 0,说明中断亲和还没调,或者只调了一半
ethtool 显示 combined 队列数为 1 就别急着设 smp_affinity
中断亲和再怎么设,也只能把一个中断号绑到多个核——但效果极差。真正要的是“多个中断号 + 各自绑定不同核”,前提是网卡得先开出多个接收队列。
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
检查命令:ethtool -l enp0s3(替换为你自己的网卡名)
关键看输出里的 Current hardware settings 行:
- 如果显示
Combined: 1,说明当前只开了 1 个队列,/proc/interrupts里最多就一个eth0-rx-0中断行 - 想开多队列,得先运行:
sudo ethtool -L enp0s3 combined 4(数字建议设为物理 CPU 核心数,避开超线程逻辑核) - 部分虚拟网卡(如
virtio_net)需加内核参数virtio_net.force_multi_queue=1才能生效 - 执行后必须重新插拔网卡或重启网络服务,否则
/proc/interrupts不会出现新中断号
echo 写 smp_affinity_list 时 CPU 编号容易搞反
别信网上抄来的“echo 1 > /proc/irq/45/smp_affinity 就是绑 CPU0”——那是老内核的十六进制掩码写法,现在主流发行版(RHEL 8+/Ubuntu 20.04+)默认用 smp_affinity_list,它要的是 CPU 序号列表,不是位掩码。
验证方式:cat /proc/irq/45/smp_affinity_list,输出是类似 0-3 或 0,2,3 这种格式。
- 正确写法:
echo "1,2,3" | sudo tee /proc/irq/45/smp_affinity_list→ 绑定到 CPU1、CPU2、CPU3 - 错误写法:
echo 2 | sudo tee /proc/irq/45/smp_affinity→ 这是旧式十六进制掩码(2=CPU1),但写错文件路径或格式会静默失败 - 批量操作前,先用
for i in $(cat /proc/interrupts | grep enp0s3 | awk '{print $1}' | sed 's/://'); do echo $i; done提取真实中断号,避免手动数错
最易被忽略的一点:网卡驱动加载顺序早于用户脚本,/etc/rc.local 里直接 echo 很可能因网卡未就绪而失败;真要持久化,得用 systemd service 加 After=network.target 和 Type=oneshot。










