perf top中[ksoftirqd]占比高通常源于网络软中断处理瓶颈,需通过/proc/net/softnet_stat分析dropped和time_squeeze字段判断是否因netdev_budget过小、RSS不均或NAPI未启用导致。
![perf top 显示 [ksoftirqd] 高占比时的 softnet_stat / netdev_budget 调优](https://img.php.cn/upload/article/001/242/473/177027942269642.jpeg)
perf top 看到 [ksoftirqd] 占比高,先确认是不是软中断瓶颈
这通常不是 CPU 被“占满”了,而是网络软中断(NET_RX)在 ksoftirqd 线程里持续被唤醒、处理不过来。关键要区分:是收包太快(网卡 flood),还是单核处理能力不足(如 RSS 未开启或不均),或是 net.core.netdev_budget 设置过小导致每次只处理少量包就让出 CPU,引发高频调度开销。
检查 softnet_stat 判断是否丢包和 backlog 积压
/proc/net/softnet_stat 每行对应一个 CPU 的软中断统计,用十六进制解析前两个字段:
- 第 1 字段(
processed):该 CPU 上成功入队并处理的包数 - 第 2 字段(
dropped):因input_pkt_queue满或内存不足被丢弃的包数 —— 若持续增长,说明软中断处理速度跟不上入队速度 - 第 3 字段(
time_squeeze):表示一次软中断上下文中,因超时(默认 2 jiffies)提前退出,被迫下次再处理 —— 高值直接指向netdev_budget过小或单次处理耗时过高
例如:echo "0x$(awk 'NR==1 {print $1}' /proc/net/softnet_stat | cut -d' ' -f1)" | bc 查当前 CPU 的 processed;重复执行对比增速,若 time_squeeze 增速 > processed,基本可断定预算不足。
netdev_budget 不是越大越好,需结合 NAPI 和中断合并调
net.core.netdev_budget 控制每次软中断上下文最多处理多少个包。默认 300,太小 → 频繁重调度 ksoftirqd;太大 → 单次处理太久,影响实时任务响应,还可能加剧 cache miss。
- 建议从 600 开始试,逐步加到 1200,观察
time_squeeze是否归零、perf top中[ksoftirqd]占比是否下降 - 必须同步打开网卡的 NAPI 和中断合并(如
ethtool -C eth0 rx on tx on),否则增大 budget 只会让单核更忙,不解决根本问题 - 多队列网卡务必确认 RSS 已启用且 flow hash 均匀(
ethtool -x eth0),否则所有包都砸向 CPU 0,调 budget 没用
真正卡住时,别只盯 budget,先看网卡侧配置和流量特征
很多 case 最终发现是硬件或驱动层限制:比如某 Mellanox CX4 卡在 LRO 启用时,软中断处理路径变长,即使 budget=1200 仍大量 time_squeeze;又或者 UDP 小包 flood 下,skb 分配开销远超处理逻辑本身。
- 用
cat /sys/class/net/eth0/device/msi_irqs/*确认每个 RX 队列绑定了哪个 CPU,再用perf record -e irq:softirq_entry --filter "vec==3" -C 0(vec=3 是 NET_RX)抓 CPU 0 的软中断触发频次 - 对比
/proc/interrupts中各 RX 队列中断分布,若严重不均,优先调sudo ethtool -X eth0 equal 8或手动设置 flow indirection table -
net.core.netdev_max_backlog要 ≥netdev_budget,否则新包直接进 drop 路径
budget 调优只是软中断流水线中的一环,容易忽略的是:网卡 ring buffer 深度、driver 的 poll 效率、甚至 CPU frequency scaling 导致的单周期吞吐波动 —— 这些都会让同样的 budget 值在不同机器上表现迥异。










