// 计算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;
}