Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sched/topology: Remove the EM_MAX_COMPLEXITY limit

The Energy Aware Scheduler (EAS) estimates the energy consumption
of placing a task on different CPUs. The goal is to minimize this
energy consumption. Estimating the energy of different task placements
is increasingly complex with the size of the platform.

To avoid having a slow wake-up path, EAS is only enabled if this
complexity is low enough.

The current complexity limit was set in:

b68a4c0dba3b1 ("sched/topology: Disable EAS on inappropriate platforms")

... based on the first implementation of EAS, which was re-computing
the power of the whole platform for each task placement scenario, see:

390031e4c309 ("sched/fair: Introduce an energy estimation helper function")

... but the complexity of EAS was reduced in:

eb92692b2544d ("sched/fair: Speed-up energy-aware wake-ups")

... and find_energy_efficient_cpu() (feec) algorithm was updated in:

3e8c6c9aac42 ("sched/fair: Remove task_util from effective utilization in feec()")

find_energy_efficient_cpu() (feec) is now doing:

feec()
\_ for_each_pd(pd) [0]
// get max_spare_cap_cpu and compute_prev_delta
\_ for_each_cpu(pd) [1]

\_ eenv_pd_busy_time(pd) [2]
\_ for_each_cpu(pd)

// compute_energy(pd) without the task
\_ eenv_pd_max_util(pd, -1) [3.0]
\_ for_each_cpu(pd)
\_ em_cpu_energy(pd, -1)
\_ for_each_ps(pd)

// compute_energy(pd) with the task on prev_cpu
\_ eenv_pd_max_util(pd, prev_cpu) [3.1]
\_ for_each_cpu(pd)
\_ em_cpu_energy(pd, prev_cpu)
\_ for_each_ps(pd)

// compute_energy(pd) with the task on max_spare_cap_cpu
\_ eenv_pd_max_util(pd, max_spare_cap_cpu) [3.2]
\_ for_each_cpu(pd)
\_ em_cpu_energy(pd, max_spare_cap_cpu)
\_ for_each_ps(pd)

[3.1] happens only once since prev_cpu is unique. With the same
definitions for nr_pd, nr_cpus and nr_ps, the complexity is of:

nr_pd * (2 * [nr_cpus in pd] + 2 * ([nr_cpus in pd] + [nr_ps in pd]))
+ ([nr_cpus in pd] + [nr_ps in pd])

[0] * ( [1] + [2] + [3.0] + [3.2] )
+ [3.1]

= nr_pd * (4 * [nr_cpus in pd] + 2 * [nr_ps in pd])
+ [nr_cpus in prev pd] + nr_ps

The complexity limit was set to 2048 in:

b68a4c0dba3b1 ("sched/topology: Disable EAS on inappropriate platforms")

... to make "EAS usable up to 16 CPUs with per-CPU DVFS and less than 8
performance states each". For the same platform, the complexity would
actually be of:

16 * (4 + 2 * 7) + 1 + 7 = 296

Since the EAS complexity was greatly reduced since the limit was
introduced, bigger platforms can handle EAS.

For instance, a platform with 112 CPUs with 7 performance states
each would not reach it:

112 * (4 + 2 * 7) + 1 + 7 = 2024

To reflect this improvement in the underlying EAS code, remove
the EAS complexity check.

Note that a limit on the number of CPUs still holds against
EM_MAX_NUM_CPUS to avoid overflows during the energy estimation.

[ mingo: Updates to the changelog. ]

Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
Reviewed-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
Link: https://lore.kernel.org/r/20231009060037.170765-2-sshegde@linux.vnet.ibm.com

authored by

Pierre Gondois and committed by
Ingo Molnar
5b77261c 7bc26384

