Skip to content

Commit af24bde

Browse files
derklingIngo Molnar
authored andcommitted
sched/uclamp: Add uclamp support to energy_compute()
The Energy Aware Scheduler (EAS) estimates the energy impact of waking up a task on a given CPU. This estimation is based on: a) an (active) power consumption defined for each CPU frequency b) an estimation of which frequency will be used on each CPU c) an estimation of the busy time (utilization) of each CPU Utilization clamping can affect both b) and c). A CPU is expected to run: - on an higher than required frequency, but for a shorter time, in case its estimated utilization will be smaller than the minimum utilization enforced by uclamp - on a smaller than required frequency, but for a longer time, in case its estimated utilization is bigger than the maximum utilization enforced by uclamp While compute_energy() already accounts clamping effects on busy time, the clamping effects on frequency selection are currently ignored. Fix it by considering how CPU clamp values will be affected by a task waking up and being RUNNABLE on that CPU. Do that by refactoring schedutil_freq_util() to take an additional task_struct* which allows EAS to evaluate the impact on clamp values of a task being eventually queued in a CPU. Clamp values are applied to the RT+CFS utilization only when a FREQUENCY_UTIL is required by compute_energy(). Do note that switching from ENERGY_UTIL to FREQUENCY_UTIL in the computation of the cpu_util signal implies that we are more likely to estimate the highest OPP when a RT task is running in another CPU of the same performance domain. This can have an impact on energy estimation but: - it's not easy to say which approach is better, since it depends on the use case - the original approach could still be obtained by setting a smaller task-specific util_min whenever required Since we are at that: - rename schedutil_freq_util() into schedutil_cpu_util(), since it's not only used for frequency selection. Signed-off-by: Patrick Bellasi <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Cc: Alessio Balsini <[email protected]> Cc: Dietmar Eggemann <[email protected]> Cc: Joel Fernandes <[email protected]> Cc: Juri Lelli <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Morten Rasmussen <[email protected]> Cc: Paul Turner <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Quentin Perret <[email protected]> Cc: Rafael J . Wysocki <[email protected]> Cc: Steve Muckle <[email protected]> Cc: Suren Baghdasaryan <[email protected]> Cc: Tejun Heo <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Todd Kjos <[email protected]> Cc: Vincent Guittot <[email protected]> Cc: Viresh Kumar <[email protected]> Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 9d20ad7 commit af24bde

File tree

3 files changed

+48
-22
lines changed

3 files changed

+48
-22
lines changed

