3. 调度域与调度组:数据结构详解
在组调度场景下,CPU 域迁移的决策依赖于两个核心数据结构:调度域(sched_domain)和调度组(sched_group)。调度域定义了 CPU 之间的拓扑层次和负载均衡范围,而调度组则代表了该域内可进行任务迁移的实体单元。理解这两个结构体的字段含义和相互关系,是进行域迁移参数调优的基础。
3.1 调度域(sched_domain)
调度域是一个树形层次结构,每个层级对应不同的 CPU 拓扑(如 SMT、MC、NUMA)。内核通过 sched_domain 结构体描述每个 CPU 所属的域层级。其核心字段如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
span |
cpumask_var_t | 该域覆盖的 CPU 位图,用于判断 CPU 是否属于本域。 |
level |
int | 域层级编号,数值越小越接近物理 CPU(如 SMT 层为 0)。 |
flags |
int | 控制域行为的标志位,如 SD_BALANCE_NEWIDLE、SD_BALANCE_EXEC、SD_BALANCE_FORK、SD_BALANCE_WAKE、SD_LOAD_BALANCE 等。 |
min_interval |
unsigned int | 负载均衡的最小触发间隔(单位:ms)。 |
max_interval |
unsigned int | 负载均衡的最大触发间隔(单位:ms)。 |
busy_factor |
unsigned int | 繁忙状态下间隔放大倍数。 |
imbalance_pct |
unsigned int | 触发迁移的不平衡百分比阈值(如 117 表示负载差超过 17% 时触发)。 |
cache_nice_tries |
unsigned int | 缓存亲和性尝试次数。 |
groups |
struct sched_group * | 指向本域内第一个调度组的指针,形成环形链表。 |
调优提示:
imbalance_pct 是组调度场景下最常调整的参数之一。在 NUMA 系统中,适当增大该值(如从 117 调整为 125)可以减少跨域迁移,降低内存访问延迟。
3.2 调度组(sched_group)
每个调度域由多个调度组组成,调度组是负载均衡的基本单元。组内可以包含一个或多个 CPU,组与组之间通过环形链表连接。其核心字段如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
cpumask |
cpumask_var_t | 该组包含的 CPU 位图。 |
group_weight |
unsigned int | 组内 CPU 数量,用于计算组容量。 |
sgc |
struct sched_group_capacity * | 指向组容量信息的指针,包含计算能力、负载等统计。 |
next |
struct sched_group * | 指向下一个调度组,形成环形链表。 |
asym_prefer_cpu |
int | 非对称拓扑中优先使用的 CPU 编号。 |
3.3 域与组的关系:层次与环形结构
调度域与调度组的关系可以用以下 SVG 图表示。图中展示了一个 4 核 2 线程的 NUMA 系统,包含 SMT、MC、NUMA 三个域层级,每个域内包含多个调度组。
3.4 数据结构在组调度中的协作流程
当内核触发负载均衡时,调度域与调度组按以下步骤协作:
- 选择域层级:从当前 CPU 所在的最低层域(如 SMT)开始,逐层向上检查是否需要均衡。
- 遍历调度组:在当前域内,通过
groups指针遍历环形链表中的每个调度组。 - 计算组负载:读取每个组的
sgc中的负载统计,计算组平均负载。 - 判断不平衡:比较最忙组与最闲组的负载差,若超过
imbalance_pct阈值,则触发迁移。 - 执行迁移:从最忙组中选择任务,迁移到最闲组中的目标 CPU。
性能优化要点:在组调度场景下,
sched_domain 的 flags 字段控制着哪些事件会触发均衡。例如,SD_BALANCE_WAKE 标志控制唤醒时是否进行负载均衡。对于延迟敏感型应用,建议关闭高层域的 SD_BALANCE_WAKE,避免频繁的跨 NUMA 迁移。
3.5 关键参数与数据结构字段映射
以下表格列出了常见的调度参数与其对应的数据结构字段,帮助你在调优时快速定位:
| 调度参数 | 对应数据结构字段 | 所属结构体 | 典型值 |
|---|---|---|---|
kernel.sched_domain.imbalance_pct |
imbalance_pct |
sched_domain | 117 (NUMA), 125 (MC) |
kernel.sched_domain.busy_factor |
busy_factor |
sched_domain | 32 (NUMA), 64 (MC) |
kernel.sched_domain.cache_nice_tries |
cache_nice_tries |
sched_domain | 2 (NUMA), 4 (MC) |
kernel.sched_group.group_weight |
group_weight |
sched_group | CPU 数量 (如 2, 4, 8) |
注意:直接修改
sched_domain 或 sched_group 的内核字段需要重新编译内核。在运行时,建议通过 /proc/sys/kernel/sched_domain/ 下的 sysctl 接口进行调整,这些接口会间接更新对应数据结构的字段值。