update_sd_lb_stats
update_sd_lb_stats是 Linux CFS 调度器中负责负载统计与决策的核心底层函数。它并不直接移动任务而是像“侦察兵”一样遍历调度域sched_domain内的所有调度组sched_group收集负载数据并筛选出最繁忙的组busiest为后续的负载迁移提供数据依据。一、函数定位与作用该函数位于kernel/sched/fair.c是load_balance()流程的关键一环。它的主要使命是回答两个问题当前域的总负载情况如何计算total_load哪个组是最需要被分担负载的选出busiest_group调用链关系load_balance()→update_sd_lb_stats()→update_sg_lb_stats()二、关键参数解析理解该函数需要先明确其操作对象参数类型说明sdstruct sched_domain*目标调度域。例如一个 NUMA 节点或一个 CPU 簇。this_cpuint发起平衡的 CPU即当前正在执行平衡逻辑的 CPU。sdsstruct sd_lb_stats*输出结构。用于存放统计结果如 busiest、this_load。idleenum cpu_idle_typeCPU 空闲状态影响负载索引计算。关键数据结构sd_lb_stats域级统计包含this本地组和busiest最忙组指针。sg_lb_stats组级统计包含avg_load、sum_nr_running等实时指标 。三、执行流程拆解函数的执行逻辑是一个典型的遍历-统计-筛选过程其核心流程如下图所示flowchart TD A[开始遍历 sd-groups] -- B{当前组是 Local Group?}; B -- 是 -- C[调用 update_sg_lb_stats 更新组统计]; B -- 否 -- C; C -- D{是 Local Group 且br无需平衡 balance0?}; D -- 是 -- E[提前返回]; D -- 否 -- F; subgraph F [核心统计逻辑] direction LR F1[累加 total_load] -- F2{判断组类型}; end F2 -- Local Group -- G[记录到 sds-this]; F2 -- 远程组 -- H[调用 update_sd_pick_busiest]; H -- I{是否比当前br候选更忙?}; I -- 是 -- J[更新 sds-busiest]; I -- 否 -- K[跳过]; G -- L[移动到下一个组]; J -- L; K -- L; L -- M{是否遍历完br所有组?}; M -- 否 -- B; M -- 是 -- N[结束];1. 初始化与遍历准备检查子域偏好如果子调度域设置了SD_PREFER_SIBLING标志偏好兄弟 CPU则设置prefer_sibling这会影响后续的容量计算策略 。获取负载索引根据 CPU 的idle状态获取正确的负载指标索引load_idx确保在 CPU 空闲和繁忙时使用不同的负载计算权重。2. 遍历所有调度组Group函数通过do-while循环遍历域内的所有组环形链表识别本地组通过cpumask_test_cpu(this_cpu, group_cpus)判断当前组是否包含this_cpu。更新组统计调用update_sg_lb_stats()填充临时变量sgssg_lb_stats计算该组的平均负载、运行任务数、剩余容量等 。3. 关键决策点提前返回如果当前组是本地组local_group且外部传入的*balance标志为 0表示无需平衡则函数直接返回。这是一个重要的优化避免在明确无需平衡时继续遍历剩余组 。4. 统计与筛选累加全局数据将每个组的负载和算力累加到sds-total_load和sds-total_pwr。处理本地组将sgs数据复制到sds-this_*系列字段。竞选最忙组对于远程组调用update_sd_pick_busiest()进行多维度比较负载、任务数、容量。如果该组比当前记录的候选组更忙则更新sds-busiest和sds-max_load。5. 特殊策略prefer_sibling如果启用了prefer_sibling并且本地组有空闲容量函数会人为限制远程组的容量sgs.group_capacity min(sgs.group_capacity, 1UL)。这旨在鼓励将任务优先迁移到本地组的兄弟 CPU而不是跨组迁移有利于提升缓存亲和性 。四、输出结果与应用函数执行完毕后sds结构体将包含完整的决策信息sds-busiest指向负载最重的调度组。如果为NULL通常意味着整个域处于平衡状态后续流程会直接跳转至out_balanced。sds-this_*与sds-busiest_*提供了本地组与最忙组的详细对比数据负载、任务数、容量。后续流程load_balance()会接着调用calculate_imbalance()利用update_sd_lb_stats()产出的数据精确计算出需要迁移多少负载env-imbalance以及迁移的类型任务数或负载量。五、总结update_sd_lb_stats是 CFS 负载均衡的数据聚合引擎。它通过遍历组、计算负载、应用拓扑策略如prefer_sibling最终输出一个清晰的决策建议“本地组”和“最忙组”是谁它们的状态如何。理解它的逻辑是理解 Linux 调度器如何实现“负载均衡”的关键一步。