Hi, Daniel & Vincent,
Do you like to give a quick testing for this direction on ARM boards? It should be worth have a try. :)
Regards Alex
From d095e6ad805576451c1b6396de99f440a66c342d Mon Sep 17 00:00:00 2001
From: Alex Shi alex.shi@linaro.org Date: Wed, 26 Aug 2015 17:39:37 +0800 Subject: [PATCH] sched: find interrupted idle cpu
Currently we just try to find least idle cpu. If we can get the interrupted idle cpu, we can use it to get benefit from both latency and power side, since the interrupted cpu don't need time to wakeup.
Signed-off-by: Alex Shi alex.shi@linaro.org --- include/linux/cpuidle.h | 1 + kernel/sched/fair.c | 9 ++++++++- kernel/sched/sched.h | 18 ++++++++++++++---- 3 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index d075d34..2a4521a 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -44,6 +44,7 @@ struct cpuidle_state { int power_usage; /* in mW */ unsigned int target_residency; /* in US */ bool disabled; /* disabled on all CPUs */ + int in_irq;
int (*enter) (struct cpuidle_device *dev, struct cpuidle_driver *drv, diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 6e2e348..094c815 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4740,7 +4740,14 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu) for_each_cpu_and(i, sched_group_cpus(group), tsk_cpus_allowed(p)) { if (idle_cpu(i)) { struct rq *rq = cpu_rq(i); - struct cpuidle_state *idle = idle_get_state(rq); + struct cpuidle_state *idle = idle_get_state(rq, i); + + /* TODO: consider the RT and IRQ load? */ + if (idle && idle->in_irq) { + shallowest_idle_cpu = i; + break; + } + if (idle && idle->exit_latency < min_exit_latency) { /* * We give priority to a CPU whose idle state diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 68cda11..ee336fd 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -9,13 +9,14 @@ #include <linux/irq_work.h> #include <linux/tick.h> #include <linux/slab.h> +#include <linux/cpuidle.h> /* for struct cpuidle_state */
#include "cpupri.h" #include "cpudeadline.h" #include "cpuacct.h" +#include "../time/tick-sched.h"
struct rq; -struct cpuidle_state;
/* task_struct::on_rq states: */ #define TASK_ON_RQ_QUEUED 1 @@ -1271,10 +1272,19 @@ static inline void idle_set_state(struct rq *rq, rq->idle_state = idle_state; }
-static inline struct cpuidle_state *idle_get_state(struct rq *rq) +static inline struct cpuidle_state *idle_get_state(struct rq *rq, int cpu) { + struct cpuidle_state *idle = rq->idle_state; +#ifdef CONFIG_NO_HZ_COMMON + struct tick_sched *ts = tick_get_tick_sched(cpu); + + /* the cpu is interrupted in idle */ + if (idle && ts->inidle && !ts->idle_active) + idle->in_irq = 1; +#endif WARN_ON(!rcu_read_lock_held()); - return rq->idle_state; + + return idle; } #else static inline void idle_set_state(struct rq *rq, @@ -1282,7 +1292,7 @@ static inline void idle_set_state(struct rq *rq, { }
-static inline struct cpuidle_state *idle_get_state(struct rq *rq) +static inline struct cpuidle_state *idle_get_state(struct rq *rq, int cpu) { return NULL; }