当前位置: 首页 > news >正文

Linux最忙CPU组查找函数和最忙运行队列查找函数

一、最忙CPU组查找函数find_busiest_group

static struct sched_group *
find_busiest_group(struct sched_domain *sd, int this_cpu,unsigned long *imbalance, enum idle_type idle)
{struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups;unsigned long max_load, avg_load, total_load, this_load, total_pwr;max_load = this_load = total_load = total_pwr = 0;do {unsigned long load;int local_group;int i, nr_cpus = 0;local_group = cpu_isset(this_cpu, group->cpumask);avg_load = 0;for_each_cpu_mask(i, group->cpumask) {if (local_group)load = target_load(i);elseload = source_load(i);nr_cpus++;avg_load += load;}if (!nr_cpus)goto nextgroup;total_load += avg_load;total_pwr += group->cpu_power;avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;if (local_group) {this_load = avg_load;this = group;goto nextgroup;} else if (avg_load > max_load) {max_load = avg_load;busiest = group;}
nextgroup:group = group->next;} while (group != sd->groups);if (!busiest || this_load >= max_load)goto out_balanced;avg_load = (SCHED_LOAD_SCALE * total_load) / total_pwr;if (this_load >= avg_load ||100*max_load <= sd->imbalance_pct*this_load)goto out_balanced;*imbalance = min(max_load - avg_load, avg_load - this_load);*imbalance = (*imbalance * min(busiest->cpu_power, this->cpu_power))/ SCHED_LOAD_SCALE;if (*imbalance < SCHED_LOAD_SCALE - 1) {unsigned long pwr_now = 0, pwr_move = 0;unsigned long tmp;if (max_load - this_load >= SCHED_LOAD_SCALE*2) {*imbalance = 1;return busiest;}pwr_now += busiest->cpu_power*min(SCHED_LOAD_SCALE, max_load);pwr_now += this->cpu_power*min(SCHED_LOAD_SCALE, this_load);pwr_now /= SCHED_LOAD_SCALE;tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/busiest->cpu_power;if (max_load > tmp)pwr_move += busiest->cpu_power*min(SCHED_LOAD_SCALE,max_load - tmp);tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/this->cpu_power;if (max_load < tmp)tmp = max_load;pwr_move += this->cpu_power*min(SCHED_LOAD_SCALE, this_load + tmp);pwr_move /= SCHED_LOAD_SCALE;if (pwr_move < pwr_now + SCHED_LOAD_SCALE / 8)goto out_balanced;*imbalance = 1;return busiest;}*imbalance = (*imbalance + 1) / SCHED_LOAD_SCALE;return busiest;out_balanced:if (busiest && (idle == NEWLY_IDLE ||(idle == SCHED_IDLE && max_load > SCHED_LOAD_SCALE)) ) {*imbalance = 1;return busiest;}*imbalance = 0;return NULL;
}

这个函数是Linux内核负载均衡器的核心,负责在调度域中找到最繁忙的CPU组,并计算需要迁移的任务量

1. 函数原型和参数

static struct sched_group *
find_busiest_group(struct sched_domain *sd, int this_cpu,unsigned long *imbalance, enum idle_type idle)

参数

  • sd:当前调度域
  • this_cpu:当前CPU编号
  • imbalance:输出参数,需要迁移的负载量
  • idle:当前CPU的空闲状态

返回值:最忙的调度组,NULL表示无需负载均衡

2. 变量初始化

struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups;
unsigned long max_load, avg_load, total_load, this_load, total_pwr;max_load = this_load = total_load = total_pwr = 0;

关键变量

  • busiest:指向最忙的调度组
  • this:指向当前CPU所在的调度组
  • max_load:最忙组的负载
  • this_load:当前组的负载
  • total_load:所有组的总负载
  • total_pwr:所有组的总计算能力

3. 调度组遍历和负载统计

