diff --git a/study/kernel/00-DESCRIPTION/SCHEDULER.md b/study/kernel/00-DESCRIPTION/SCHEDULER.md index 071e8b2..f6690ca 100644 --- a/study/kernel/00-DESCRIPTION/SCHEDULER.md +++ b/study/kernel/00-DESCRIPTION/SCHEDULER.md @@ -1957,7 +1957,7 @@ max_idle_balance_cost 则跟踪了当前调度域最近一段时间执行 idle b | 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 | |:----:|:----:|:---:|:---:|:----------:|:----:| -| 2013/09/13 | Jason Low | [sched: Limiting idle balance](https://lore.kernel.org/patchwork/patch/403138) | 这些补丁修改和添加了限制 idle balance 的方式. [第一个补丁](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=abfafa54db9aba404e8e6763503f04d35bd07138)减少了我们高估 avg_idle 的可能性. [第二个补丁](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9bd721c55c8a886b938a45198aab0ccb52f1f7fa)引入了 sd->max_idle_balance_cost 跟踪了跟踪每个调度域执行 idle balance 所花费的最大成本, 如果当前 CPU 的平均 idle 时间 rq->avg_idle 小于 sd->max_idle_balance_cost, 则限制 idle balance, 此时没必要再通过 idle balance 从其他 CPU 上 pull 一个进程过来, 因此可能 idle balance 还没有完成, 就本核上其他进程就可以已经唤醒准备投入运行. [第三个补丁](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f48627e686a69f5215cb0761e731edb3d9859dd9) 则周期性地衰减每个 sched_domain 的 max_idle_balance_cost. 当 CPU 保持空闲的时间很短且不超过执行平衡的成本时, 这些更改进一步减少了我们尝试 idle balance 的机会. | v5 ☑ 3.13-rc1 | [LORE v5,0/3](https://lore.kernel.org/all/1379096813-3032-1-git-send-email-jason.low2@hp.com) | +| 2013/09/13 | Jason Low | [sched: Limiting idle balance](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=f48627e686a69f5215cb0761e731edb3d9859dd9) | 这些补丁修改和添加了限制 idle balance 的方式. [第一个补丁](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=abfafa54db9aba404e8e6763503f04d35bd07138)减少了我们高估 avg_idle 的可能性. [第二个补丁](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9bd721c55c8a886b938a45198aab0ccb52f1f7fa)引入了 sd->max_idle_balance_cost 跟踪了跟踪每个调度域执行 idle balance 所花费的最大成本, 如果当前 CPU 的平均 idle 时间 rq->avg_idle 小于 sd->max_idle_balance_cost, 则限制 idle balance, 此时没必要再通过 idle balance 从其他 CPU 上 pull 一个进程过来, 因此可能 idle balance 还没有完成, 就本核上其他进程就可以已经唤醒准备投入运行. [第三个补丁](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f48627e686a69f5215cb0761e731edb3d9859dd9) 则周期性地衰减每个 sched_domain 的 max_idle_balance_cost. 当 CPU 保持空闲的时间很短且不超过执行平衡的成本时, 这些更改进一步减少了我们尝试 idle balance 的机会. | v5 ☑ 3.13-rc1 | [LORE v5,0/3](https://lore.kernel.org/all/1379096813-3032-1-git-send-email-jason.low2@hp.com) | ### 4.4.2 Improve cost accounting of newidle_balance ------- diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/Makefile b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/Makefile index 1dfecff..fa43dc2 100644 --- a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/Makefile +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/Makefile @@ -1,21 +1,9 @@ -ROOT=../../../ -PLATFORM=$(shell $(ROOT)/systype.sh) -include $(ROOT)/Make.defines.$(PLATFORM) - -target=memorylayout - - +target=load_balance.svg newidle_balance.svg nohz_idle_balance.svg tick_load_balance.svg passive_load_balance.svg all:$(target) - -memorylayout : memorylayout.o - $(CC) $^ -o $@ $(LDFLAGS) - echo "C程序的内存布局..." - -%.o : %.c - $(CC) -c $^ -o $@ $(CFLAGS) $(DEFINES) +%.svg : %.gv + dot -Tsvg $^ -o $@ clean : - rm -rf *.o rm -rf $(target) diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/README.md b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/README.md index 02c54c7..db628a8 100644 --- a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/README.md +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/README.md @@ -2,8 +2,102 @@ ------- -# 2 周期性调度器 +* 主动 Load Balancing + +1. CFS 负载均衡器周期性的检查系统的负载均衡状态, 然后从 busy CPU 上拉取任务出来, 使系统跟均衡. + +2. 但是要想让系统中的 Newly Idle CPU, 能够躁动起来, 就需要借助 Idle Load Balance. + +3. 而对于进入 NOHZ 状态的 IDLE CPU, 只能寄希望于 NOHZ Idle Load Balance 通过 KICK 将其唤醒. + +| 均衡器 | 描述 | +|:----:|:----:| +| 周期性负载均衡 (periodic load balance 或者 tick load balance | 在 TICK 中, 周期性的检测系统的负载均衡状况, 依次遍历每层调度域, 自底向上进行负载均衡. 通过 find_busiest_group() 找到系统中负载最重的 sched_group, 通过 find_busiest_group() 找到其中最繁忙的 CPU, 将其上的 RUNNABLE(甚至是 RUNNING) 任务拉到本 CPU 以便让系统的负载处于均衡的状态. 为了避免每层调度域负载均衡过于频繁, 通常在 sched_group 内第一个 IDLE 的 CPU 上执行, 参见 should_we_balance(), 同时通过 sd->balance_interval 限制出发间隔. | +| New Idle Load Balance | 当 CPU 上没有任务执行即将进入 IDLE 状态的时候, 是执行 Load Balance 非常合适的时机. 这时候看看其他 CPU 是否需要帮忙, 从 BUSY 的 CPU 上拉取任务, 可以让整个系统的负载处于更加均衡的状态. | +| NOHZ Idle Load Balance | 其他的 CPU 已经进入 NOHZ IDLE 状态, 不太可能触发 TICK 进行周期性负载均衡, 但是本 CPU 上任务又太重, 此时则需要通过 IPI KICK 其他 IDLE 的 CPU, 唤醒它来进行负载均衡. | + +* 被动 Load Balancing + +4. 除了 CFS 本身 PULL 机制的主动 Load Balance 之外, 可以认为: 所有 select_task_rq 的时机都是一次隐含的 LoadBalance. 因此选核决策本身, 也需要考虑一定的负载均衡决策. + +| 时机 | 描述 | +|:---:|:----:| +| WF_FORK | 每次 FORK 后, wake_up_new_task() 唤醒新创建的进程时, 会为进程选择一次 CPU. | +| WF_EXEC | 每次一个进程执行 exec 后, sched_exec() 中会为新进程重新选核. | +| WF_TTWU | 每次 try_to_wake_up() 唤醒进程时, 为重新为进程选核. | + + +# 2 SMP NICE 的 Load Balancing +------- + +## 2.1 Periodic Load Balance +------- + + +| 背景 | 描述 | 参考 | +|:---:|:----:|:---:| +| 为什么需要 Periodic Load Balance | 周期性地检查系统的负载均衡情况, 必要时执行负载均衡. | trigger_load_balance() | +| 哪些 CPU 触发/执行 NOHZ Load Balance | 通常是 sched_group 域内第一个 IDLE CPU. 没有没有 IDLE CPU, 则由 sched_group 的第一个 CPU 来完成. | should_we_balance() | +| 如何触发 Periodic Load Balance | TICK 中通过发送 SCHED_SOFTIRQ 的软中断来处理, 最终执行 run_rebalance_domains(). | run_rebalance_domains() | +| 如何进行 Periodic Load Balance | 自底向上遍历所有调度域, 对所有配置了调度域, 依次执行 load_balance(). | rebalance_domain() | + +![Periodic Load Balance](./tick_load_balance.svg) + +## 2.2 New Idle Load Balance +------- + +| 背景 | 描述 | 参考 | +|:---:|:----:|:---:| +| 为什么需要 New Idle Load Balance? | 为了保持系统吞吐量最大化, 那么当 CPU 即将 IDLE 时, 尝试从其他 BUSY CPU 上 PULL 任务出来时一个非常合适的主动 Load Balance 时机. 但是在每次 CPU NEWLY IDLE 时都进行 Idle Balancing 又时非常不合适的. 因此如果该 CPU 平均 IDLE 时间非常短, CPU 本身很快就会被任务重新唤醒, 这时当 CPU 重新回来执行的任务的时候, 还是 cache hot 的, 如果从其他 CPU 上拉取任务, 那么这些新的任务会破坏当前 CPU 上原来任务的 cache 状态. 更进一步此时被唤醒的任务不得不出现 RUNNABLE, 甚至迁移, 这都无疑会影响系统的性能. | NA | +| 哪些 CPU 触发/执行 NOHZ Load Balance | 没有任务执行, 即将进入 IDLE 状态的 CPU 作为 src_cpu. 系统中繁忙的 CPU 作为 dst_cpu. | newidle_balance() | +| 如何触发 New Idle Load Balance | 以下情况下 IDLE CPU 不会执行 Idle Balancing. 1. 如果 CPU 上有 ttwu_pending, 则其马上就会被唤醒.
2. 如果当前 IDLE CPU 的历史平均 IDLE 时间 avg_idle 比系统整体的 newidle 开销 max_newidle_lb_cost 要小, 说明做 Idle Balancing, 收益不大. 任务都还没有 PULL 过来, CPU 就被唤醒了已经.
3. root_domain 需要 overload, 如果 CPU 上大于 1 个 runnable task, 即该 CPU 上有等待执行的任务. 或者只有一个正在运行的任务, 但是是 misfit task. 则会对应设置 sched_group 为 SG_OVERLOAD, 继而 root_domain 被认为是 overload. | newidle_balance() | +| 如何进行 New Idle Load Balance | 从当前 newly IDLE 的 CPU, 自底向上遍历所有调度域, 对所有配置了 SD_BALANCE_NEWIDLE 的调度域, 依次执行 load_balance(). | newidle_balance() | + +![New Idle Load Balance](./newidle_balance.svg) + +## 2.3 NOHZ Load Balance +------- + +| 背景 | 描述 | 参考 | +|:---:|:----:|:---:| +| 为什么需要 NOHZ Load Balance? | 如果 CPU 进入 IDLE 状态之后仍然有周期性的 TICK, 那么通过周期性负载均衡就能完成负载均衡了. 但是如果内核配置了 NOHZ, 那么 CPU 进入 IDLE 状态后, TICK 也会被停掉. 这就造成周期性负载均衡不会触发. 不需要 IPI 来唤醒 idle 的 CPU. 和周期性均衡一样, NOHZ idle load balance 也是通过 busy CPU 上 tick 驱动的, 如果需要 kick idle load balancer, 那么就会通过 GIC 发送一个 ipi 中断给选中的 idle CPU, 让它代表系统所有的 idle CPU 们进行负载均衡. | NA | +| 哪些 CPU 触发 NOHZ Load Balance | TICK 中触发周期性负载均衡之前, 检查是否需要进行 NOHZ KICK, 唤醒一个 IDLE CPU 来帮忙做 Load Balancing. | trigger_load_balance()
->nohz_balancer_kick()
->kick_ilb() | +| 如何触发 NOHZ Load Balance | BUSY 的 CPU 会 KICK ILB owner, 通过 IPI 发送 SCHED_SOFTIRQ. 并标记 ILB owner 的 rq->nohz_idle_balance. | nohz_csd_func()
->raise_softirq_irqoff(SCHED_SOFTIRQ) | +| 哪些 CPU 执行 NOHZ Load Balance | 会寻找一个 IDLE 的 CPU, 作为 ILB owner 来执行. 通常为 nohz.idle_cpus_mask 记录的第一个 IDLE CPU. | find_new_ilb() | +| 如何进行 NOHZ Load Balance | ILB owner 接收到 SCHED_SOFTIRQ 后, 触发 run_rebalance_domains() 时会检查是否需要进行 nohz_idle_balance(). | run_rebalance_domains()
->nohz_idle_balance(). | + + +![NOHZ Load Balance](./nohz_idle_balance.svg) + +## 2.4 Load Balance 的核心主体 +------- + +![Load Balance](./load_balance.svg) + + +## 2.5 Passive Load Balancing +------- + + +| 均衡器 | 描述 | 选核 select_task_rq_fair() 标记的 FLAG | 执行均衡决策时的 FLAG | +|:-----:|:----:|:--------:|:--------:| +| FORK 均衡 | 创建任务时, 确定任务是在父任务运行的 CPU 上执行, 还是迁移到其他 CPU. | 如果可能, 请选择具有缓存亲和力的 CPU 或 IDLE CPU, 否则将迁移到 CPU 负载较低的 CPU 运行. 在 wake_up_new_task() 函数中使用 SD_BALANCE_FORK 标志调用它. | WF_FORK | SD_BALANCE_FORK | +| EXEC 平衡 | 进程执行 exec, 加载新程序空间, 运行新任务时, 确定任务是从现有 CPU 执行还是迁移到其他 CPU. 如果可能. 请选择具有缓存亲和力的 cpu 或 idle cpu,否则将迁移到 CPU 负载较低的 cpu 运行. 迁移到其他 cpu 时使用混合线程. 在 sched_exec() 函数中使用 SD_BALANCE_EXEC 标志. | WF_EXEC | SD_BALANCE_EXEC | +| WAKEUP 平衡 | 确定在 idle 任务唤醒时是从唤醒的 CPU 执行还是迁移到其他 IDLE CPU. 在 try_to_wake_up() 中使用 SD_BALANCE_WAKE 标志. | WF_TTWU | SD_BALANCE_WAKE | + +![Passive Load Balancing](./passive_load_balance.svg) + + +# 3 能效感知的 Load Balancing 决策 +------- + + +# X 扩展阅读 +------- -# 3 \ No newline at end of file +| 文档 | 描述 | +|:---:|:----:| +| [内核工匠 - 负载均衡情景分析](https://blog.csdn.net/feelabclihu/article/details/112057633) | 介绍 CFS 负载均衡的基础框架核原理. | +| [jakeisname 的博客专栏](http://jake.dothome.co.kr/scheduler) | 韩国内核开发者 jakeisname 的博客专栏. | \ No newline at end of file diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/load_balance.gv b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/load_balance.gv index a95eab3..0f8adff 100644 --- a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/load_balance.gv +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/load_balance.gv @@ -10,14 +10,42 @@ digraph load_balance { newidle_balance -> load_balance; // 负载均衡核心逻辑 - load_balance:s -> {should_we_balance, find_busiest_group, find_busiest_queue, detach_tasks, attach_tasks, need_active_balance, stop_one_cpu_nowait}; - should_we_balance -> {group_balance_mask, group_balance_cpu}; - find_busiest_group -> {init_sd_lb_stats, update_sd_lb_stats, sched_energy_enabled, compare_local_busiest_group_type, calculate_imbalance}; - find_busiest_queue -> for_each_sched_group_span -> {fbq_classify_rq, switch_env_migration_type_FBQ}; - detach_tasks -> {can_migrate_task, switch_env_migration_type_DT, detach_task}; - attach_tasks -> {attach_task}; - need_active_balance -> stop_one_cpu_nowait -> active_load_balance_cpu_stop [style=dashed]; - active_load_balance_cpu_stop -> {detach_one_task, attach_one_task}; + subgraph cluster_0 { + label = "执行 Load Balance"; + color = blue; + + load_balance:s -> {should_we_balance, find_busiest_group, find_busiest_queue, detach_tasks, attach_tasks, need_active_balance, stop_one_cpu_nowait}; + + subgraph cluster_1 { + label = "寻找 dst CPU"; + color = red; + + should_we_balance -> {group_balance_mask, group_balance_cpu}; + }; + + subgraph cluster_2 { + label = "寻找 src CPU"; + color = red; + + find_busiest_group -> {init_sd_lb_stats, update_sd_lb_stats, sched_energy_enabled, compare_local_busiest_group_type, calculate_imbalance}; + find_busiest_queue -> for_each_sched_group_span -> {fbq_classify_rq, switch_env_migration_type_FBQ}; + }; + + subgraph cluster_3 { + label = "Normal Migration"; + color = red; + + detach_tasks -> {can_migrate_task, switch_env_migration_type_DT, detach_task}; + attach_tasks -> {attach_task}; + }; + subgraph cluster_4 { + label = "Active Migration"; + color = red; + + need_active_balance -> stop_one_cpu_nowait -> active_load_balance_cpu_stop [style=dashed]; + active_load_balance_cpu_stop -> {detach_one_task, attach_one_task}; + }; + }; rebalance_domains [label="rebalance_domains"; style=filled; fillcolor=palegreen; shape=oval]; newidle_balance [label="newidle_balance"; style=filled; fillcolor=palegreen; shape=oval]; diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/load_balance.svg b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/load_balance.svg new file mode 100644 index 0000000..d4e32a9 --- /dev/null +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/load_balance.svg @@ -0,0 +1,362 @@ + + + + + + +load_balance + + +cluster_0 + +执行 Load Balance + + +cluster_1 + +寻找 dst CPU + + +cluster_2 + +寻找 src CPU + + +cluster_3 + +Normal Migration + + +cluster_4 + +Active Migration + + + +rebalance_domains + +rebalance_domains + + + +load_balance + +load_balance + + + +rebalance_domains->load_balance + + + + + +should_we_balance + +should_we_balance + + + +load_balance:s->should_we_balance + + + + + +find_busiest_group + +find_busiest_group + + + +load_balance:s->find_busiest_group + + + + + +find_busiest_queue + +find_busiest_queue + + + +load_balance:s->find_busiest_queue + + + + + +detach_tasks + +detach_tasks + + + +load_balance:s->detach_tasks + + + + + +attach_tasks + +attach_tasks + + + +load_balance:s->attach_tasks + + + + + +need_active_balance + +need_active_balance + + + +load_balance:s->need_active_balance + + + + + +stop_one_cpu_nowait + +stop_one_cpu_nowait + + + +load_balance:s->stop_one_cpu_nowait + + + + + +newidle_balance + +newidle_balance + + + +newidle_balance->load_balance + + + + + +group_balance_mask + +group_balance_mask + + + +should_we_balance->group_balance_mask + + + + + +group_balance_cpu + +group_balance_cpu + + + +should_we_balance->group_balance_cpu + + + + + +init_sd_lb_stats + +init_sd_lb_stats + + + +find_busiest_group->init_sd_lb_stats + + + + + +update_sd_lb_stats + +update_sd_lb_stats + + + +find_busiest_group->update_sd_lb_stats + + + + + +sched_energy_enabled + +sched_energy_enabled + + + +find_busiest_group->sched_energy_enabled + + + + + +compare_local_busiest_group_type + +compare_local_busiest_group_type + + + +find_busiest_group->compare_local_busiest_group_type + + + + + +calculate_imbalance + +calculate_imbalance + + + +find_busiest_group->calculate_imbalance + + + + + +for_each_sched_group_span + +for_each_sched_group_span + + + +find_busiest_queue->for_each_sched_group_span + + + + + +can_migrate_task + +can_migrate_task + + + +detach_tasks->can_migrate_task + + + + + +switch_env_migration_type_DT + +switch_env_migration_type_DT + + + +detach_tasks->switch_env_migration_type_DT + + + + + +detach_task + +detach_task + + + +detach_tasks->detach_task + + + + + +attach_task + +attach_task + + + +attach_tasks->attach_task + + + + + +need_active_balance->stop_one_cpu_nowait + + + + + +active_load_balance_cpu_stop + +active_load_balance_cpu_stop + + + +stop_one_cpu_nowait->active_load_balance_cpu_stop + + + + + +fbq_classify_rq + +fbq_classify_rq + + + +for_each_sched_group_span->fbq_classify_rq + + + + + +switch_env_migration_type_FBQ + +switch_env_migration_type_FBQ + + + +for_each_sched_group_span->switch_env_migration_type_FBQ + + + + + +detach_one_task + +detach_one_task + + + +active_load_balance_cpu_stop->detach_one_task + + + + + +attach_one_task + +attach_one_task + + + +active_load_balance_cpu_stop->attach_one_task + + + + + diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/newidle_balance.gv b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/newidle_balance.gv index 5c9ed3f..b8abbe4 100644 --- a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/newidle_balance.gv +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/newidle_balance.gv @@ -1,17 +1,28 @@ digraph newidle_balance { // IDLE 负载均衡器 - __schedule -> pick_next_task;// -> {__pick_next_task, put_prev_task_balance}; - pick_next_task -> __pick_next_task [label="!sched_core_enabled(rq)"]; - pick_next_task -> put_prev_task_balance [label="sched_core_enabled"]; + subgraph cluster_1 { + label = "触发 New Idle Load Balance"; + color=red; - __pick_next_task -> {pick_next_task_fair, pick_next_task_idle, put_prev_task_balance, class_pick_next_task}; - class_pick_next_task -> pick_next_task_fair [style=dashed]; - put_prev_task_balance -> for_class_range_prev_to_idle -> class_balance -> balance_fair -> newidle_balance; - pick_next_task_fair -> newidle_balance - newidle_balance -> {update_misfit_status, update_next_balance, update_blocked_averages, for_each_domain_ILB} -> nohz_newidle_balance; + __schedule -> pick_next_task;// -> {__pick_next_task, put_prev_task_balance}; + pick_next_task -> __pick_next_task [label="!sched_core_enabled(rq)"]; + pick_next_task -> put_prev_task_balance [label="sched_core_enabled"]; - for_each_domain_ILB -> {update_next_balance, load_balance, update_newidle_cost}; - nohz_newidle_balance -> set_NOHZ_NEWILB_KICK + __pick_next_task -> {pick_next_task_fair, pick_next_task_idle, put_prev_task_balance, class_pick_next_task}; + class_pick_next_task -> pick_next_task_fair [style=dashed]; + put_prev_task_balance -> for_class_range_prev_to_idle -> class_balance -> balance_fair -> newidle_balance; + pick_next_task_fair -> newidle_balance; + }; + + subgraph cluster_2 { + label = "执行 New Idle Load Balance"; + color=blue; + + newidle_balance -> {update_misfit_status, update_next_balance, update_blocked_averages, for_each_domain_ILB} -> nohz_newidle_balance; + + for_each_domain_ILB -> {update_next_balance, load_balance, update_newidle_cost}; + nohz_newidle_balance -> set_NOHZ_NEWILB_KICK + }; // caller pick_next_task_fair [label="pick_next_task_fair"; style=filled; fillcolor=lightyellow; shape=oval]; diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/newidle_balance.svg b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/newidle_balance.svg new file mode 100644 index 0000000..ca5a18b --- /dev/null +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/newidle_balance.svg @@ -0,0 +1,289 @@ + + + + + + +newidle_balance + + +cluster_1 + +触发 New Idle Load Balance + + +cluster_2 + +执行 New Idle Load Balance + + + +__schedule + +__schedule + + + +pick_next_task + +pick_next_task + + + +__schedule->pick_next_task + + + + + +__pick_next_task + +__pick_next_task + + + +pick_next_task->__pick_next_task + + +!sched_core_enabled(rq) + + + +put_prev_task_balance + +put_prev_task_balance + + + +pick_next_task->put_prev_task_balance + + +sched_core_enabled + + + +__pick_next_task->put_prev_task_balance + + + + + +pick_next_task_fair + +pick_next_task_fair + + + +__pick_next_task->pick_next_task_fair + + + + + +pick_next_task_idle + +pick_next_task_idle + + + +__pick_next_task->pick_next_task_idle + + + + + +class_pick_next_task + +class->pick_next_task + + + +__pick_next_task->class_pick_next_task + + + + + +for_class_range_prev_to_idle + +for_class_range_prev_to_idle + + + +put_prev_task_balance->for_class_range_prev_to_idle + + + + + +newidle_balance + +newidle_balance + + + +pick_next_task_fair->newidle_balance + + + + + +class_pick_next_task->pick_next_task_fair + + + + + +class_balance + +class->balance + + + +for_class_range_prev_to_idle->class_balance + + + + + +balance_fair + +balance_fair + + + +class_balance->balance_fair + + + + + +balance_fair->newidle_balance + + + + + +update_misfit_status + +update_misfit_status + + + +newidle_balance->update_misfit_status + + + + + +update_next_balance + +update_next_balance + + + +newidle_balance->update_next_balance + + + + + +update_blocked_averages + +update_blocked_averages + + + +newidle_balance->update_blocked_averages + + + + + +for_each_domain_ILB + +for_each_domain_ILB + + + +newidle_balance->for_each_domain_ILB + + + + + +nohz_newidle_balance + +nohz_newidle_balance + + + +update_misfit_status->nohz_newidle_balance + + + + + +update_next_balance->nohz_newidle_balance + + + + + +update_blocked_averages->nohz_newidle_balance + + + + + +for_each_domain_ILB->update_next_balance + + + + + +for_each_domain_ILB->nohz_newidle_balance + + + + + +load_balance + +load_balance + + + +for_each_domain_ILB->load_balance + + + + + +update_newidle_cost + +update_newidle_cost + + + +for_each_domain_ILB->update_newidle_cost + + + + + +set_NOHZ_NEWILB_KICK + +set_NOHZ_NEWILB_KICK + + + +nohz_newidle_balance->set_NOHZ_NEWILB_KICK + + + + + diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/nohz_idle_balance.gv b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/nohz_idle_balance.gv index fa060d2..ce2c10f 100644 --- a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/nohz_idle_balance.gv +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/nohz_idle_balance.gv @@ -1,30 +1,42 @@ digraph nohz_idle_balance { // 周期性负载均衡器 run_rebalance_domains //run_rebalance_domains -> {nohz_idle_balance, update_blocked_averages, rebalance_domains}; - scheduler_tick -> trigger_load_balance -> {raise_softirq_SCHED_SOFTIRQ, nohz_balancer_kick}; - run_rebalance_domains -> nohz_idle_balance [label="has NOHZ_BALANCE_KICK"]; - run_rebalance_domains -> {/* nohz_idle_balance, */update_blocked_averages, rebalance_domains}; + run_rebalance_domains -> {/* nohz_idle_balance, */update_blocked_averages, rebalance_domains} [style=dashed]; - // KICK - nohz_balancer_kick -> {set_NOHZ_STATS_KICK, set_NOHZ_BALANCE_KICK, set_NOHZ_NEXT_KICK} -> kick_ilb -> find_new_ilb -> KICK_CPU_BY_IPI -> nohz_csd_func -> raise_softirq_SCHED_SOFTIRQ; + subgraph cluster_1 { + label = "触发 NOHZ Load Balance"; + color=red; - // NOHZ 负载均衡器 nohz_idle_balance - nohz_idle_balance -> {clear_nohz_idle_balance, _nohz_idle_balance}; - /* - _nohz_idle_balance -> for_each_nohz_idle_cpus_mask -> {has_NOHZ_STATS_KICK, has_NOHZ_BALANCE_KICK}; - has_NOHZ_STATS_KICK -> update_nohz_stats -> update_blocked_averages; - has_NOHZ_BALANCE_KICK -> rebalance_domains; - */ - _nohz_idle_balance -> for_each_nohz_idle_cpus_mask; - for_each_nohz_idle_cpus_mask -> update_nohz_stats -> update_blocked_averages [label="has NOHZ_STATS_KICK"]; - for_each_nohz_idle_cpus_mask -> rebalance_domains [label="has NOHZ_BALANCE_KICK"]; + // KICK + scheduler_tick -> trigger_load_balance -> nohz_balancer_kick; + trigger_load_balance -> raise_softirq_SCHED_SOFTIRQ [style=dashed]; + nohz_balancer_kick -> {set_NOHZ_STATS_KICK, set_NOHZ_BALANCE_KICK, set_NOHZ_NEXT_KICK} -> kick_ilb -> find_new_ilb -> KICK_CPU_BY_IPI -> nohz_csd_func -> raise_softirq_SCHED_SOFTIRQ; + }; + + subgraph cluster_2 { + label = "执行 NOHZ Load Balance"; + color=blue; + + raise_softirq_SCHED_SOFTIRQ -> run_rebalance_domains [style=dashed]; + + // NOHZ 负载均衡器 nohz_idle_balance + run_rebalance_domains -> nohz_idle_balance [label="has NOHZ_BALANCE_KICK"]; + nohz_idle_balance -> {clear_nohz_idle_balance, _nohz_idle_balance}; + /* + _nohz_idle_balance -> for_each_nohz_idle_cpus_mask -> {has_NOHZ_STATS_KICK, has_NOHZ_BALANCE_KICK}; + has_NOHZ_STATS_KICK -> update_nohz_stats -> update_blocked_averages; + has_NOHZ_BALANCE_KICK -> rebalance_domains; + */ + _nohz_idle_balance -> for_each_nohz_idle_cpus_mask; + for_each_nohz_idle_cpus_mask -> update_nohz_stats -> update_blocked_averages [label="has NOHZ_STATS_KICK"]; + for_each_nohz_idle_cpus_mask -> rebalance_domains [label="has NOHZ_BALANCE_KICK"]; + }; // IDLE 负载均衡器 newidle_balance -> nohz_newidle_balance; - nohz_newidle_balance -> set_NOHZ_NEWILB_KICK - raise_softirq_SCHED_SOFTIRQ -> run_rebalance_domains [style=dashed]; + raise_softirq_SCHED_SOFTIRQ [label="raise_softirq(SCHED_SOFTIRQ)"; style=filled; shape=oval] clear_nohz_idle_balance [label="this_rq->nohz_idle_balance = 0"; style=filled; shape=oval]; diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/nohz_idle_balance.svg b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/nohz_idle_balance.svg new file mode 100644 index 0000000..8bb856e --- /dev/null +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/nohz_idle_balance.svg @@ -0,0 +1,309 @@ + + + + + + +nohz_idle_balance + + +cluster_1 + +触发 NOHZ Load Balance + + +cluster_2 + +执行 NOHZ Load Balance + + + +run_rebalance_domains + +run_rebalance_domains + + + +update_blocked_averages + +update_blocked_averages + + + +run_rebalance_domains->update_blocked_averages + + + + + +rebalance_domains + +rebalance_domains + + + +run_rebalance_domains->rebalance_domains + + + + + +nohz_idle_balance + +nohz_idle_balance + + + +run_rebalance_domains->nohz_idle_balance + + +has NOHZ_BALANCE_KICK + + + +scheduler_tick + +scheduler_tick + + + +trigger_load_balance + +trigger_load_balance + + + +scheduler_tick->trigger_load_balance + + + + + +nohz_balancer_kick + +nohz_balancer_kick + + + +trigger_load_balance->nohz_balancer_kick + + + + + +raise_softirq_SCHED_SOFTIRQ + +raise_softirq(SCHED_SOFTIRQ) + + + +trigger_load_balance->raise_softirq_SCHED_SOFTIRQ + + + + + +set_NOHZ_STATS_KICK + +set_NOHZ_STATS_KICK + + + +nohz_balancer_kick->set_NOHZ_STATS_KICK + + + + + +set_NOHZ_BALANCE_KICK + +set_NOHZ_BALANCE_KICK + + + +nohz_balancer_kick->set_NOHZ_BALANCE_KICK + + + + + +set_NOHZ_NEXT_KICK + +set_NOHZ_NEXT_KICK + + + +nohz_balancer_kick->set_NOHZ_NEXT_KICK + + + + + +raise_softirq_SCHED_SOFTIRQ->run_rebalance_domains + + + + + +kick_ilb + +kick_ilb + + + +set_NOHZ_STATS_KICK->kick_ilb + + + + + +set_NOHZ_BALANCE_KICK->kick_ilb + + + + + +set_NOHZ_NEXT_KICK->kick_ilb + + + + + +find_new_ilb + +find_new_ilb + + + +kick_ilb->find_new_ilb + + + + + +KICK_CPU_BY_IPI + +smp_call_function_single_async(ilb_cpu, &cpu_rq(ilb_cpu)->nohz_csd) + + + +find_new_ilb->KICK_CPU_BY_IPI + + + + + +nohz_csd_func + +nohz_csd_func + + + +KICK_CPU_BY_IPI->nohz_csd_func + + + + + +nohz_csd_func->raise_softirq_SCHED_SOFTIRQ + + + + + +clear_nohz_idle_balance + +this_rq->nohz_idle_balance = 0 + + + +nohz_idle_balance->clear_nohz_idle_balance + + + + + +_nohz_idle_balance + +_nohz_idle_balance + + + +nohz_idle_balance->_nohz_idle_balance + + + + + +for_each_nohz_idle_cpus_mask + +for_each_nohz_idle_cpus_mask + + + +_nohz_idle_balance->for_each_nohz_idle_cpus_mask + + + + + +for_each_nohz_idle_cpus_mask->rebalance_domains + + +has NOHZ_BALANCE_KICK + + + +update_nohz_stats + +update_nohz_stats + + + +for_each_nohz_idle_cpus_mask->update_nohz_stats + + +has NOHZ_STATS_KICK + + + +update_nohz_stats->update_blocked_averages + + +has NOHZ_STATS_KICK + + + +newidle_balance + +newidle_balance + + + +nohz_newidle_balance + +nohz_newidle_balance + + + +newidle_balance->nohz_newidle_balance + + + + + +set_NOHZ_NEWILB_KICK + +atomic_or(NOHZ_NEWILB_KICK, nohz_flags(this_cpu)) + + + +nohz_newidle_balance->set_NOHZ_NEWILB_KICK + + + + + diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/passive_load_balance.gv b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/passive_load_balance.gv new file mode 100644 index 0000000..2df740d --- /dev/null +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/passive_load_balance.gv @@ -0,0 +1,47 @@ +digraph load_balance { + subgraph cluster_0 { + label = "触发选核(被动负载均衡)"; + color = red; + + wake_up_new_task -> select_task_rq [label="WF_TTWU"]; + sched_exec -> select_task_rq [label="WF_EXEC"]; + try_to_wake_up -> select_task_rq [label="WF_TTWU"]; + select_task_rq -> select_task_rq_fair [style=dashed]; + }; + + select_task_rq_fair -> find_energy_efficient_cpu [label="WF_TTWU && sched_energy_enabled"]; + select_task_rq_fair -> select_idle_sibling [label="want_affine && SD_WAKE_AFFINE && WF_TTWU"]; + select_task_rq_fair -> find_idlest_cpu; + + subgraph cluster_1 { + label = "唤醒路径的能效感知"; + color = blue; + + find_energy_efficient_cpu -> compute_energy; + }; + + subgraph cluster_2 { + label = "慢速路径"; + color = blue; + + find_idlest_cpu -> {find_idlest_group, find_idlest_group_cpu}; + }; + + subgraph cluster_3 { + label = "唤醒快速路径"; + color = blue; + + select_idle_sibling -> {select_idle_capacity, select_idle_smt, select_idle_cpu}; + }; + + wake_up_new_task [label="wake_up_new_task"; style=filled; fillcolor=lightyellow; shape=oval]; + sched_exec [label="sched_exec"; style=filled; fillcolor=lightyellow; shape=oval]; + try_to_wake_up [label="try_to_wake_up"; style=filled; fillcolor=lightyellow; shape=oval]; + + + select_task_rq_fair [label="select_task_rq_fair"; style=filled; fillcolor=palegreen; shape=oval]; + + find_energy_efficient_cpu [label="find_energy_efficient_cpu"; style=filled; fillcolor=lightyellow; shape=oval]; + select_idle_sibling [label="select_idle_sibling"; style=filled; fillcolor=lightyellow; shape=oval]; + find_idlest_cpu [label="find_idlest_cpu"; style=filled; fillcolor=lightyellow; shape=oval]; +} \ No newline at end of file diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/passive_load_balance.svg b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/passive_load_balance.svg new file mode 100644 index 0000000..f8353f7 --- /dev/null +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/passive_load_balance.svg @@ -0,0 +1,200 @@ + + + + + + +load_balance + + +cluster_0 + +触发选核(被动负载均衡) + + +cluster_1 + +唤醒路径的能效感知 + + +cluster_2 + +慢速路径 + + +cluster_3 + +唤醒快速路径 + + + +wake_up_new_task + +wake_up_new_task + + + +select_task_rq + +select_task_rq + + + +wake_up_new_task->select_task_rq + + +WF_TTWU + + + +select_task_rq_fair + +select_task_rq_fair + + + +select_task_rq->select_task_rq_fair + + + + + +sched_exec + +sched_exec + + + +sched_exec->select_task_rq + + +WF_EXEC + + + +try_to_wake_up + +try_to_wake_up + + + +try_to_wake_up->select_task_rq + + +WF_TTWU + + + +find_energy_efficient_cpu + +find_energy_efficient_cpu + + + +select_task_rq_fair->find_energy_efficient_cpu + + +WF_TTWU && sched_energy_enabled + + + +select_idle_sibling + +select_idle_sibling + + + +select_task_rq_fair->select_idle_sibling + + +want_affine && SD_WAKE_AFFINE && WF_TTWU + + + +find_idlest_cpu + +find_idlest_cpu + + + +select_task_rq_fair->find_idlest_cpu + + + + + +compute_energy + +compute_energy + + + +find_energy_efficient_cpu->compute_energy + + + + + +select_idle_capacity + +select_idle_capacity + + + +select_idle_sibling->select_idle_capacity + + + + + +select_idle_smt + +select_idle_smt + + + +select_idle_sibling->select_idle_smt + + + + + +select_idle_cpu + +select_idle_cpu + + + +select_idle_sibling->select_idle_cpu + + + + + +find_idlest_group + +find_idlest_group + + + +find_idlest_cpu->find_idlest_group + + + + + +find_idlest_group_cpu + +find_idlest_group_cpu + + + +find_idlest_cpu->find_idlest_group_cpu + + + + + diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/tick_load_balance.gv b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/tick_load_balance.gv index a3164ac..b890f82 100644 --- a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/tick_load_balance.gv +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/tick_load_balance.gv @@ -1,11 +1,21 @@ digraph rebalance_domains { // 周期性负载均衡器 run_rebalance_domains - scheduler_tick -> trigger_load_balance -> {raise_softirq_SCHED_SOFTIRQ, nohz_balancer_kick}; - raise_softirq_SCHED_SOFTIRQ -> run_rebalance_domains [style=dashed]; - run_rebalance_domains -> {nohz_idle_balance, update_blocked_averages, rebalance_domains}; + subgraph cluster_1 { + label = "触发 Periodic Load Balance"; + color=red; - rebalance_domains -> for_each_domain_LB -> {update_newidle_cost, get_sd_balance_interval, load_balance, update_next_balance}; + scheduler_tick -> trigger_load_balance -> {raise_softirq_SCHED_SOFTIRQ, nohz_balancer_kick}; + raise_softirq_SCHED_SOFTIRQ -> run_rebalance_domains [style=dashed]; + run_rebalance_domains -> {nohz_idle_balance, update_blocked_averages, rebalance_domains}; + }; + + subgraph cluster_2 { + label = "执行 Periodic Load Balance"; + color=blue; + + rebalance_domains -> for_each_domain_LB -> {update_newidle_cost, get_sd_balance_interval, load_balance, update_next_balance}; + }; // caller raise_softirq_SCHED_SOFTIRQ [label="raise_softirq(SCHED_SOFTIRQ)"; style=filled; fillcolor=lightyellow; shape=oval]; diff --git a/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/tick_load_balance.svg b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/tick_load_balance.svg new file mode 100644 index 0000000..0e08fbc --- /dev/null +++ b/study/kernel/01-process/05-schedule/07-cfs/10-load_balance/tick_load_balance.svg @@ -0,0 +1,173 @@ + + + + + + +rebalance_domains + + +cluster_1 + +触发 Periodic Load Balance + + +cluster_2 + +执行 Periodic Load Balance + + + +scheduler_tick + +scheduler_tick + + + +trigger_load_balance + +trigger_load_balance + + + +scheduler_tick->trigger_load_balance + + + + + +raise_softirq_SCHED_SOFTIRQ + +raise_softirq(SCHED_SOFTIRQ) + + + +trigger_load_balance->raise_softirq_SCHED_SOFTIRQ + + + + + +nohz_balancer_kick + +nohz_balancer_kick + + + +trigger_load_balance->nohz_balancer_kick + + + + + +run_rebalance_domains + +run_rebalance_domains + + + +raise_softirq_SCHED_SOFTIRQ->run_rebalance_domains + + + + + +nohz_idle_balance + +nohz_idle_balance + + + +run_rebalance_domains->nohz_idle_balance + + + + + +update_blocked_averages + +update_blocked_averages + + + +run_rebalance_domains->update_blocked_averages + + + + + +rebalance_domains + +rebalance_domains + + + +run_rebalance_domains->rebalance_domains + + + + + +for_each_domain_LB + +for_each_domain_LB + + + +rebalance_domains->for_each_domain_LB + + + + + +update_newidle_cost + +update_newidle_cost + + + +for_each_domain_LB->update_newidle_cost + + + + + +get_sd_balance_interval + +get_sd_balance_interval + + + +for_each_domain_LB->get_sd_balance_interval + + + + + +load_balance + +load_balance + + + +for_each_domain_LB->load_balance + + + + + +update_next_balance + +update_next_balance + + + +for_each_domain_LB->update_next_balance + + + + +