控制线程偶尔跑到另一颗 CPU 后,延迟突然多出一截。先别急着把 isolcpus 加进内核启动参数。Linux 里至少有三件事容易混在一起:进程的 CPU 亲和性、某个线程的亲和性,以及中断和内核后台工作的落点。只绑住其中一个,其他工作仍然可能在同一颗 CPU 上打断它。
这篇先把“用户线程绑核”讲完整,再说明怎样验证绑核真的生效。代码和命令都可以在普通 Linux 主机上练习,实时控制的结论仍需要目标内核和负载下的测量。
先分清 PID、TID 和当前 CPU
ps 显示一个进程时,默认只给出进程级信息。真正执行控制循环的是线程。可以先列出线程和它最近运行过的 CPU:
1 | ps -eLo pid,tid,psr,cls,rtprio,pri,comm --sort=tid |
psr 是最近一次运行的 CPU,不是允许集合。taskset -pc 读到的是进程的 affinity mask;如果进程已经创建了多个线程,后续仍应逐个检查 /proc/<PID>/task/<TID>/status。
用 taskset 做第一次实验
对一个已经运行的进程,可以先把它限制到 CPU 2 和 3:
1 | taskset -cp 2,3 <PID> |
这条命令修改的是进程里已有线程的允许集合。新线程是否继承该集合、程序是否随后自己修改,都要实际确认。权限不足时,普通用户只能调整自己拥有的任务;跨用户或实时优先级操作可能需要相应的权限和 cgroup 配置。
绑核不是把线程“钉死”在一颗 CPU 上。2,3 代表它仍可在两颗 CPU 之间迁移。若要减少迁移,可以指定单个 CPU,但这会把该 CPU 的算力和中断余量一起压缩,必须看负载而不是只看延迟最好的一次结果。
代码里设置单个线程
Linux 提供 pthread_setaffinity_np() 设置指定线程的 CPU 集合。下面的例子创建一个工作线程,把它限制在 CPU 2,然后打印线程看到的集合:
1 |
|
编译和运行:
1 | gcc -O2 -Wall -Wextra -pthread affinity_demo.c -o affinity_demo |
生产代码还要处理 CPU 编号不存在、容器 cpuset 不允许 CPU 2、线程创建失败和退出顺序。pthread_setaffinity_np 的 np 表示它不是 POSIX 可移植接口,跨平台程序应把这段能力包在平台适配层里。
为什么绑核后延迟仍然会抖
线程 affinity 只限制调度范围。网卡 IRQ、线程化中断、softirq、workqueue、日志线程和同一 cgroup 的其他任务仍可能使用这颗 CPU。可以对照查看:
1 | cat /proc/interrupts |
如果控制线程固定在 CPU 2,而网卡多队列也集中到 CPU 2,绑核只会让冲突更稳定。实时部署通常需要一起规划 housekeeping CPU、IRQ affinity、线程 affinity 和 cgroup,而不是单独执行一条 taskset。
NUMA 机器还要看内存在哪
双路或多 NUMA 节点机器上,线程跑在哪个 CPU 和数据页落在哪个节点是两回事。线程启动时在 CPU 0 上分配并触碰大缓冲区,后面迁到另一个节点后,访问可能变成跨节点。可以先查看 CPU 和内存节点:
1 | lscpu -e=CPU,NODE,ONLINE |
绑核、内存预触碰和 NUMA policy 应作为一个实验变量组处理。单独看到 cache miss 增加,不能马上断言是调度迁移造成的。
验证要看迁移和尾延迟
绑核前后使用同一负载、同一运行时长和同一测量工具。记录线程实际运行 CPU、迁移次数、IRQ 活跃度、P95/P99 延迟和 deadline miss。只看 top 里的平均 CPU 使用率,看不出一个 200 微秒的尾部尖峰。
一个合格的结论应写清楚:线程允许哪些 CPU、哪些 IRQ 在这些 CPU 上、内存策略是什么、测试负载是什么,以及测量没有覆盖哪些固件或硬件干扰。
需要把 PID、TID 和 /proc/<PID>/task 再拆开时,可以看Linux 进程、线程与 task;绑核前后的延迟比较则适合放进绝对唤醒周期循环里,避免用普通业务负载得到一组无法复现的数字。
参考资料
- sched_setaffinity(2)
- pthread_setaffinity_np(3)
- Linux CPU isolation
- Linux IRQ affinity
- Linux cpuset controller
证据边界:示例只证明如何设置和检查用户线程的 CPU 允许集合,不代表绑核后一定得到更低延迟。IRQ、cgroup、NUMA、固件和热管理都可能改变结果;发布前应在目标内核、设备和负载上复测。