do {unsigned long load;int local_group;int i, nr_cpus = 0;local_group = cpu_isset(this_cpu, group->cpumask);

本地组判断

local_group = cpu_isset(this_cpu, group->cpumask);
  • 检查当前CPU是否属于这个调度组
  • 本地组和远程组采用不同的负载计算策略

3.1.组内CPU负载累加

avg_load = 0;
for_each_cpu_mask(i, group->cpumask) {if (local_group)load = target_load(i);elseload = source_load(i);nr_cpus++;avg_load += load;
}

for_each_cpu_mask

  • 遍历调度组中所有的CPU
  • group->cpumask:位图,标识该组包含哪些CPU
  • i:循环变量,表示当前CPU编号

3.2.负载计算函数差异

**target_load() **

实现

static inline unsigned long target_load(int cpu)
{runqueue_t *rq = cpu_rq(cpu);unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;return max(rq->cpu_load, load_now);
}

特点:

  • 获取的负载值取 平均负载值瞬时负载值的较大值
  • 瞬时负载值影响较大
  • 得到的负载值大,迁移阈值高

**source_load() **

实现

static inline unsigned long source_load(int cpu)
{runqueue_t *rq = cpu_rq(cpu);unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;return min(rq->cpu_load, load_now);
}

特点:

  • 获取的负载值取 平均负载值瞬时负载值的较小值
  • 瞬时负载值影响较小
  • 得到的负载值小,迁移阈值低

4.负载标准化和power调整

#define SCHED_LOAD_SCALE        128UL   /* increase resolution of load */total_load += avg_load;
total_pwr += group->cpu_power;/* Adjust by relative CPU power of the group */
avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;

变量含义

  • total_load:所有调度组的原始负载总和
  • total_pwr:所有调度组的计算能力总和
  • group->cpu_power:该组的相对计算能力
标准化负载 = (原始负载 × 缩放因子) / CPU计算能力

将不同性能CPU的负载转换为可比较的标准单位

5.最忙组选择

if (local_group) {this_load = avg_load;this = group;goto nextgroup;
} else if (avg_load > max_load) {max_load = avg_load;busiest = group;
}

local_group

  • 记录本地组的负载到this_load

avg_load > max_load

  • 找到负载最高的远程组作为busiest

6.检查是否需要平衡

if (!busiest || this_load >= max_load)goto out_balanced;avg_load = (SCHED_LOAD_SCALE * total_load) / total_pwr;if (this_load >= avg_load ||100*max_load <= sd->imbalance_pct*this_load)goto out_balanced;

条件1:!busiest

!busiest  // 没有找到最忙的组

含义:只有一个本地调度组

条件2:this_load >= max_load

this_load >= max_load  // 当前组负载 ≥ 最忙组负载

含义:当前CPU所在组的负载已经不低于最忙组的负载

  • 如果当前组已经比最忙组更忙,迁移任务只会让情况更糟

全局平均负载计算

avg_load = (SCHED_LOAD_SCALE * total_load) / total_pwr;

计算公式

全局平均负载 = (缩放因子 × 总原始负载) / 总计算能力

计算整个调度域的负载

if (this_load >= avg_load ||100*max_load <= sd->imbalance_pct*this_load)goto out_balanced;

条件3:this_load >= avg_load

this_load >= avg_load  // 当前组负载 ≥ 全局平均负载

含义:当前组已经达到或超过全局平均负载水平

  • 当前组已经"贡献"了应有的负载份额

条件4:100\*max_load <= sd->imbalance_pct\*this_load

100 * max_load <= sd->imbalance_pct * this_load

重新排列更易理解

max_load <= (sd->imbalance_pct / 100) * this_load

实际含义

最忙组负载 ≤ 不平衡百分比 × 当前组负载

典型配置

sd->imbalance_pct = 125  // 25%的不平衡容忍度

计算示例

当前组负载 (this_load): 100
最忙组负载 (max_load): 120
不平衡百分比: 125%计算: 120 <= (125/100) × 100 = 125
条件成立: 120 <= 125 → 跳转到平衡状态

设计原理容忍适度不平衡

  • 允许一定程度的负载差异存在
  • 避免因微小不平衡触发昂贵的迁移操作
  • 在性能和完美平衡间取得权衡

6.1.不执行负载均衡的四种情况

  1. 无候选组!busiest
    • 说明只有一个本地组
  2. 当前组更忙this_load >= max_load
    • 迁移会使情况更糟
  3. 当前组已达平均this_load >= avg_load
    • 当前组已承担公平份额
  4. 不平衡在容忍范围内max_load ≤ 125% × this_load
    • 差异太小,不值得迁移

7.不平衡量计算

*imbalance = min(max_load - avg_load, avg_load - this_load);/* How much load to actually move to equalise the imbalance */
*imbalance = (*imbalance * min(busiest->cpu_power, this->cpu_power))/ SCHED_LOAD_SCALE;

这段代码计算了需要迁移的负载量

7.1.基础不平衡量计算

*imbalance = min(max_load - avg_load, avg_load - this_load);

计算两个方向的不平衡量,取较小值:

  1. max_load - avg_load:最忙组超出平均的负载量
  2. avg_load - this_load:当前组低于平均的负载量
7.1.1.为什么取最小值?

防止过度迁移

确保可行性

  • 迁移量不能超过当前组的接收能力
  • 迁移量不能超过最忙组的可释放量

7.2.功率调整计算

*imbalance = (*imbalance * min(busiest->cpu_power, this->cpu_power))/ SCHED_LOAD_SCALE;

计算公式

实际迁移量 = (基础不平衡量 × 最小CPU功率) / 缩放因子

按较弱CPU的能力调整

  • 迁移量受限于两个组中计算能力较低的一方
  • 确保迁移后的负载分布考虑实际硬件能力

7.3.在负载均衡流程中的位置

完整决策链

1. 找到最忙组 ✓
2. 检查是否需要平衡 ✓  
3. 计算基础不平衡量 ✓
4. 按CPU功率调整 ✓
5. 转换为实际任务数
6. 选择具体任务迁移

8.小不平衡量处理

	if (*imbalance < SCHED_LOAD_SCALE - 1) {unsigned long pwr_now = 0, pwr_move = 0;unsigned long tmp;if (max_load - this_load >= SCHED_LOAD_SCALE*2) {*imbalance = 1;return busiest;}pwr_now += busiest->cpu_power*min(SCHED_LOAD_SCALE, max_load);pwr_now += this->cpu_power*min(SCHED_LOAD_SCALE, this_load);pwr_now /= SCHED_LOAD_SCALE;tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/busiest->cpu_power;if (max_load > tmp)pwr_move += busiest->cpu_power*min(SCHED_LOAD_SCALE,max_load - tmp);tmp = SCHED_LOAD_SCALE*SCHED_LOAD_SCALE/this->cpu_power;if (max_load < tmp)tmp = max_load;pwr_move += this->cpu_power*min(SCHED_LOAD_SCALE, this_load + tmp);pwr_move /= SCHED_LOAD_SCALE;if (pwr_move < pwr_now + SCHED_LOAD_SCALE / 8)goto out_balanced;*imbalance = 1;}

这段代码处理小规模不平衡的特殊情况,进行经济性分析以决定是否值得迁移

8.1.条件判断入口

if (*imbalance < SCHED_LOAD_SCALE - 1) {

含义:当计算出的不平衡量小于127时(SCHED_LOAD_SCALE=128

设计意图

  • 不平衡量很小,可能不值得迁移
  • 需要进行成本收益分析
  • 避免因微小不平衡触发昂贵的迁移操作

8.2.严重不平衡的特殊处理

if (max_load - this_load >= SCHED_LOAD_SCALE*2) {*imbalance = 1;return busiest;
}

条件分析

max_load - this_load >= 256  // SCHED_LOAD_SCALE*2

含义:最忙组与当前组的负载差异很大(≥256)

特殊处理

  • 即使计算出的*imbalance很小
  • 也强制迁移至少1个任务(*imbalance = 1
  • 立即返回最忙组

设计原理:当负载差异很大时,即使精细计算显示迁移量小,也优先解决明显的不平衡

8.3.当前系统吞吐量计算

pwr_now += busiest->cpu_power * min(SCHED_LOAD_SCALE, max_load);
pwr_now += this->cpu_power * min(SCHED_LOAD_SCALE, this_load);
pwr_now /= SCHED_LOAD_SCALE;

计算公式

当前吞吐量 = (busiest_power × min(128, max_load) + this_power × min(128, this_load)) / 128

数学原理

  • 每个CPU的贡献受其计算能力和负载限制
  • min(SCHED_LOAD_SCALE, load):负载上限为128
  • 除以SCHED_LOAD_SCALE得到标准化吞吐量

8.4.迁移后吞吐量计算

第一部分:最忙组减少的负载

tmp = SCHED_LOAD_SCALE * SCHED_LOAD_SCALE / busiest->cpu_power;
if (max_load > tmp)pwr_move += busiest->cpu_power * min(SCHED_LOAD_SCALE, max_load - tmp);

计算tmp

tmp = 128 × 128 / busiest_cpu_power

含义:最忙组减少一个标准负载单位(128)对应的负载量

设计原理:考虑CPU功率差异,高性能CPU减少相同负载需要迁移更多任务

第二部分:当前组增加的负载

tmp = SCHED_LOAD_SCALE * SCHED_LOAD_SCALE / this->cpu_power;
if (max_load < tmp)tmp = max_load;
pwr_move += this->cpu_power * min(SCHED_LOAD_SCALE, this_load + tmp);

计算逻辑

  • 计算当前组增加一个标准负载单位对应的负载量
  • 如果max_load较小,使用实际值
  • 累加到迁移后吞吐量

最终吞吐量计算

pwr_move /= SCHED_LOAD_SCALE;

含义:将迁移后的吞吐量标准化。

8.5.经济性决策

if (pwr_move < pwr_now + SCHED_LOAD_SCALE / 8)goto out_balanced;

条件分析

迁移后吞吐量 < 当前吞吐量 + 16  (128/8)

设计原理:只有迁移能带来至少1/8 CPU的吞吐量提升时才执行迁移

决策逻辑

  • 如果收益太小,放弃迁移
  • 否则,设置最小迁移量(*imbalance = 1

9.不平衡量转化为实际任务数

*imbalance = (*imbalance + 1) / SCHED_LOAD_SCALE;
  • 实际任务数 = (负载量 + 1) / 缩放因子
  • +1确保至少迁移1个任务

10.特殊空闲状态处理

out_balanced:
if (busiest && (idle == NEWLY_IDLE ||(idle == SCHED_IDLE && max_load > SCHED_LOAD_SCALE)) ) {*imbalance = 1;return busiest;
}

空闲CPU的特殊规则

  • NEWLY_IDLE:刚变空闲,积极迁移
  • SCHED_IDLE:调度器空闲,只有负载较重时才迁移

11.完整算法流程

1. 遍历所有调度组,计算负载
2. 找到最忙的远程组和当前组
3. 检查系统是否已经平衡
4. 计算需要迁移的不平衡量
5. 对小不平衡量进行经济性分析
6. 考虑空闲状态的积极迁移
7. 返回最忙组和需要迁移的负载量

二、最忙运行队列查找函数find_busiest_queue

static runqueue_t *find_busiest_queue(struct sched_group *group)
{unsigned long load, max_load = 0;runqueue_t *busiest = NULL;int i;for_each_cpu_mask(i, group->cpumask) {load = source_load(i);if (load > max_load) {max_load = load;busiest = cpu_rq(i);}}return busiest;
}

这个函数在给定的调度组内查找负载最高的单个CPU运行队列

1. 函数原型和目的

static runqueue_t *find_busiest_queue(struct sched_group *group)

功能:在调度组的所有CPU中,找到负载最高的那个CPU的运行队列

参数

  • group:要搜索的调度组

2. 变量初始化

unsigned long load, max_load = 0;
runqueue_t *busiest = NULL;
int i;

变量说明

  • load:当前CPU的负载值
  • max_load:遇到的最大负载值
  • busiest:指向最忙运行队列的指针
  • i:循环计数器,表示CPU编号

3. 循环遍历组内所有CPU

for_each_cpu_mask(i, group->cpumask) {

for_each_cpu_mask

  • 遍历group->cpumask位图中设置的所有CPU
  • group->cpumask:位图,标识该调度组包含哪些CPU

4. 负载计算和比较

load = source_load(i);if (load > max_load) {max_load = load;busiest = cpu_rq(i);
}

source_load(i) 函数

  • 返回CPU i的负载,取 **平均负载 **和 瞬时负载的较小值
  • 对负载变化不敏感,防止出现乒乓效应

cpu_rq(i) 函数

  • 返回CPU i对应的运行队列指针
  • 每个CPU有自己独立的运行队列
http://www.dtcms.com/a/427214.html

相关文章:

  • 查看未知LiDAR设备的IP地址
  • iOS 0Day漏洞CVE-2025-24085相关PoC利用细节已公开
  • 网站文案框架网络推广策划书
  • 基于Chrome140的FB账号自动化——运行脚本(三)
  • 广州做网站设计镇江建筑公司排名最新
  • RHCA - CL260 | Day12:集群性能建议
  • CNN基础学习(自用)
  • Spring Boot 集成 Kafka 详解
  • MQTT数据集成
  • 网站的会员系统怎么做电商小程序价格
  • Redis 进阶:跳出缓存局限!7 大核心场景的原理与工程化实践
  • 数据结构——LinkedList和链表
  • 一学一做专题网站哈尔滨黑大主题邮局
  • 基于类的四种设计模式
  • 用ChatGPT修改论文,如何在提升质量的同时降低AI检测风险?
  • 实验指导-基于阿里云Serverless应用引l擎SAE的服务部署迀移
  • 黔西县住房和城乡建设局网站个人网页制作方法
  • 长沙网站推广系统动态wordpress动态主题
  • 基于Matlab实现路径规划
  • 给定数据规模的ACM风格笔试题-子矩阵的最大累加和问题
  • 一站式服务图片wordpress博客整站源码
  • 明星粉丝网站怎么做建设银行手机银行官方网站下载安装
  • Spring boot中 限制 Mybatis SQL日志的大字段输出
  • SQL Server数据库事务日志问题的诊断与解法(从膨胀到瘦身)
  • Postgresql CLOG文件及其从库同步解析
  • wordpress 授权一个空间两个网站对seo
  • 正规的招聘网站永州市网站建设
  • 加强教育信息网站建设昆山建设工程安监站网站
  • EndoChat:面向内镜手术的基于事实依据的多模态大型语言模型|文献速递-文献分享
  • 零基础学AI大模型之ChatModel聊天模型与ChatPromptTemplate实战