For the governor has predict functionality, add a new predict
interface in cpuidle framework to call and use it.
---
 drivers/cpuidle/cpuidle.c        | 34 ++++++++++++++++++++++++++++++++++
 drivers/cpuidle/governors/menu.c |  7 +++++++
 include/linux/cpuidle.h          |  3 +++
 kernel/sched/idle.c              |  1 +
 4 files changed, 45 insertions(+)

diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 4066308..ef6f7dd 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -336,6 +336,40 @@ void cpuidle_entry_end(void)
 }
 
 /**
+ * cpuidle_predict - predict whether the coming idle is a fast idle or not
+ */
+void cpuidle_predict(void)
+{
+       struct cpuidle_device *dev = cpuidle_get_device();
+       unsigned int overhead_threshold;
+
+       if (!dev)
+               return;
+
+       overhead_threshold = dev->idle_stat.overhead;
+
+       if (cpuidle_curr_governor->predict) {
+               dev->idle_stat.predicted_us = cpuidle_curr_governor->predict();
+               /*
+                * notify idle governor to avoid reduplicative
+                * prediction computation
+                */
+               dev->idle_stat.predicted = true;
+               if (dev->idle_stat.predicted_us < overhead_threshold) {
+                       /*
+                        * notify tick subsystem to keep ticking
+                        * for the coming idle
+                        */
+                       dev->idle_stat.fast_idle = true;
+               } else
+                       dev->idle_stat.fast_idle = false;
+       } else {
+               dev->idle_stat.predicted = false;
+               dev->idle_stat.fast_idle = false;
+       }
+}
+
+/**
  * cpuidle_install_idle_handler - installs the cpuidle idle loop handler
  */
 void cpuidle_install_idle_handler(void)
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 6bed197..90b2a10 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -344,6 +344,12 @@ static int menu_select(struct cpuidle_driver *drv, struct 
cpuidle_device *dev)
        if (unlikely(latency_req == 0))
                return 0;
 
+       /*don't predict again if idle framework already did it */
+       if (!dev->idle_stat.predicted)
+               menu_predict();
+       else
+               dev->idle_stat.predicted = false;
+
        if (CPUIDLE_DRIVER_STATE_START > 0) {
                struct cpuidle_state *s = 
&drv->states[CPUIDLE_DRIVER_STATE_START];
                unsigned int polling_threshold;
@@ -518,6 +524,7 @@ static struct cpuidle_governor menu_governor = {
        .enable =       menu_enable_device,
        .select =       menu_select,
        .reflect =      menu_reflect,
+       .predict =      menu_predict,
 };
 
 /**
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index cad9b71..9ca0288 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -143,6 +143,7 @@ extern int cpuidle_select(struct cpuidle_driver *drv,
                          struct cpuidle_device *dev);
 extern void cpuidle_entry_start(void);
 extern void cpuidle_entry_end(void);
+extern void cpuidle_predict(void);
 extern int cpuidle_enter(struct cpuidle_driver *drv,
                         struct cpuidle_device *dev, int index);
 extern void cpuidle_reflect(struct cpuidle_device *dev, int index);
@@ -178,6 +179,7 @@ static inline int cpuidle_select(struct cpuidle_driver *drv,
 {return -ENODEV; }
 static inline void cpuidle_entry_start(void) { }
 static inline void cpuidle_entry_end(void) { }
+static inline void cpuidle_predict(void) { }
 static inline int cpuidle_enter(struct cpuidle_driver *drv,
                                struct cpuidle_device *dev, int index)
 {return -ENODEV; }
@@ -255,6 +257,7 @@ struct cpuidle_governor {
        int  (*select)          (struct cpuidle_driver *drv,
                                        struct cpuidle_device *dev);
        void (*reflect)         (struct cpuidle_device *dev, int index);
+       unsigned int (*predict)(void);
 };
 
 #ifdef CONFIG_CPU_IDLE
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index 0951dac..8704f3c 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -225,6 +225,7 @@ static void do_idle(void)
         */
        __current_set_polling();
        quiet_vmstat();
+       cpuidle_predict();
        tick_nohz_idle_enter();
        cpuidle_entry_end();
 
-- 
2.7.4

Reply via email to