aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/cpuidle/governors/menu.c73
-rw-r--r--include/linux/tick.h6
-rw-r--r--kernel/time/tick-sched.c9
3 files changed, 6 insertions, 82 deletions
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index b69a87e22155..bc580b67a652 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -28,13 +28,6 @@
28#define MAX_INTERESTING 50000 28#define MAX_INTERESTING 50000
29#define STDDEV_THRESH 400 29#define STDDEV_THRESH 400
30 30
31/* 60 * 60 > STDDEV_THRESH * INTERVALS = 400 * 8 */
32#define MAX_DEVIATION 60
33
34static DEFINE_PER_CPU(struct hrtimer, menu_hrtimer);
35static DEFINE_PER_CPU(int, hrtimer_status);
36/* menu hrtimer mode */
37enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT};
38 31
39/* 32/*
40 * Concepts and ideas behind the menu governor 33 * Concepts and ideas behind the menu governor
@@ -198,42 +191,17 @@ static u64 div_round64(u64 dividend, u32 divisor)
198 return div_u64(dividend + (divisor / 2), divisor); 191 return div_u64(dividend + (divisor / 2), divisor);
199} 192}
200 193
201/* Cancel the hrtimer if it is not triggered yet */
202void menu_hrtimer_cancel(void)
203{
204 int cpu = smp_processor_id();
205 struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
206
207 /* The timer is still not time out*/
208 if (per_cpu(hrtimer_status, cpu)) {
209 hrtimer_cancel(hrtmr);
210 per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
211 }
212}
213EXPORT_SYMBOL_GPL(menu_hrtimer_cancel);
214
215/* Call back for hrtimer is triggered */
216static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer)
217{
218 int cpu = smp_processor_id();
219
220 per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
221
222 return HRTIMER_NORESTART;
223}
224
225/* 194/*
226 * Try detecting repeating patterns by keeping track of the last 8 195 * Try detecting repeating patterns by keeping track of the last 8
227 * intervals, and checking if the standard deviation of that set 196 * intervals, and checking if the standard deviation of that set
228 * of points is below a threshold. If it is... then use the 197 * of points is below a threshold. If it is... then use the
229 * average of these 8 points as the estimated value. 198 * average of these 8 points as the estimated value.
230 */ 199 */
231static u32 get_typical_interval(struct menu_device *data) 200static void get_typical_interval(struct menu_device *data)
232{ 201{
233 int i = 0, divisor = 0; 202 int i = 0, divisor = 0;
234 uint64_t max = 0, avg = 0, stddev = 0; 203 uint64_t max = 0, avg = 0, stddev = 0;
235 int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */ 204 int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */
236 unsigned int ret = 0;
237 205
238again: 206again:
239 207
@@ -274,16 +242,13 @@ again:
274 if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3)) 242 if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
275 || stddev <= 20) { 243 || stddev <= 20) {
276 data->predicted_us = avg; 244 data->predicted_us = avg;
277 ret = 1; 245 return;
278 return ret;
279 246
280 } else if ((divisor * 4) > INTERVALS * 3) { 247 } else if ((divisor * 4) > INTERVALS * 3) {
281 /* Exclude the max interval */ 248 /* Exclude the max interval */
282 thresh = max - 1; 249 thresh = max - 1;
283 goto again; 250 goto again;
284 } 251 }
285
286 return ret;
287} 252}
288 253
289/** 254/**
@@ -298,9 +263,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
298 int i; 263 int i;
299 int multiplier; 264 int multiplier;
300 struct timespec t; 265 struct timespec t;
301 int repeat = 0, low_predicted = 0;
302 int cpu = smp_processor_id();
303 struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
304 266
305 if (data->needs_update) { 267 if (data->needs_update) {
306 menu_update(drv, dev); 268 menu_update(drv, dev);
@@ -335,7 +297,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
335 data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], 297 data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket],
336 RESOLUTION * DECAY); 298 RESOLUTION * DECAY);
337 299
338 repeat = get_typical_interval(data); 300 get_typical_interval(data);
339 301
340 /* 302 /*
341 * We want to default to C1 (hlt), not to busy polling 303 * We want to default to C1 (hlt), not to busy polling
@@ -356,10 +318,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
356 318
357 if (s->disabled || su->disable) 319 if (s->disabled || su->disable)
358 continue; 320 continue;
359 if (s->target_residency > data->predicted_us) { 321 if (s->target_residency > data->predicted_us)
360 low_predicted = 1;
361 continue; 322 continue;
362 }
363 if (s->exit_latency > latency_req) 323 if (s->exit_latency > latency_req)
364 continue; 324 continue;
365 if (s->exit_latency * multiplier > data->predicted_us) 325 if (s->exit_latency * multiplier > data->predicted_us)
@@ -369,28 +329,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
369 data->exit_us = s->exit_latency; 329 data->exit_us = s->exit_latency;
370 } 330 }
371 331
372 /* not deepest C-state chosen for low predicted residency */
373 if (low_predicted) {
374 unsigned int timer_us = 0;
375
376 /*
377 * Set a timer to detect whether this sleep is much
378 * longer than repeat mode predicted. If the timer
379 * triggers, the code will evaluate whether to put
380 * the CPU into a deeper C-state.
381 * The timer is cancelled on CPU wakeup.
382 */
383 timer_us = 2 * (data->predicted_us + MAX_DEVIATION);
384
385 if (repeat && (4 * timer_us < data->expected_us)) {
386 RCU_NONIDLE(hrtimer_start(hrtmr,
387 ns_to_ktime(1000 * timer_us),
388 HRTIMER_MODE_REL_PINNED));
389 /* In repeat case, menu hrtimer is started */
390 per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT;
391 }
392 }
393
394 return data->last_state_idx; 332 return data->last_state_idx;
395} 333}
396 334
@@ -481,9 +419,6 @@ static int menu_enable_device(struct cpuidle_driver *drv,
481 struct cpuidle_device *dev) 419 struct cpuidle_device *dev)
482{ 420{
483 struct menu_device *data = &per_cpu(menu_devices, dev->cpu); 421 struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
484 struct hrtimer *t = &per_cpu(menu_hrtimer, dev->cpu);
485 hrtimer_init(t, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
486 t->function = menu_hrtimer_notify;
487 422
488 memset(data, 0, sizeof(struct menu_device)); 423 memset(data, 0, sizeof(struct menu_device));
489 424
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 9180f4b85e6d..62bd8b72873c 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -174,10 +174,4 @@ static inline void tick_nohz_task_switch(struct task_struct *tsk) { }
174#endif 174#endif
175 175
176 176
177# ifdef CONFIG_CPU_IDLE_GOV_MENU
178extern void menu_hrtimer_cancel(void);
179# else
180static inline void menu_hrtimer_cancel(void) {}
181# endif /* CONFIG_CPU_IDLE_GOV_MENU */
182
183#endif 177#endif
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index e80183f4a6c4..e77edc97e036 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -827,13 +827,10 @@ void tick_nohz_irq_exit(void)
827{ 827{
828 struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); 828 struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
829 829
830 if (ts->inidle) { 830 if (ts->inidle)
831 /* Cancel the timer because CPU already waken up from the C-states*/
832 menu_hrtimer_cancel();
833 __tick_nohz_idle_enter(ts); 831 __tick_nohz_idle_enter(ts);
834 } else { 832 else
835 tick_nohz_full_stop_tick(ts); 833 tick_nohz_full_stop_tick(ts);
836 }
837} 834}
838 835
839/** 836/**
@@ -931,8 +928,6 @@ void tick_nohz_idle_exit(void)
931 928
932 ts->inidle = 0; 929 ts->inidle = 0;
933 930
934 /* Cancel the timer because CPU already waken up from the C-states*/
935 menu_hrtimer_cancel();
936 if (ts->idle_active || ts->tick_stopped) 931 if (ts->idle_active || ts->tick_stopped)
937 now = ktime_get(); 932 now = ktime_get();
938 933