// 计算group在给定domain中的imbalance // 调用路径:find_busiest_group->calculate_imbalance // 函数参数: // sds:sched domain的统计信息 // this_cpu:当前正在运行load balance的cpu // imbalance:保存imbalance值 // 函数任务: // 1.计算最忙group内进程的平均负载 // 1.1 公式:最忙group当前的负载量/最忙group当前运行的进程数 // 2.如果最忙group失衡 // 2.1 最忙group内进程的平均负载 = min(最忙group的当前负载,sched doman的平均负载) // 3.如果最忙group的负载小于domain平均负载,则说明已经平衡,返回 // 4.如果最忙group没有失衡 // 4.1 计算最忙group超过group容量的进程个数 // 5.计算load balance进行pull的load // 5.1 pull的load量为 min(最忙group超过domain平均负载的量,最忙group的超过容量的负载量) // 6.计算this_cpu所在group与最忙cpu所在group之间的imbalance量 // 6.1 imbalance量为 min(load balance进行pull的load,当前cpu所在group超过domain平均负载的量) // 7.如果imbalance不足最忙group中进程的平均负载 // 7.1 进行微调整 static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu, unsigned long *imbalance) { unsigned long max_pull, load_above_capacity = ~0UL; //计算最忙group内进程当前的平均负载 sds->busiest_load_per_task /= sds->busiest_nr_running; //如果最忙group失衡 if (sds->group_imb) { //则最忙group内进程的平均负载取 min(当前负载、历史负载) sds->busiest_load_per_task = min(sds->busiest_load_per_task, sds->avg_load); } //如果最忙group的负载小于平均负载,则说明已平衡 if (sds->max_load < sds->avg_load) { //imbalance=0 *imbalance = 0; return fix_small_imbalance(sds, this_cpu, imbalance); } //没有group失衡 if (!sds->group_imb) { //最忙group超过容量的进程数 load_above_capacity = (sds->busiest_nr_running - sds->busiest_group_capacity); load_above_capacity *= (SCHED_LOAD_SCALE * SCHED_LOAD_SCALE); load_above_capacity /= sds->busiest->cpu_power; } //计算load balance进行pull的load max_pull = min(sds->max_load - sds->avg_load, load_above_capacity); //计算imbalance *imbalance = min(max_pull * sds->busiest->cpu_power, (sds->avg_load - sds->this_load) * sds->this->cpu_power) / SCHED_LOAD_SCALE; //imbalance不足最忙group中进程的平均负载 if (*imbalance < sds->busiest_load_per_task) return fix_small_imbalance(sds, this_cpu, imbalance); } // 查找sched group中最忙的group // 函数任务: // 1.遍历group内所有在线的cpu // 1.1 获取cpu对应的rq的当前负载rq->load.weight // 1.2 如果rq当前只有一个进程,并且负载大于imbalance,继续1.1 // 1.3 通过cpu power计算cpu的负载 // 1.3.1 为方便在不同cpu见进行比较 // 1.4 记录负载最大的cpu // 2.返回最忙的cpu // 调用路径:load_balance->find_busiest_queue 2.1 static struct rq *find_busiest_queue(struct sched_group *group, enum cpu_idle_type idle, unsigned long imbalance, const struct cpumask *cpus) { struct rq *busiest = NULL, *rq; unsigned long max_load = 0; int i; //遍历group内的cpu for_each_cpu(i, sched_group_cpus(group)) { unsigned long power = power_of(i); unsigned long capacity = DIV_ROUND_CLOSEST(power, SCHED_LOAD_SCALE); unsigned long wl; //cpu在线 if (!cpumask_test_cpu(i, cpus)) continue; //cpu的rq rq = cpu_rq(i); //rq当前的负载 wl = weighted_cpuload(i); //rq当前只有一个进程,则返回 if (capacity && rq->nr_running == 1 && wl > imbalance) continue; //通过cpu power计算cpu的负载 wl = (wl * SCHED_LOAD_SCALE) / power; //记录最大负载的cpu if (wl > max_load) { max_load = wl; busiest = rq; } } //返回最忙的cpu return busiest; } // 获取cpu power // 函数任务: // 1.如果cpu没有对应的group,返回SCHED_LOAD_SCALE // 2.否则返回对应group的power 2.2 static unsigned long power_of(int cpu) { //获取cpu对应的group struct sched_group *group = group_of(cpu); //没有对应的group,返回SCHED_LOAD_SCALE if (!group) return SCHED_LOAD_SCALE; //否则返回group的power return group->cpu_power; }