As we know in which idle state the cpu is, we can investigate the following:

1. when did the cpu entered the idle state ? the longer the cpu is idle, the
deeper it is idle
2. what exit latency is ? the greater the exit latency is, the deeper it is

With both information, when all cpus are idle, we can choose the idlest cpu.

When one cpu is not idle, the old check against weighted load applies.

Signed-off-by: Daniel Lezcano <daniel.lezc...@linaro.org>
---
 kernel/sched/fair.c |   46 ++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 40 insertions(+), 6 deletions(-)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 16042b5..068e503 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -23,6 +23,7 @@
 #include <linux/latencytop.h>
 #include <linux/sched.h>
 #include <linux/cpumask.h>
+#include <linux/cpuidle.h>
 #include <linux/slab.h>
 #include <linux/profile.h>
 #include <linux/interrupt.h>
@@ -4336,20 +4337,53 @@ static int
 find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
 {
        unsigned long load, min_load = ULONG_MAX;
-       int idlest = -1;
+       unsigned int min_exit_latency = UINT_MAX;
+       u64 idle_stamp, min_idle_stamp = ULONG_MAX;
+
+       struct rq *rq;
+       struct cpuidle_power *power;
+
+       int cpu_idle = -1;
+       int cpu_busy = -1;
        int i;
 
        /* Traverse only the allowed CPUs */
        for_each_cpu_and(i, sched_group_cpus(group), tsk_cpus_allowed(p)) {
-               load = weighted_cpuload(i);
 
-               if (load < min_load || (load == min_load && i == this_cpu)) {
-                       min_load = load;
-                       idlest = i;
+               if (idle_cpu(i)) {
+
+                       rq = cpu_rq(i);
+                       power = rq->power;
+                       idle_stamp = rq->idle_stamp;
+
+                       /* The cpu is idle since a shorter time */
+                       if (idle_stamp < min_idle_stamp) {
+                               min_idle_stamp = idle_stamp;
+                               cpu_idle = i;
+                               continue;
+                       }
+
+                       /* The cpu is idle but the exit_latency is shorter */
+                       if (power && power->exit_latency < min_exit_latency) {
+                               min_exit_latency = power->exit_latency;
+                               cpu_idle = i;
+                               continue;
+                       }
+               } else {
+
+                       load = weighted_cpuload(i);
+
+                       if (load < min_load ||
+                           (load == min_load && i == this_cpu)) {
+                               min_load = load;
+                               cpu_busy = i;
+                               continue;
+                       }
                }
        }
 
-       return idlest;
+       /* Busy cpus are considered less idle than idle cpus ;) */
+       return cpu_busy != -1 ? cpu_busy : cpu_idle;
 }
 
 /*
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to