linux 多核支持原理,linux在多核处理器上的负载均衡原理(2)

假如现在是 Core 3 在执行idle_balance,则先在domain 1里找最忙的group,找到第二忙的group是core 0(core 4不在domain 1里,所以不会找到它),再从core 0里找最忙的runqueue(运行队列),core 0就一个运行队列,所以直接就是它对应的runqueue了,然后从该runqueue里挪出几个任务到Core 3,这一层domain的均衡做完了。

接着是domain

1的父domain,即 cpu_domain,下图的domain 0:

6faa216fd4c4165e439eb837d50229c1.gif

这个domain 0包含了两个group,每个group对应一个chip,即每个group对应了4个core。

在domain 0找最繁忙的group,显然会找到Processor1 对应的group(因为core 4超忙),那么继续在Processor 1里找最忙的runqueue,于是找到core 4,最后从core 4的runqueue里挑出几个任务挪到core 3,。

这样,整个系统8个核都基本平衡了。

也许有人要问,为什么是从子domain到父domain这样遍历,而不是倒过来,从父到子遍历呢?这是因为子domain通常都是在一个chip上,任务的很多数据在共享的L2 cache上,为了不让其失效,有必要尽量让任务保持在一个chip上。

也许还有人要问:如果core 3本来就是最忙的core,它如果运行idle_balance,会发生什么?答案是什么也不会发生。因为在find_busiest_group函数里,如果发现最忙的是“本CPU”,那么就直接返回NULL,也就不再做任何事。

那core 3岂不永远是最忙的了?呵呵,大家忘了,系统里总有闲的CPU(哪怕是相对比较闲),它总会执行schedule(),就算它从不调用sleep从不睡眠,时钟中断也会迫使其进程切换,进而调用schedule,进而将繁忙CPU的任务揽一部分到自己身上。这样,谁最闲,谁早晚会从忙人身上揽活儿过来,所以忙人不会永远最忙,闲人也不会永远最闲,所以就平等,就均衡了。

再看try_to_wake_up():

[kernel/sched.c --> try_to_wake_up()]

1398 static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync)

1399 {

......

1417

1418     cpu = task_cpu(p);

1419     this_cpu = smp_processor_id();

1420

1421 #ifdef CONFIG_SMP

1422     if (unlikely(task_running(rq, p)))

1423         goto out_activate;

1424

1425     new_cpu = cpu;

1426

1427     schedstat_inc(rq, ttwu_cnt);

1428     if (cpu == this_cpu) {

1429         schedstat_inc(rq, ttwu_local);

1430         goto out_set_cpu;

1431     }

变量this_cpu和变量cpu有什么区别?变量this_cpu是实际运行这个函数的处理器(“目标处理器”),而变量cpu是进程p在睡眠之前运行的处理器??为了方便我们暂且称之为“源处理器”。当然,这两个处理器也可能是同一个,比如进程p在处理器A上运行,然后睡眠,而运行try_to_wake_up的也是处理器A,其实这样就最好了,进程p在处理器A里cache的数据都不用动,直接让A运行p就行了??这就是1428行的逻辑。

如果this_cpu和cpu不是同一个处理器,那么代码继续:

1447     if (this_sd) {

1448         int idx = this_sd->wake_idx;

1449         unsigned int imbalance;

1450

1451         imbalance = 100 + (this_sd->imbalance_pct - 100) / 2;

1452

1453         load = source_load(cpu, idx);

1454         this_load = target_load(this_cpu, idx);

1455

1456         new_cpu = this_cpu; /* Wake to this CPU if we can */

1457

1458         if (this_sd->flags & SD_WAKE_AFFINE) {

1459             unsigned long tl = this_load;

1460             unsigned long tl_per_task;

1461

1462             tl_per_task = cpu_avg_load_per_task(this_cpu);

1463

1464             /*

1465              * If sync wakeup then subtract the (maximum possible)

1466              * effect of the currently running task from the load

1467              * of the current CPU:

1468              */

1469             if (sync)

1470                 tl -= current->load_weight;

1471

1472             if ((tl <= load &&

1473                 tl + target_load(cpu, idx) <= tl_per_task) ||

1474                 100*(tl + p->load_weight) <= imbalance*load) {

1475                 /*

1476                  * This domain has SD_WAKE_AFFINE and

1477                  * p is cache cold in this domain, and

1478                  * there is no bad imbalance.

1479                  */

1480                 schedstat_inc(this_sd, ttwu_move_affine);

1481                 goto out_set_cpu;

1482             }

1483         }

计算出“目标处理器”和“源处理器”各自的负载(

1453行和1454行),再计算“目标处理器”上的每任务平均负载

tl_per_task,最后进行判断:如果“目标处理器”的负载小于“源处理器”的负载且两处理器负载相加都比 tl_per_task小的话,唤醒的进程转为“目标处理器”执行。还有一种情况就是1474行的判断,如果“目标处理器”的负载加上被唤醒的进程的负载后,还比“源处理器”的负载(乘以imbalance后)的小的话,也要把唤醒的进程转为“目标处理器”执行。如果两个因素都不满足,那还是由p进程原来呆的那个CPU(即”源处理器“)继续来处理吧。

有点儿绕,是吧?其实代码虽绕,用意是简单的:

1472行-1473行其实是这样一个用意:如果“目标处理器”的负载很小,小得即使把压力全给到“源处理器”上去也不会超过“源处理器”上的平均任务负载,那么这“目标处理器”的负载是真的很小,值得把p进程挪过来。

1474行的用意则是:如果我们真的把p进程挪到“目标处理器”以后,“目标处理器”的压力也不比“源处理器”大多少,所以,还是值得一挪。

说来说去,还是那个笨原则:把任务从最忙的CPU那儿转到很闲的CPU这儿。

我们已经看过了睡眠和醒来时的内核函数,那么软中断里的

run_rebalance_domains又干了些什么呢?其实也很简单,它调用了load_balance函数,而这个函数和load_balance_newidle实现上基本一样,就不累述了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值