Linux CPU 亲和性
🌟 概述
CPU 亲和性(CPU Affinity)是指将线程(或任务)绑定到特定 CPU 核心运行,以优化性能、减少缓存失效或确保实时任务的确定性。在 Linux 中,CPU 亲和性常与调度策略(如 SCHED_FIFO、SCHED_RR、SCHED_OTHER)结合使用。
🔍 核心概念
- 定义:通过设置线程的 CPU 亲和掩码(affinity mask),限制其运行的 CPU 核心。
- 目的:
- 提高缓存命中率,减少跨核心数据迁移。
- 降低上下文切换开销,提升实时任务确定性。
- 隔离任务,避免多核干扰。
- 调度单位:线程(Linux 内核的任务)。
- 与调度策略的关系:
- SCHED_FIFO/SCHED_RR:亲和性可确保实时线程固定在高性能核心,减少延迟。
- SCHED_OTHER (CFS):亲和性优化普通任务的缓存局部性。
🛠️ 主要 API
以下是 Linux 中管理 CPU 亲和性的核心 API(定义在 <sched.h>
):
1. sched_setaffinity
int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask);
- 功能:设置线程的 CPU 亲和掩码。
- 参数:
pid
:线程 ID(0 表示当前线程)。cpusetsize
:掩码大小(通常为sizeof(cpu_set_t)
)。mask
:cpu_set_t
类型,指定允许的 CPU 核心。
- 返回值:成功返回 0,失败返回 -1(检查
errno
)。
2. sched_getaffinity
int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
- 功能:获取线程的 CPU 亲和掩码。
- 返回值:成功返回 0,失败返回 -1。
3. cpu_set_t 操作宏
- 定义:
cpu_set_t
是一个位图,表示 CPU 核心。 - 常用宏:
CPU_ZERO(&set)
:清空掩码。CPU_SET(cpu, &set)
:添加 CPU 核心(cpu
从 0 开始)。CPU_CLR(cpu, &set)
:移除 CPU 核心。CPU_ISSET(cpu, &set)
:检查 CPU 是否在掩码中。
⚠️ 注意事项
- 权限:普通用户可设置亲和性,但受系统限制(如
cgroup
或numactl
配置)。 - 实时调度:SCHED_FIFO/SCHED_RR 结合亲和性可提高确定性,但高优先级线程可能导致低优先级线程饿死。
- 多核影响:绑定单一核心可能限制并行性,需权衡。
- 动态调整:亲和性可随时修改,但频繁更改可能增加开销。
- 工具:使用
taskset
命令查看/设置亲和性(如taskset -c 0,1 <pid>
绑定到 CPU 0 和 1)。
📊 CPU 亲和性与调度策略结合
调度策略 | 亲和性用途 | 注意点 |
---|---|---|
SCHED_FIFO | 绑定高性能核心,确保硬实时低延迟 | 避免低优先级线程饿死 |
SCHED_RR | 固定核心,减少软实时任务切换 | 时间片切换可能受核心负载影响 |
SCHED_OTHER | 优化缓存局部性,提升普通任务性能 | 动态调度可能削弱亲和性效果 |
✅ 优点
- 提高缓存效率,减少跨核心迁移。
- 增强实时任务确定性。
- 隔离任务,降低干扰。
🚫 局限性
- 绑定单一核心可能降低多核利用率。
- 配置不当可能导致负载不均。
- 不适合频繁迁移的动态任务。