CPU性能优化:CPU绑定与隔离、中断负载均衡、调度策略选择、降低上下文切换

各位好,我是老张。今天咱们聊聊CPU性能优化这块硬骨头。

说实话,我早年做驱动适配时,最头疼的就是CPU资源打架。你想想看,一个中断来了,把正在跑的关键任务给打断了,系统响应直接崩掉。后来我慢慢摸索出几招,今天全部分享给你们。

核心思路:CPU优化的本质,就是让每个CPU核心干它最擅长的事,别互相干扰。

一、CPU绑定与隔离

CPU绑定,说白了就是把某个进程或线程,死死摁在某个CPU核心上跑。为什么要这么做?

我遇到过这样一个案例:一个实时性要求很高的数据采集任务,默认情况下它在各个核心间跳来跳去。每次切换,缓存就失效了,性能直接打七折。绑核之后,缓存命中率上来了,延迟降了一半。

具体怎么做?Linux下用 taskset 命令:

# 把进程PID 1234绑定到CPU 0-3
taskset -cp 0-3 1234

# 启动时直接绑定
taskset -c 0 ./my_app

代码里也能做,用 sched_setaffinity 系统调用:

#include <sched.h>
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(0, &mask);  // 绑定到CPU 0
sched_setaffinity(0, sizeof(mask), &mask);

我的习惯:关键实时任务绑到独立核心,非关键任务丢到共享核心池。别把所有鸡蛋放一个篮子里。

CPU隔离就更狠了。把某些核心从内核调度器中摘出来,普通进程根本看不到它们。只有你指定的任务才能用。

内核启动参数里加 isolcpus=2,3,核心2和3就被隔离了。然后你用 taskset 把专属任务绑上去,完美。

我曾经踩过的坑:隔离了核心,但忘了把内核线程也迁走。结果内核线程还在隔离核心上跑,白忙活一场。记得用 cset shield 工具把内核线程也赶走。

二、中断负载均衡

中断这玩意儿,处理不好就是性能杀手。你想想,网卡每收一个包就触发一次中断,如果所有中断都挤在CPU 0上,它不得累死?

Linux内核有个 irqbalance 服务,默认会帮你把中断分散到各个核心。但说实话,自动的往往不是最优的。

我建议手动分配。先看看中断号:

cat /proc/interrupts

找到网卡的中断号,比如 eth0 对应中断号 48。然后写它的亲和性:

echo 2 > /proc/irq/48/smp_affinity

这里的 2 是二进制 0010,表示绑定到CPU 1。每个bit代表一个核心。

中断类型 推荐绑核策略
网卡RX/TX 分散到多个核心,避免单核瓶颈
存储设备 绑定到与驱动亲和的核心
定时器中断 留给CPU 0,别动它

我的经验:高吞吐网卡场景,用 RPS/RFS 配合中断绑核,效果拔群。RPS把软中断也分散了,RFS还能保证数据局部性。

三、调度策略选择

Linux调度策略有好几种,选错了就是灾难。

  • SCHED_OTHER (CFS): 默认策略,公平分享CPU。适合普通应用。
  • SCHED_FIFO: 实时策略,先到先服务。优先级高的任务不跑完,低优先级别想动。
  • SCHED_RR: 实时策略,时间片轮转。同优先级任务轮流跑。
  • SCHED_DEADLINE: 最新策略,指定截止时间。适合硬实时场景。

我一般这么选:

# 把音频播放进程设为SCHED_FIFO,优先级80
chrt -f -p 80 1234

# 代码里设置
struct sched_param param;
param.sched_priority = 80;
sched_setscheduler(0, SCHED_FIFO, &param);

注意:实时策略用不好会锁死系统。我曾经把某个死循环进程设成SCHED_FIFO最高优先级,结果系统直接卡死,只能硬重启。实时策略只给那些确定能快速完成的任务用。

四、降低上下文切换

上下文切换,说白了就是CPU从跑A任务切换到跑B任务。每次切换都要保存恢复寄存器、刷新TLB,开销不小。

怎么降?我总结了三条路:

  1. 减少线程数: 别动不动就开几十个线程。用线程池,控制并发数。
  2. 使用大页内存: TLB miss少了,切换代价也小了。
  3. 避免锁竞争: 锁争抢会导致大量上下文切换。用无锁数据结构或者RCU。

看看上下文切换频率:

vmstat 1 5
# 看 cs 列,就是每秒上下文切换次数

如果 cs 值超过几万,说明有问题了。我见过一个数据库服务,cs飙到20万,查了半天发现是日志打印太频繁,每次打印都触发系统调用。改成批量写入后,cs直接降到5000。

避坑指南:我曾经用 perf sched record 抓调度事件,发现某个锁导致大量切换。改用 futex 优化后,性能提升30%。工具用起来,别瞎猜。

知识体系总览

下面这张图,是我自己整理的CPU优化知识框架。你们可以照着这个思路去排查问题:

CPU性能优化知识体系 CPU绑定与隔离 • taskset绑核 • sched_setaffinity • isolcpus隔离 • cset shield 中断负载均衡 • irqbalance • smp_affinity • RPS/RFS • 手动分配策略 调度策略选择 • SCHED_OTHER • SCHED_FIFO/RR • SCHED_DEADLINE • chrt命令 降低上下文切换 • 减少线程数 • 大页内存 • 避免锁竞争 • vmstat监控 优化流程 1. 分析瓶颈:用perf/vmstat/top找出CPU热点 2. 制定策略:根据场景选择绑核/隔离/调度策略 3. 验证效果:对比优化前后的延迟和吞吐量

好了,CPU优化这块就聊到这儿。记住一个原则:让每个核心专注做自己的事,别瞎折腾。 你按照这个思路去调,性能至少能提20%。

想要更多资料,联系可可