diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/sched/cpufreq_schedutil.c | 53 | ||||
| -rw-r--r-- | kernel/sched/sched.h | 30 |
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 | ||
| 18 | struct sugov_tunables { | 19 | struct 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 | */ |
| 200 | static unsigned long sugov_get_util(struct sugov_cpu *sg_cpu) | 201 | unsigned 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 | |||
| 277 | static 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 | */ | ||
| 2204 | enum schedutil_type { | ||
| 2205 | FREQUENCY_UTIL, | ||
| 2206 | ENERGY_UTIL, | ||
| 2207 | }; | ||
| 2208 | |||
| 2209 | unsigned long schedutil_freq_util(int cpu, unsigned long util_cfs, | ||
| 2210 | unsigned long max, enum schedutil_type type); | ||
| 2211 | |||
| 2212 | static 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 | |||
| 2194 | static inline unsigned long cpu_bw_dl(struct rq *rq) | 2219 | static 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 */ | ||
| 2246 | static 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 |
