summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sched/cpufreq_schedutil.c53
-rw-r--r--kernel/sched/sched.h30
2 files changed, 68 insertions, 15 deletions
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 3fffad3bc8a8..90128be27712 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -13,6 +13,7 @@
13 13
14#include "sched.h" 14#include "sched.h"
15 15
16#include <linux/sched/cpufreq.h>
16#include <trace/events/power.h> 17#include <trace/events/power.h>
17 18
18struct sugov_tunables { 19struct sugov_tunables {
@@ -167,7 +168,7 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy,
167 unsigned int freq = arch_scale_freq_invariant() ? 168 unsigned int freq = arch_scale_freq_invariant() ?
168 policy->cpuinfo.max_freq : policy->cur; 169 policy->cpuinfo.max_freq : policy->cur;
169 170
170 freq = (freq + (freq >> 2)) * util / max; 171 freq = map_util_freq(util, freq, max);
171 172
172 if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update) 173 if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update)
173 return sg_policy->next_freq; 174 return sg_policy->next_freq;
@@ -197,15 +198,13 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy,
197 * based on the task model parameters and gives the minimal utilization 198 * based on the task model parameters and gives the minimal utilization
198 * required to meet deadlines. 199 * required to meet deadlines.
199 */ 200 */
200static unsigned long sugov_get_util(struct sugov_cpu *sg_cpu) 201unsigned long schedutil_freq_util(int cpu, unsigned long util_cfs,
202 unsigned long max, enum schedutil_type type)
201{ 203{
202 struct rq *rq = cpu_rq(sg_cpu->cpu); 204 unsigned long dl_util, util, irq;
203 unsigned long util, irq, max; 205 struct rq *rq = cpu_rq(cpu);
204 206
205 sg_cpu->max = max = arch_scale_cpu_capacity(NULL, sg_cpu->cpu); 207 if (type == FREQUENCY_UTIL && rt_rq_is_runnable(&rq->rt))
206 sg_cpu->bw_dl = cpu_bw_dl(rq);
207
208 if (rt_rq_is_runnable(&rq->rt))
209 return max; 208 return max;
210 209
211 /* 210 /*
@@ -223,22 +222,31 @@ static unsigned long sugov_get_util(struct sugov_cpu *sg_cpu)
223 * utilization (PELT windows are synchronized) we can directly add them 222 * utilization (PELT windows are synchronized) we can directly add them
224 * to obtain the CPU's actual utilization. 223 * to obtain the CPU's actual utilization.
225 */ 224 */
226 util = cpu_util_cfs(rq); 225 util = util_cfs;
227 util += cpu_util_rt(rq); 226 util += cpu_util_rt(rq);
228 227
228 dl_util = cpu_util_dl(rq);
229
229 /* 230 /*
230 * We do not make cpu_util_dl() a permanent part of this sum because we 231 * For frequency selection we do not make cpu_util_dl() a permanent part
231 * want to use cpu_bw_dl() later on, but we need to check if the 232 * of this sum because we want to use cpu_bw_dl() later on, but we need
232 * CFS+RT+DL sum is saturated (ie. no idle time) such that we select 233 * to check if the CFS+RT+DL sum is saturated (ie. no idle time) such
233 * f_max when there is no idle time. 234 * that we select f_max when there is no idle time.
234 * 235 *
235 * NOTE: numerical errors or stop class might cause us to not quite hit 236 * NOTE: numerical errors or stop class might cause us to not quite hit
236 * saturation when we should -- something for later. 237 * saturation when we should -- something for later.
237 */ 238 */
238 if ((util + cpu_util_dl(rq)) >= max) 239 if (util + dl_util >= max)
239 return max; 240 return max;
240 241
241 /* 242 /*
243 * OTOH, for energy computation we need the estimated running time, so
244 * include util_dl and ignore dl_bw.
245 */
246 if (type == ENERGY_UTIL)
247 util += dl_util;
248
249 /*
242 * There is still idle time; further improve the number by using the 250 * There is still idle time; further improve the number by using the
243 * irq metric. Because IRQ/steal time is hidden from the task clock we 251 * irq metric. Because IRQ/steal time is hidden from the task clock we
244 * need to scale the task numbers: 252 * need to scale the task numbers:
@@ -260,7 +268,22 @@ static unsigned long sugov_get_util(struct sugov_cpu *sg_cpu)
260 * bw_dl as requested freq. However, cpufreq is not yet ready for such 268 * bw_dl as requested freq. However, cpufreq is not yet ready for such
261 * an interface. So, we only do the latter for now. 269 * an interface. So, we only do the latter for now.
262 */ 270 */
263 return min(max, util + sg_cpu->bw_dl); 271 if (type == FREQUENCY_UTIL)
272 util += cpu_bw_dl(rq);
273
274 return min(max, util);
275}
276
277static unsigned long sugov_get_util(struct sugov_cpu *sg_cpu)
278{
279 struct rq *rq = cpu_rq(sg_cpu->cpu);
280 unsigned long util = cpu_util_cfs(rq);
281 unsigned long max = arch_scale_cpu_capacity(NULL, sg_cpu->cpu);
282
283 sg_cpu->max = max;
284 sg_cpu->bw_dl = cpu_bw_dl(rq);
285
286 return schedutil_freq_util(sg_cpu->cpu, util, max, FREQUENCY_UTIL);
264} 287}
265 288
266/** 289/**
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 66067152a831..2eafa228aebf 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -2191,6 +2191,31 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {}
2191#endif 2191#endif
2192 2192
2193#ifdef CONFIG_CPU_FREQ_GOV_SCHEDUTIL 2193#ifdef CONFIG_CPU_FREQ_GOV_SCHEDUTIL
2194/**
2195 * enum schedutil_type - CPU utilization type
2196 * @FREQUENCY_UTIL: Utilization used to select frequency
2197 * @ENERGY_UTIL: Utilization used during energy calculation
2198 *
2199 * The utilization signals of all scheduling classes (CFS/RT/DL) and IRQ time
2200 * need to be aggregated differently depending on the usage made of them. This
2201 * enum is used within schedutil_freq_util() to differentiate the types of
2202 * utilization expected by the callers, and adjust the aggregation accordingly.
2203 */
2204enum schedutil_type {
2205 FREQUENCY_UTIL,
2206 ENERGY_UTIL,
2207};
2208
2209unsigned long schedutil_freq_util(int cpu, unsigned long util_cfs,
2210 unsigned long max, enum schedutil_type type);
2211
2212static inline unsigned long schedutil_energy_util(int cpu, unsigned long cfs)
2213{
2214 unsigned long max = arch_scale_cpu_capacity(NULL, cpu);
2215
2216 return schedutil_freq_util(cpu, cfs, max, ENERGY_UTIL);
2217}
2218
2194static inline unsigned long cpu_bw_dl(struct rq *rq) 2219static inline unsigned long cpu_bw_dl(struct rq *rq)
2195{ 2220{
2196 return (rq->dl.running_bw * SCHED_CAPACITY_SCALE) >> BW_SHIFT; 2221 return (rq->dl.running_bw * SCHED_CAPACITY_SCALE) >> BW_SHIFT;
@@ -2217,6 +2242,11 @@ static inline unsigned long cpu_util_rt(struct rq *rq)
2217{ 2242{
2218 return READ_ONCE(rq->avg_rt.util_avg); 2243 return READ_ONCE(rq->avg_rt.util_avg);
2219} 2244}
2245#else /* CONFIG_CPU_FREQ_GOV_SCHEDUTIL */
2246static inline unsigned long schedutil_energy_util(int cpu, unsigned long cfs)
2247{
2248 return cfs;
2249}
2220#endif 2250#endif
2221 2251
2222#ifdef CONFIG_HAVE_SCHED_AVG_IRQ 2252#ifdef CONFIG_HAVE_SCHED_AVG_IRQ