kernel/sched/cpufreq_schedutil.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,9 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy,
196196
* based on the task model parameters and gives the minimal utilization
197197
* required to meet deadlines.
198198
*/
199-
unsigned long schedutil_freq_util(int cpu, unsigned long util_cfs,
200-
unsigned long max, enum schedutil_type type)
199+
unsigned long schedutil_cpu_util(int cpu, unsigned long util_cfs,
200+
unsigned long max, enum schedutil_type type,
201+
struct task_struct *p)
201202
{
202203
unsigned long dl_util, util, irq;
203204
struct rq *rq = cpu_rq(cpu);
@@ -230,7 +231,7 @@ unsigned long schedutil_freq_util(int cpu, unsigned long util_cfs,
230231
*/
231232
util = util_cfs + cpu_util_rt(rq);
232233
if (type == FREQUENCY_UTIL)
233-
util = uclamp_util(rq, util);
234+
util = uclamp_util_with(rq, util, p);
234235

235236
dl_util = cpu_util_dl(rq);
236237

@@ -290,7 +291,7 @@ static unsigned long sugov_get_util(struct sugov_cpu *sg_cpu)
290291
sg_cpu->max = max;
291292
sg_cpu->bw_dl = cpu_bw_dl(rq);
292293

293-
return schedutil_freq_util(sg_cpu->cpu, util, max, FREQUENCY_UTIL);
294+
return schedutil_cpu_util(sg_cpu->cpu, util, max, FREQUENCY_UTIL, NULL);
294295
}
295296

296297
/**

kernel/sched/fair.c

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6231,11 +6231,21 @@ static unsigned long cpu_util_next(int cpu, struct task_struct *p, int dst_cpu)
62316231
static long
62326232
compute_energy(struct task_struct *p, int dst_cpu, struct perf_domain *pd)
62336233
{
6234-
long util, max_util, sum_util, energy = 0;
6234+
unsigned int max_util, util_cfs, cpu_util, cpu_cap;
6235+
unsigned long sum_util, energy = 0;
6236+
struct task_struct *tsk;
62356237
int cpu;
62366238

62376239
for (; pd; pd = pd->next) {
6240+
struct cpumask *pd_mask = perf_domain_span(pd);
6241+
6242+
/*
6243+
* The energy model mandates all the CPUs of a performance
6244+
* domain have the same capacity.
6245+
*/
6246+
cpu_cap = arch_scale_cpu_capacity(cpumask_first(pd_mask));
62386247
max_util = sum_util = 0;
6248+
62396249
/*
62406250
* The capacity state of CPUs of the current rd can be driven by
62416251
* CPUs of another rd if they belong to the same performance
@@ -6246,11 +6256,29 @@ compute_energy(struct task_struct *p, int dst_cpu, struct perf_domain *pd)
62466256
* it will not appear in its pd list and will not be accounted
62476257
* by compute_energy().
62486258
*/
6249-
for_each_cpu_and(cpu, perf_domain_span(pd), cpu_online_mask) {
6250-
util = cpu_util_next(cpu, p, dst_cpu);
6251-
util = schedutil_energy_util(cpu, util);
6252-
max_util = max(util, max_util);
6253-
sum_util += util;
6259+
for_each_cpu_and(cpu, pd_mask, cpu_online_mask) {
6260+
util_cfs = cpu_util_next(cpu, p, dst_cpu);
6261+
6262+
/*
6263+
* Busy time computation: utilization clamping is not
6264+
* required since the ratio (sum_util / cpu_capacity)
6265+
* is already enough to scale the EM reported power
6266+
* consumption at the (eventually clamped) cpu_capacity.
6267+
*/
6268+
sum_util += schedutil_cpu_util(cpu, util_cfs, cpu_cap,
6269+
ENERGY_UTIL, NULL);
6270+
6271+
/*
6272+
* Performance domain frequency: utilization clamping
6273+
* must be considered since it affects the selection
6274+
* of the performance domain frequency.
6275+
* NOTE: in case RT tasks are running, by default the
6276+
* FREQUENCY_UTIL's utilization can be max OPP.
6277+
*/
6278+
tsk = cpu == dst_cpu ? p : NULL;
6279+
cpu_util = schedutil_cpu_util(cpu, util_cfs, cpu_cap,
6280+
FREQUENCY_UTIL, tsk);
6281+
max_util = max(max_util, cpu_util);
62546282
}
62556283

62566284
energy += em_pd_energy(pd->em_pd, max_util, sum_util);

kernel/sched/sched.h

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2322,7 +2322,6 @@ static inline unsigned long capacity_orig_of(int cpu)
23222322
}
23232323
#endif
23242324

2325-
#ifdef CONFIG_CPU_FREQ_GOV_SCHEDUTIL
23262325
/**
23272326
* enum schedutil_type - CPU utilization type
23282327
* @FREQUENCY_UTIL: Utilization used to select frequency
@@ -2338,15 +2337,11 @@ enum schedutil_type {
23382337
ENERGY_UTIL,
23392338
};
23402339

2341-
unsigned long schedutil_freq_util(int cpu, unsigned long util_cfs,
2342-
unsigned long max, enum schedutil_type type);
2340+
#ifdef CONFIG_CPU_FREQ_GOV_SCHEDUTIL
23432341

2344-
static inline unsigned long schedutil_energy_util(int cpu, unsigned long cfs)
2345-
{
2346-
unsigned long max = arch_scale_cpu_capacity(cpu);
2347-
2348-
return schedutil_freq_util(cpu, cfs, max, ENERGY_UTIL);
2349-
}
2342+
unsigned long schedutil_cpu_util(int cpu, unsigned long util_cfs,
2343+
unsigned long max, enum schedutil_type type,
2344+
struct task_struct *p);
23502345

23512346
static inline unsigned long cpu_bw_dl(struct rq *rq)
23522347
{
@@ -2375,11 +2370,13 @@ static inline unsigned long cpu_util_rt(struct rq *rq)
23752370
return READ_ONCE(rq->avg_rt.util_avg);
23762371
}
23772372
#else /* CONFIG_CPU_FREQ_GOV_SCHEDUTIL */
2378-
static inline unsigned long schedutil_energy_util(int cpu, unsigned long cfs)
2373+
static inline unsigned long schedutil_cpu_util(int cpu, unsigned long util_cfs,
2374+
unsigned long max, enum schedutil_type type,
2375+
struct task_struct *p)
23792376
{
2380-
return cfs;
2377+
return 0;
23812378
}
2382-
#endif
2379+
#endif /* CONFIG_CPU_FREQ_GOV_SCHEDUTIL */
23832380

23842381
#ifdef CONFIG_HAVE_SCHED_AVG_IRQ
23852382
static inline unsigned long cpu_util_irq(struct rq *rq)

0 commit comments

Comments
 (0)