cpuidle: Add decaying history logic to menu idle predictor
authorPallipadi, Venkatesh <venkatesh.pallipadi@intel.com>
Tue, 30 Dec 2008 22:46:02 +0000 (14:46 -0800)
committerLen Brown <len.brown@intel.com>
Tue, 30 Dec 2008 23:48:01 +0000 (18:48 -0500)
Add decaying history of predicted idle time, instead of using the last early
wakeup. This logic helps menu governor do better job of predicting idle time.

With this change, we also measured noticable (~8%) power savings on
a DP server system with CPUs supporting deep C states, when system
was lightly loaded. There was no change to power or perf on other load
conditions.

Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
drivers/cpuidle/governors/menu.c

index 8d7cf3f31450728ab60a3f349f2e9f88b00cfb95..f1df59f59a37710e4c0370e993ae786f2bddbc4b 100644 (file)
 #include <linux/tick.h>
 
 #define BREAK_FUZZ     4       /* 4 us */
+#define PRED_HISTORY_PCT       50
 
 struct menu_device {
        int             last_state_idx;
 
        unsigned int    expected_us;
        unsigned int    predicted_us;
+       unsigned int    current_predicted_us;
        unsigned int    last_measured_us;
        unsigned int    elapsed_us;
 };
@@ -47,6 +49,12 @@ static int menu_select(struct cpuidle_device *dev)
        data->expected_us =
                (u32) ktime_to_ns(tick_nohz_get_sleep_length()) / 1000;
 
+       /* Recalculate predicted_us based on prediction_history_pct */
+       data->predicted_us *= PRED_HISTORY_PCT;
+       data->predicted_us += (100 - PRED_HISTORY_PCT) *
+                               data->current_predicted_us;
+       data->predicted_us /= 100;
+
        /* find the deepest idle state that satisfies our constraints */
        for (i = CPUIDLE_DRIVER_STATE_START + 1; i < dev->state_count; i++) {
                struct cpuidle_state *s = &dev->states[i];
@@ -97,7 +105,7 @@ static void menu_reflect(struct cpuidle_device *dev)
                measured_us = -1;
 
        /* Predict time until next break event */
-       data->predicted_us = max(measured_us, data->last_measured_us);
+       data->current_predicted_us = max(measured_us, data->last_measured_us);
 
        if (last_idle_us + BREAK_FUZZ <
            data->expected_us - target->exit_latency) {