+6 -62
+3 -26
Documentation/scheduler/sched-energy.rst
··· 359 359 6.3 - Energy Model complexity 360 360 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 361 361 362 - The task wake-up path is very latency-sensitive. When the EM of a platform is 363 - too complex (too many CPUs, too many performance domains, too many performance 364 - states, ...), the cost of using it in the wake-up path can become prohibitive. 365 - The energy-aware wake-up algorithm has a complexity of: 366 - 367 - C = Nd * (Nc + Ns) 368 - 369 - with: Nd the number of performance domains; Nc the number of CPUs; and Ns the 370 - total number of OPPs (ex: for two perf. domains with 4 OPPs each, Ns = 8). 371 - 372 - A complexity check is performed at the root domain level, when scheduling 373 - domains are built. EAS will not start on a root domain if its C happens to be 374 - higher than the completely arbitrary EM_MAX_COMPLEXITY threshold (2048 at the 375 - time of writing). 376 - 377 - If you really want to use EAS but the complexity of your platform's Energy 378 - Model is too high to be used with a single root domain, you're left with only 379 - two possible options: 380 - 381 - 1. split your system into separate, smaller, root domains using exclusive 382 - cpusets and enable EAS locally on each of them. This option has the 383 - benefit to work out of the box but the drawback of preventing load 384 - balance between root domains, which can result in an unbalanced system 385 - overall; 386 - 2. submit patches to reduce the complexity of the EAS wake-up algorithm, 387 - hence enabling it to cope with larger EMs in reasonable time. 362 + EAS does not impose any complexity limit on the number of PDs/OPPs/CPUs but 363 + restricts the number of CPUs to EM_MAX_NUM_CPUS to prevent overflows during 364 + the energy estimation. 388 365 389 366 390 367 6.4 - Schedutil governor
+3 -36
kernel/sched/topology.c
··· 348 348 * 1. an Energy Model (EM) is available; 349 349 * 2. the SD_ASYM_CPUCAPACITY flag is set in the sched_domain hierarchy. 350 350 * 3. no SMT is detected. 351 - * 4. the EM complexity is low enough to keep scheduling overheads low; 352 - * 5. schedutil is driving the frequency of all CPUs of the rd; 353 - * 6. frequency invariance support is present; 354 - * 355 - * The complexity of the Energy Model is defined as: 356 - * 357 - * C = nr_pd * (nr_cpus + nr_ps) 358 - * 359 - * with parameters defined as: 360 - * - nr_pd: the number of performance domains 361 - * - nr_cpus: the number of CPUs 362 - * - nr_ps: the sum of the number of performance states of all performance 363 - * domains (for example, on a system with 2 performance domains, 364 - * with 10 performance states each, nr_ps = 2 * 10 = 20). 365 - * 366 - * It is generally not a good idea to use such a model in the wake-up path on 367 - * very complex platforms because of the associated scheduling overheads. The 368 - * arbitrary constraint below prevents that. It makes EAS usable up to 16 CPUs 369 - * with per-CPU DVFS and less than 8 performance states each, for example. 351 + * 4. schedutil is driving the frequency of all CPUs of the rd; 352 + * 5. frequency invariance support is present; 370 353 */ 371 - #define EM_MAX_COMPLEXITY 2048 372 - 373 354 extern struct cpufreq_governor schedutil_gov; 374 355 static bool build_perf_domains(const struct cpumask *cpu_map) 375 356 { 376 - int i, nr_pd = 0, nr_ps = 0, nr_cpus = cpumask_weight(cpu_map); 357 + int i; 377 358 struct perf_domain *pd = NULL, *tmp; 378 359 int cpu = cpumask_first(cpu_map); 379 360 struct root_domain *rd = cpu_rq(cpu)->rd; ··· 412 431 goto free; 413 432 tmp->next = pd; 414 433 pd = tmp; 415 - 416 - /* 417 - * Count performance domains and performance states for the 418 - * complexity check. 419 - */ 420 - nr_pd++; 421 - nr_ps += em_pd_nr_perf_states(pd->em_pd); 422 - } 423 - 424 - /* Bail out if the Energy Model complexity is too high. */ 425 - if (nr_pd * (nr_ps + nr_cpus) > EM_MAX_COMPLEXITY) { 426 - WARN(1, "rd %*pbl: Failed to start EAS, EM complexity is too high\n", 427 - cpumask_pr_args(cpu_map)); 428 - goto free; 429 434 } 430 435 431 436 perf_domain_debug(cpu_map, pd);