|
@@ -28,13 +28,6 @@
|
|
|
#define MAX_INTERESTING 50000
|
|
|
#define STDDEV_THRESH 400
|
|
|
|
|
|
-/* 60 * 60 > STDDEV_THRESH * INTERVALS = 400 * 8 */
|
|
|
-#define MAX_DEVIATION 60
|
|
|
-
|
|
|
-static DEFINE_PER_CPU(struct hrtimer, menu_hrtimer);
|
|
|
-static DEFINE_PER_CPU(int, hrtimer_status);
|
|
|
-/* menu hrtimer mode */
|
|
|
-enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT};
|
|
|
|
|
|
/*
|
|
|
* Concepts and ideas behind the menu governor
|
|
@@ -198,42 +191,17 @@ static u64 div_round64(u64 dividend, u32 divisor)
|
|
|
return div_u64(dividend + (divisor / 2), divisor);
|
|
|
}
|
|
|
|
|
|
-/* Cancel the hrtimer if it is not triggered yet */
|
|
|
-void menu_hrtimer_cancel(void)
|
|
|
-{
|
|
|
- int cpu = smp_processor_id();
|
|
|
- struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
|
|
|
-
|
|
|
- /* The timer is still not time out*/
|
|
|
- if (per_cpu(hrtimer_status, cpu)) {
|
|
|
- hrtimer_cancel(hrtmr);
|
|
|
- per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
|
|
|
- }
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(menu_hrtimer_cancel);
|
|
|
-
|
|
|
-/* Call back for hrtimer is triggered */
|
|
|
-static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer)
|
|
|
-{
|
|
|
- int cpu = smp_processor_id();
|
|
|
-
|
|
|
- per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
|
|
|
-
|
|
|
- return HRTIMER_NORESTART;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Try detecting repeating patterns by keeping track of the last 8
|
|
|
* intervals, and checking if the standard deviation of that set
|
|
|
* of points is below a threshold. If it is... then use the
|
|
|
* average of these 8 points as the estimated value.
|
|
|
*/
|
|
|
-static u32 get_typical_interval(struct menu_device *data)
|
|
|
+static void get_typical_interval(struct menu_device *data)
|
|
|
{
|
|
|
int i = 0, divisor = 0;
|
|
|
uint64_t max = 0, avg = 0, stddev = 0;
|
|
|
int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */
|
|
|
- unsigned int ret = 0;
|
|
|
|
|
|
again:
|
|
|
|
|
@@ -274,16 +242,13 @@ again:
|
|
|
if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
|
|
|
|| stddev <= 20) {
|
|
|
data->predicted_us = avg;
|
|
|
- ret = 1;
|
|
|
- return ret;
|
|
|
+ return;
|
|
|
|
|
|
} else if ((divisor * 4) > INTERVALS * 3) {
|
|
|
/* Exclude the max interval */
|
|
|
thresh = max - 1;
|
|
|
goto again;
|
|
|
}
|
|
|
-
|
|
|
- return ret;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -298,9 +263,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
|
|
|
int i;
|
|
|
int multiplier;
|
|
|
struct timespec t;
|
|
|
- int repeat = 0, low_predicted = 0;
|
|
|
- int cpu = smp_processor_id();
|
|
|
- struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
|
|
|
|
|
|
if (data->needs_update) {
|
|
|
menu_update(drv, dev);
|
|
@@ -335,7 +297,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
|
|
|
data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket],
|
|
|
RESOLUTION * DECAY);
|
|
|
|
|
|
- repeat = get_typical_interval(data);
|
|
|
+ get_typical_interval(data);
|
|
|
|
|
|
/*
|
|
|
* 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)
|
|
|
|
|
|
if (s->disabled || su->disable)
|
|
|
continue;
|
|
|
- if (s->target_residency > data->predicted_us) {
|
|
|
- low_predicted = 1;
|
|
|
+ if (s->target_residency > data->predicted_us)
|
|
|
continue;
|
|
|
- }
|
|
|
if (s->exit_latency > latency_req)
|
|
|
continue;
|
|
|
if (s->exit_latency * multiplier > data->predicted_us)
|
|
@@ -369,28 +329,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
|
|
|
data->exit_us = s->exit_latency;
|
|
|
}
|
|
|
|
|
|
- /* not deepest C-state chosen for low predicted residency */
|
|
|
- if (low_predicted) {
|
|
|
- unsigned int timer_us = 0;
|
|
|
-
|
|
|
- /*
|
|
|
- * Set a timer to detect whether this sleep is much
|
|
|
- * longer than repeat mode predicted. If the timer
|
|
|
- * triggers, the code will evaluate whether to put
|
|
|
- * the CPU into a deeper C-state.
|
|
|
- * The timer is cancelled on CPU wakeup.
|
|
|
- */
|
|
|
- timer_us = 2 * (data->predicted_us + MAX_DEVIATION);
|
|
|
-
|
|
|
- if (repeat && (4 * timer_us < data->expected_us)) {
|
|
|
- RCU_NONIDLE(hrtimer_start(hrtmr,
|
|
|
- ns_to_ktime(1000 * timer_us),
|
|
|
- HRTIMER_MODE_REL_PINNED));
|
|
|
- /* In repeat case, menu hrtimer is started */
|
|
|
- per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
return data->last_state_idx;
|
|
|
}
|
|
|
|
|
@@ -481,9 +419,6 @@ static int menu_enable_device(struct cpuidle_driver *drv,
|
|
|
struct cpuidle_device *dev)
|
|
|
{
|
|
|
struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
|
|
|
- struct hrtimer *t = &per_cpu(menu_hrtimer, dev->cpu);
|
|
|
- hrtimer_init(t, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
|
|
- t->function = menu_hrtimer_notify;
|
|
|
|
|
|
memset(data, 0, sizeof(struct menu_device));
|
|
|
|