Commit 71325960 authored by Suresh Siddha's avatar Suresh Siddha Committed by Ingo Molnar

sched/nohz: Fix nohz cpu idle load balancing state with cpu hotplug

With the recent nohz scheduler changes, rq's nohz flag
'NOHZ_TICK_STOPPED' and its associated state doesn't get cleared
immediately after the cpu exits idle. This gets cleared as part
of the next tick seen on that cpu.

For the cpu offline support, we need to clear this state
manually. Fix it by registering a cpu notifier, which clears the
nohz idle load balance state for this rq explicitly during the
CPU_DYING notification.

There won't be any nohz updates for that cpu, after the
CPU_DYING notification. But lets be extra paranoid and skip
updating the nohz state in the select_nohz_load_balancer() if
the cpu is not in active state anymore.
Reported-by: default avatarSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Reviewed-and-tested-by: default avatarSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Tested-by: default avatarSergey Senozhatsky <sergey.senozhatsky@gmail.com>
Signed-off-by: default avatarSuresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1327026538.16150.40.camel@sbsiddha-desk.sc.intel.comSigned-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent db7e527d
...@@ -4866,6 +4866,15 @@ static void nohz_balancer_kick(int cpu) ...@@ -4866,6 +4866,15 @@ static void nohz_balancer_kick(int cpu)
return; return;
} }
static inline void clear_nohz_tick_stopped(int cpu)
{
if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) {
cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
atomic_dec(&nohz.nr_cpus);
clear_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
}
}
static inline void set_cpu_sd_state_busy(void) static inline void set_cpu_sd_state_busy(void)
{ {
struct sched_domain *sd; struct sched_domain *sd;
...@@ -4904,6 +4913,12 @@ void select_nohz_load_balancer(int stop_tick) ...@@ -4904,6 +4913,12 @@ void select_nohz_load_balancer(int stop_tick)
{ {
int cpu = smp_processor_id(); int cpu = smp_processor_id();
/*
* If this cpu is going down, then nothing needs to be done.
*/
if (!cpu_active(cpu))
return;
if (stop_tick) { if (stop_tick) {
if (test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu))) if (test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))
return; return;
...@@ -4914,6 +4929,18 @@ void select_nohz_load_balancer(int stop_tick) ...@@ -4914,6 +4929,18 @@ void select_nohz_load_balancer(int stop_tick)
} }
return; return;
} }
static int __cpuinit sched_ilb_notifier(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DYING:
clear_nohz_tick_stopped(smp_processor_id());
return NOTIFY_OK;
default:
return NOTIFY_DONE;
}
}
#endif #endif
static DEFINE_SPINLOCK(balancing); static DEFINE_SPINLOCK(balancing);
...@@ -5070,11 +5097,7 @@ static inline int nohz_kick_needed(struct rq *rq, int cpu) ...@@ -5070,11 +5097,7 @@ static inline int nohz_kick_needed(struct rq *rq, int cpu)
* busy tick after returning from idle, we will update the busy stats. * busy tick after returning from idle, we will update the busy stats.
*/ */
set_cpu_sd_state_busy(); set_cpu_sd_state_busy();
if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) { clear_nohz_tick_stopped(cpu);
clear_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu));
cpumask_clear_cpu(cpu, nohz.idle_cpus_mask);
atomic_dec(&nohz.nr_cpus);
}
/* /*
* None are in tickless mode and hence no need for NOHZ idle load * None are in tickless mode and hence no need for NOHZ idle load
...@@ -5590,6 +5613,7 @@ __init void init_sched_fair_class(void) ...@@ -5590,6 +5613,7 @@ __init void init_sched_fair_class(void)
#ifdef CONFIG_NO_HZ #ifdef CONFIG_NO_HZ
zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT); zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT);
cpu_notifier(sched_ilb_notifier, 0);
#endif #endif
#endif /* SMP */ #endif /* SMP */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment