aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Fernandes <joelaf@google.com>2017-07-23 11:54:25 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-07-26 16:52:13 -0400
commita5a0809bc58e133d674e45175b052c9bdf002f1d (patch)
treefd192920b77bcc95f5aa4be534508b4cf2c339c6
parent520eccdfe187591a51ea9ab4c1a024ae4d0f68d9 (diff)
cpufreq: schedutil: Make iowait boost more energy efficient
Currently the iowait_boost feature in schedutil makes the frequency go to max on iowait wakeups. This feature was added to handle a case that Peter described where the throughput of operations involving continuous I/O requests [1] is reduced due to running at a lower frequency, however the lower throughput itself causes utilization to be low and hence causing frequency to be low hence its "stuck". Instead of going to max, its also possible to achieve the same effect by ramping up to max if there are repeated in_iowait wakeups happening. This patch is an attempt to do that. We start from a lower frequency (policy->min) and double the boost for every consecutive iowait update until we reach the maximum iowait boost frequency (iowait_boost_max). I ran a synthetic test (continuous O_DIRECT writes in a loop) on an x86 machine with intel_pstate in passive mode using schedutil. In this test the iowait_boost value ramped from 800MHz to 4GHz in 60ms. The patch achieves the desired improved throughput as the existing behavior. [1] https://patchwork.kernel.org/patch/9735885/ Suggested-by: Peter Zijlstra <peterz@infradead.org> Suggested-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Joel Fernandes <joelaf@google.com> Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--kernel/sched/cpufreq_schedutil.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 29a397067ffa..148844a995a8 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -53,6 +53,7 @@ struct sugov_cpu {
53 struct update_util_data update_util; 53 struct update_util_data update_util;
54 struct sugov_policy *sg_policy; 54 struct sugov_policy *sg_policy;
55 55
56 bool iowait_boost_pending;
56 unsigned long iowait_boost; 57 unsigned long iowait_boost;
57 unsigned long iowait_boost_max; 58 unsigned long iowait_boost_max;
58 u64 last_update; 59 u64 last_update;
@@ -169,30 +170,54 @@ static void sugov_set_iowait_boost(struct sugov_cpu *sg_cpu, u64 time,
169 unsigned int flags) 170 unsigned int flags)
170{ 171{
171 if (flags & SCHED_CPUFREQ_IOWAIT) { 172 if (flags & SCHED_CPUFREQ_IOWAIT) {
172 sg_cpu->iowait_boost = sg_cpu->iowait_boost_max; 173 if (sg_cpu->iowait_boost_pending)
174 return;
175
176 sg_cpu->iowait_boost_pending = true;
177
178 if (sg_cpu->iowait_boost) {
179 sg_cpu->iowait_boost <<= 1;
180 if (sg_cpu->iowait_boost > sg_cpu->iowait_boost_max)
181 sg_cpu->iowait_boost = sg_cpu->iowait_boost_max;
182 } else {
183 sg_cpu->iowait_boost = sg_cpu->sg_policy->policy->min;
184 }
173 } else if (sg_cpu->iowait_boost) { 185 } else if (sg_cpu->iowait_boost) {
174 s64 delta_ns = time - sg_cpu->last_update; 186 s64 delta_ns = time - sg_cpu->last_update;
175 187
176 /* Clear iowait_boost if the CPU apprears to have been idle. */ 188 /* Clear iowait_boost if the CPU apprears to have been idle. */
177 if (delta_ns > TICK_NSEC) 189 if (delta_ns > TICK_NSEC) {
178 sg_cpu->iowait_boost = 0; 190 sg_cpu->iowait_boost = 0;
191 sg_cpu->iowait_boost_pending = false;
192 }
179 } 193 }
180} 194}
181 195
182static void sugov_iowait_boost(struct sugov_cpu *sg_cpu, unsigned long *util, 196static void sugov_iowait_boost(struct sugov_cpu *sg_cpu, unsigned long *util,
183 unsigned long *max) 197 unsigned long *max)
184{ 198{
185 unsigned long boost_util = sg_cpu->iowait_boost; 199 unsigned long boost_util, boost_max;
186 unsigned long boost_max = sg_cpu->iowait_boost_max;
187 200
188 if (!boost_util) 201 if (!sg_cpu->iowait_boost)
189 return; 202 return;
190 203
204 if (sg_cpu->iowait_boost_pending) {
205 sg_cpu->iowait_boost_pending = false;
206 } else {
207 sg_cpu->iowait_boost >>= 1;
208 if (sg_cpu->iowait_boost < sg_cpu->sg_policy->policy->min) {
209 sg_cpu->iowait_boost = 0;
210 return;
211 }
212 }
213
214 boost_util = sg_cpu->iowait_boost;
215 boost_max = sg_cpu->iowait_boost_max;
216
191 if (*util * boost_max < *max * boost_util) { 217 if (*util * boost_max < *max * boost_util) {
192 *util = boost_util; 218 *util = boost_util;
193 *max = boost_max; 219 *max = boost_max;
194 } 220 }
195 sg_cpu->iowait_boost >>= 1;
196} 221}
197 222
198#ifdef CONFIG_NO_HZ_COMMON 223#ifdef CONFIG_NO_HZ_COMMON
@@ -264,6 +289,7 @@ static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, u64 time)
264 delta_ns = time - j_sg_cpu->last_update; 289 delta_ns = time - j_sg_cpu->last_update;
265 if (delta_ns > TICK_NSEC) { 290 if (delta_ns > TICK_NSEC) {
266 j_sg_cpu->iowait_boost = 0; 291 j_sg_cpu->iowait_boost = 0;
292 j_sg_cpu->iowait_boost_pending = false;
267 continue; 293 continue;
268 } 294 }
269 if (j_sg_cpu->flags & SCHED_CPUFREQ_RT_DL) 295 if (j_sg_cpu->flags & SCHED_CPUFREQ_RT_DL)