LKML Archive on lore.kernel.org help / color / mirror / Atom feed
* [RFC PATCH] kick sleeping idle CPUS on cpu_idle_wait @ 2008-01-08 2:27 Steven Rostedt 2008-01-08 3:33 ` Andi Kleen 0 siblings, 1 reply; 17+ messages in thread From: Steven Rostedt @ 2008-01-08 2:27 UTC (permalink / raw) To: LKML Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Thomas Gleixner, Andi Kleen, Brown, Len, Venkatesh Pallipadi, Adam Belay, Peter Zijlstra Sometimes cpu_idle_wait gets stuck because it might miss CPUS that are already in idle, have no tasks waiting to run and have no interrupts going to them. This is common on bootup when switching cpu idle governors. This patch accounts for CPUs already in idle. Background: ----------- I notice this while developing the mcount patches, that every once in a while the system would hang. Looking deeper, the hang was always at boot up when registering init_menu of the cpu_idle menu governor. Talking with Thomas Gliexner, we discovered that one of the CPUS had no timer events scheduled for it and it was in idle (running with NO_HZ). So the CPU would not set the cpu_idle_state bit. Hitting sysrq-t a few times would eventually route the interrupt to the stuck CPU and the system would continue. Note, I would have used the PDA isidle but that is set after the cpu_idle_state bit is cleared, and would leave a window open where we may miss being kicked. hmm, looking closer at this, we still have a small race window between clearing the cpu_idle_state and disabling interrupts (hence the RFC). CPU0: CPU 1: --------- --------- cpu_idle_wait(): cpu_idle(): | __cpu_cpu_var(is_idle) = 1; | if (__get_cpu_var(cpu_idle_state)) /* == 0 */ per_cpu(cpu_idle_state, 1) = 1; | if (per_cpu(is_idle, 1)) /* == 1 */ | smp_call_function(1) | | receives ipi and runs do_nothing. wait on map == empty idle(); /* waits forever */ So really we need interrupts off for most of this then. One might think that we could simply clear the cpu_idle_state from do_nothing, but I'm assuming that cpu_idle governors can be removed, and this might cause a race that a governor might be used after the module was removed. One solution I think is that we could keep calling do_nothing to all the bits of map that are still set in the cpu_idle_wait() loop. That would work too. Thoughts? Signed-off-by: Steven Rostedt <srostedt@redhat.com> --- arch/x86/kernel/process_32.c | 36 ++++++++++++++++++++++++++++++++---- arch/x86/kernel/process_64.c | 28 ++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 8 deletions(-) Index: linus.git/arch/x86/kernel/process_32.c =================================================================== --- linus.git.orig/arch/x86/kernel/process_32.c 2005-09-11 20:05:46.000000000 -0400 +++ linus.git/arch/x86/kernel/process_32.c 2008-01-07 20:42:24.000000000 -0500 @@ -83,6 +83,7 @@ unsigned long thread_saved_pc(struct tas void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); static DEFINE_PER_CPU(unsigned int, cpu_idle_state); +static DEFINE_PER_CPU(unsigned int, in_idle); void disable_hlt(void) { @@ -178,6 +179,12 @@ void cpu_idle(void) /* endless idle loop with no priority at all */ while (1) { tick_nohz_stop_sched_tick(); + __get_cpu_var(in_idle) = 1; + /* + * Make sure in_idle is seen by others + * before cpu_idle_state is set (and read) + */ + smp_mb(); while (!need_resched()) { void (*idle)(void); @@ -197,6 +204,7 @@ void cpu_idle(void) __get_cpu_var(irq_stat).idle_timestamp = jiffies; idle(); } + __get_cpu_var(in_idle) = 0; tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); @@ -204,6 +212,10 @@ void cpu_idle(void) } } +static void do_nothing(void *unused) +{ +} + void cpu_idle_wait(void) { unsigned int cpu, this_cpu = get_cpu(); @@ -212,15 +224,31 @@ void cpu_idle_wait(void) set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); put_cpu(); + for_each_online_cpu(cpu) + per_cpu(cpu_idle_state, cpu) = 1; + + __get_cpu_var(cpu_idle_state) = 0; + + /* + * Make cpu_idle_state viewable by other CPUs + * and be able to read in_idle of other CPUs. + */ + smp_mb(); + + /* Wake up any CPUs that are already in idle */ cpus_clear(map); for_each_online_cpu(cpu) { - per_cpu(cpu_idle_state, cpu) = 1; - cpu_set(cpu, map); + if (per_cpu(in_idle, cpu)) + cpu_set(cpu, map); } + smp_call_function_mask(map, do_nothing, 0, 0); - __get_cpu_var(cpu_idle_state) = 0; + cpus_clear(map); + for_each_online_cpu(cpu) { + if (per_cpu(cpu_idle_state, cpu)) + cpu_set(cpu, map); + } - wmb(); do { ssleep(1); for_each_online_cpu(cpu) { Index: linus.git/arch/x86/kernel/process_64.c =================================================================== --- linus.git.orig/arch/x86/kernel/process_64.c 2007-10-19 12:30:44.000000000 -0400 +++ linus.git/arch/x86/kernel/process_64.c 2008-01-07 20:47:34.000000000 -0500 @@ -65,6 +65,7 @@ EXPORT_SYMBOL(boot_option_idle_override) void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); static DEFINE_PER_CPU(unsigned int, cpu_idle_state); +static DEFINE_PER_CPU(unsigned int, in_idle); static ATOMIC_NOTIFIER_HEAD(idle_notifier); @@ -135,6 +136,10 @@ static void poll_idle (void) cpu_relax(); } +static void do_nothing(void *unused) +{ +} + void cpu_idle_wait(void) { unsigned int cpu, this_cpu = get_cpu(); @@ -143,15 +148,30 @@ void cpu_idle_wait(void) set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); put_cpu(); + for_each_online_cpu(cpu) + per_cpu(cpu_idle_state, cpu) = 1; + __get_cpu_var(cpu_idle_state) = 0; + + /* + * Make cpu_idle_state viewable by other CPUs + * and be able to read in_idle of other CPUs. + */ + smp_mb(); + + /* Wake up any CPUs that are already in idle */ cpus_clear(map); for_each_online_cpu(cpu) { - per_cpu(cpu_idle_state, cpu) = 1; - cpu_set(cpu, map); + if (per_cpu(in_idle, cpu)) + cpu_set(cpu, map); } + smp_call_function_mask(map, do_nothing, 0, 0); - __get_cpu_var(cpu_idle_state) = 0; + cpus_clear(map); + for_each_online_cpu(cpu) { + if (per_cpu(cpu_idle_state, cpu)) + cpu_set(cpu, map); + } - wmb(); do { ssleep(1); for_each_online_cpu(cpu) { ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC PATCH] kick sleeping idle CPUS on cpu_idle_wait 2008-01-08 2:27 [RFC PATCH] kick sleeping idle CPUS on cpu_idle_wait Steven Rostedt @ 2008-01-08 3:33 ` Andi Kleen 2008-01-09 20:42 ` [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait Steven Rostedt 0 siblings, 1 reply; 17+ messages in thread From: Andi Kleen @ 2008-01-08 3:33 UTC (permalink / raw) To: Steven Rostedt Cc: LKML, Linus Torvalds, Andrew Morton, Ingo Molnar, Thomas Gleixner, Andi Kleen, Brown, Len, Venkatesh Pallipadi, Adam Belay, Peter Zijlstra On Mon, Jan 07, 2008 at 09:27:24PM -0500, Steven Rostedt wrote: > > Sometimes cpu_idle_wait gets stuck because it might miss CPUS that are > already in idle, have no tasks waiting to run and have no interrupts > going to them. This is common on bootup when switching cpu idle > governors. I must admit I never liked that cpu idle wait code anyways. Why again can't normal RCU be used for this? Waiting for two RCU quiescent cycles should be enough, shouldn't it? -Andi ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait 2008-01-08 3:33 ` Andi Kleen @ 2008-01-09 20:42 ` Steven Rostedt 2008-01-09 22:12 ` Steven Rostedt ` (3 more replies) 0 siblings, 4 replies; 17+ messages in thread From: Steven Rostedt @ 2008-01-09 20:42 UTC (permalink / raw) To: LKML Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Thomas Gleixner, Brown, Len, Venkatesh Pallipadi, Adam Belay, Peter Zijlstra, Andi Kleen This patch is different than the first patch I sent out. This one just sends an IPI to all CPUS that don't check in after 1 sec. Sometimes cpu_idle_wait gets stuck because it might miss CPUS that are already in idle, have no tasks waiting to run and have no interrupts going to them. This is common on bootup when switching cpu idle governors. This patch gives those CPUS that don't check in an IPI kick. Signed-off-by: Steven Rostedt <srostedt@redhat.com> --- arch/x86/kernel/process_32.c | 11 +++++++++++ arch/x86/kernel/process_64.c | 11 +++++++++++ 2 files changed, 22 insertions(+) Index: linux-compile-i386.git/arch/x86/kernel/process_32.c =================================================================== --- linux-compile-i386.git.orig/arch/x86/kernel/process_32.c 2008-01-09 14:09:36.000000000 -0500 +++ linux-compile-i386.git/arch/x86/kernel/process_32.c 2008-01-09 14:09:45.000000000 -0500 @@ -204,6 +204,10 @@ void cpu_idle(void) } } +static void do_nothing(void *unused) +{ +} + void cpu_idle_wait(void) { unsigned int cpu, this_cpu = get_cpu(); @@ -228,6 +232,13 @@ void cpu_idle_wait(void) cpu_clear(cpu, map); } cpus_and(map, map, cpu_online_map); + /* + * We waited 1 sec, if a CPU still did not call idle + * it may be because it is in idle and not waking up + * because it has nothing to do. + * Give all the remaining CPUS a kick. + */ + smp_call_function_mask(map, do_nothing, 0, 0); } while (!cpus_empty(map)); set_cpus_allowed(current, tmp); Index: linux-compile-i386.git/arch/x86/kernel/process_64.c =================================================================== --- linux-compile-i386.git.orig/arch/x86/kernel/process_64.c 2008-01-09 14:09:36.000000000 -0500 +++ linux-compile-i386.git/arch/x86/kernel/process_64.c 2008-01-09 15:17:20.000000000 -0500 @@ -135,6 +135,10 @@ static void poll_idle (void) cpu_relax(); } +static void do_nothing(void *unused) +{ +} + void cpu_idle_wait(void) { unsigned int cpu, this_cpu = get_cpu(); @@ -160,6 +164,13 @@ void cpu_idle_wait(void) cpu_clear(cpu, map); } cpus_and(map, map, cpu_online_map); + /* + * We waited 1 sec, if a CPU still did not call idle + * it may be because it is in idle and not waking up + * because it has nothing to do. + * Give all the remaining CPUS a kick. + */ + smp_call_function_mask(map, do_nothing, 0, 0); } while (!cpus_empty(map)); set_cpus_allowed(current, tmp); ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait 2008-01-09 20:42 ` [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait Steven Rostedt @ 2008-01-09 22:12 ` Steven Rostedt 2008-01-10 13:45 ` Ingo Molnar 2008-01-09 23:42 ` Andrew Morton ` (2 subsequent siblings) 3 siblings, 1 reply; 17+ messages in thread From: Steven Rostedt @ 2008-01-09 22:12 UTC (permalink / raw) To: LKML Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Thomas Gleixner, Brown, Len, Venkatesh Pallipadi, Adam Belay, Peter Zijlstra, Andi Kleen On Wed, 2008-01-09 at 15:42 -0500, Steven Rostedt wrote: > This patch is different than the first patch I sent out. > This one just sends an IPI to all CPUS that don't check in after 1 sec. > > > Sometimes cpu_idle_wait gets stuck because it might miss CPUS that are > already in idle, have no tasks waiting to run and have no interrupts > going to them. This is common on bootup when switching cpu idle > governors. > > This patch gives those CPUS that don't check in an IPI kick. FYI, I just hit this hang on 2.6.24-rc6 without any extra patches. So, unless 2.6.24-rc7 did anything to fix this issue, this is a high priority bug (IMHO). -- Steve ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait 2008-01-09 22:12 ` Steven Rostedt @ 2008-01-10 13:45 ` Ingo Molnar 2008-01-10 14:43 ` Steven Rostedt 0 siblings, 1 reply; 17+ messages in thread From: Ingo Molnar @ 2008-01-10 13:45 UTC (permalink / raw) To: Steven Rostedt Cc: LKML, Linus Torvalds, Andrew Morton, Thomas Gleixner, Brown, Len, Venkatesh Pallipadi, Adam Belay, Peter Zijlstra, Andi Kleen * Steven Rostedt <rostedt@goodmis.org> wrote: > On Wed, 2008-01-09 at 15:42 -0500, Steven Rostedt wrote: > > This patch is different than the first patch I sent out. > > This one just sends an IPI to all CPUS that don't check in after 1 sec. > > > > > > Sometimes cpu_idle_wait gets stuck because it might miss CPUS that are > > already in idle, have no tasks waiting to run and have no interrupts > > going to them. This is common on bootup when switching cpu idle > > governors. > > > > This patch gives those CPUS that don't check in an IPI kick. > > FYI, I just hit this hang on 2.6.24-rc6 without any extra patches. So, > unless 2.6.24-rc7 did anything to fix this issue, this is a high > priority bug (IMHO). i'm wondering why this only triggered now. Is this something new in 2.6.24? Ingo ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait 2008-01-10 13:45 ` Ingo Molnar @ 2008-01-10 14:43 ` Steven Rostedt 2008-01-10 17:31 ` Pallipadi, Venkatesh 0 siblings, 1 reply; 17+ messages in thread From: Steven Rostedt @ 2008-01-10 14:43 UTC (permalink / raw) To: Ingo Molnar Cc: LKML, Linus Torvalds, Andrew Morton, Thomas Gleixner, Brown, Len, Venkatesh Pallipadi, Adam Belay, Peter Zijlstra, Andi Kleen On Thu, 10 Jan 2008, Ingo Molnar wrote: > > FYI, I just hit this hang on 2.6.24-rc6 without any extra patches. So, > > unless 2.6.24-rc7 did anything to fix this issue, this is a high > > priority bug (IMHO). > > i'm wondering why this only triggered now. Is this something new in > 2.6.24? It only triggeres with the switching of the idle governors. And not just one, you need to switch twice. The first loading of a governor does not call cpu_idle_wait, but the second one does. NO_HZ must also be enabled, plus this needs to happen when no events or threads are scheduled to run on a CPU, which limits this to boot up. Also, this only seems to happen on my 2x2 (4way) and only once in a while. I'm surprised that I'm the only one so far to report it. I can boot up the 2.6.23 kernel on this box to see if it also hangs sometimes. But, as I said, it may take several hundreds of tries to see it. -- Steve ^ permalink raw reply [flat|nested] 17+ messages in thread
* RE: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait 2008-01-10 14:43 ` Steven Rostedt @ 2008-01-10 17:31 ` Pallipadi, Venkatesh 2008-01-10 18:03 ` Steven Rostedt 0 siblings, 1 reply; 17+ messages in thread From: Pallipadi, Venkatesh @ 2008-01-10 17:31 UTC (permalink / raw) To: Steven Rostedt, Ingo Molnar Cc: LKML, Linus Torvalds, Andrew Morton, Thomas Gleixner, Brown, Len, Adam Belay, Peter Zijlstra, Andi Kleen >-----Original Message----- >From: linux-kernel-owner@vger.kernel.org >[mailto:linux-kernel-owner@vger.kernel.org] On Behalf Of Steven Rostedt >Sent: Thursday, January 10, 2008 6:44 AM >To: Ingo Molnar >Cc: LKML; Linus Torvalds; Andrew Morton; Thomas Gleixner; >Brown, Len; Pallipadi, Venkatesh; Adam Belay; Peter Zijlstra; >Andi Kleen >Subject: Re: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait > > > >On Thu, 10 Jan 2008, Ingo Molnar wrote: >> > FYI, I just hit this hang on 2.6.24-rc6 without any extra >patches. So, >> > unless 2.6.24-rc7 did anything to fix this issue, this is a high >> > priority bug (IMHO). >> >> i'm wondering why this only triggered now. Is this something new in >> 2.6.24? > >It only triggeres with the switching of the idle governors. >And not just >one, you need to switch twice. The first loading of a governor does not >call cpu_idle_wait, but the second one does. NO_HZ must also >be enabled, >plus this needs to happen when no events or threads are >scheduled to run >on a CPU, which limits this to boot up. > >Also, this only seems to happen on my 2x2 (4way) and only once >in a while. > >I'm surprised that I'm the only one so far to report it. I can >boot up the >2.6.23 kernel on this box to see if it also hangs sometimes. But, as I >said, it may take several hundreds of tries to see it. With 2.6.23, you can try compiling acpi processor.ko as a module and doing insmod and rmmod in a loop. That should call cpu_idle_wait very frequently. Thanks, Venki ^ permalink raw reply [flat|nested] 17+ messages in thread
* RE: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait 2008-01-10 17:31 ` Pallipadi, Venkatesh @ 2008-01-10 18:03 ` Steven Rostedt 0 siblings, 0 replies; 17+ messages in thread From: Steven Rostedt @ 2008-01-10 18:03 UTC (permalink / raw) To: Pallipadi, Venkatesh Cc: Ingo Molnar, LKML, Linus Torvalds, Andrew Morton, Thomas Gleixner, Brown, Len, Adam Belay, Peter Zijlstra, Andi Kleen On Thu, 10 Jan 2008, Pallipadi, Venkatesh wrote: > > > With 2.6.23, you can try compiling acpi processor.ko as a module and > doing insmod and rmmod in a loop. That should call cpu_idle_wait very > frequently. The thing is, after the full boot, there's too many things going on to keep a system fully idle. Little services can wake a processor up. The problem I had was that this happens on early bootup where there's not much around to wake the sleeping processor. I'm not sure if it is too much of a problem after boot up. -- Steve ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait 2008-01-09 20:42 ` [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait Steven Rostedt 2008-01-09 22:12 ` Steven Rostedt @ 2008-01-09 23:42 ` Andrew Morton 2008-01-10 0:05 ` Steven Rostedt 2008-01-10 0:12 ` Pallipadi, Venkatesh [not found] ` <B5B0CFF685D7DF46A05CF1678CFB42ED20E00653@orsmsx423.amr.corp.intel.com> 3 siblings, 1 reply; 17+ messages in thread From: Andrew Morton @ 2008-01-09 23:42 UTC (permalink / raw) To: Steven Rostedt Cc: linux-kernel, torvalds, mingo, tglx, len.brown, venkatesh.pallipadi, abelay, a.p.zijlstra, ak > Subject: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait s/cpus_/cpu_/ On Wed, 09 Jan 2008 15:42:10 -0500 Steven Rostedt <rostedt@goodmis.org> wrote: > This patch is different than the first patch I sent out. > This one just sends an IPI to all CPUS that don't check in after 1 sec. > > > Sometimes cpu_idle_wait gets stuck because it might miss CPUS that are > already in idle, have no tasks waiting to run and have no interrupts > going to them. This is common on bootup when switching cpu idle > governors. > > This patch gives those CPUS that don't check in an IPI kick. > (wakes up) > > Index: linux-compile-i386.git/arch/x86/kernel/process_32.c > =================================================================== > --- linux-compile-i386.git.orig/arch/x86/kernel/process_32.c 2008-01-09 14:09:36.000000000 -0500 > +++ linux-compile-i386.git/arch/x86/kernel/process_32.c 2008-01-09 14:09:45.000000000 -0500 > @@ -204,6 +204,10 @@ void cpu_idle(void) > } > } > > +static void do_nothing(void *unused) > +{ > +} > + > void cpu_idle_wait(void) > { > unsigned int cpu, this_cpu = get_cpu(); > @@ -228,6 +232,13 @@ void cpu_idle_wait(void) > cpu_clear(cpu, map); > } > cpus_and(map, map, cpu_online_map); > + /* > + * We waited 1 sec, if a CPU still did not call idle > + * it may be because it is in idle and not waking up > + * because it has nothing to do. > + * Give all the remaining CPUS a kick. > + */ > + smp_call_function_mask(map, do_nothing, 0, 0); > } while (!cpus_empty(map)); > > set_cpus_allowed(current, tmp); This seems rather hacky. Although it may turn out to be the most efficient fix, dunno. I'd have thought that the right fix would be to plug the race which you described at the top-of-thread. That might require some redesign, but it sounds like the design is wrong anyway. Maybe your proposed fix is suitable for a 2.6.24 bandaid.. <looks at cpu_idle_wait()> <pokes his tongue out at the person who put in a global, exported-to-modules interface and didn't bother documenting it> OK, it's called infrequently, so a few extra IPIs there won't hurt. btw, it's pretty damn sad that cpu_idle_wait() will always stall for at least one second. That's a huge amount of time and I bet it's thousands of times longer than is actually needed.. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait 2008-01-09 23:42 ` Andrew Morton @ 2008-01-10 0:05 ` Steven Rostedt 0 siblings, 0 replies; 17+ messages in thread From: Steven Rostedt @ 2008-01-10 0:05 UTC (permalink / raw) To: Andrew Morton Cc: linux-kernel, torvalds, mingo, tglx, len.brown, venkatesh.pallipadi, abelay, a.p.zijlstra, ak On Wed, 9 Jan 2008, Andrew Morton wrote: > > > Subject: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait > > s/cpus_/cpu_/ I've been up to 4am writing patches. I must be seeing double :-/ > > { > > unsigned int cpu, this_cpu = get_cpu(); > > @@ -228,6 +232,13 @@ void cpu_idle_wait(void) > > cpu_clear(cpu, map); > > } > > cpus_and(map, map, cpu_online_map); > > + /* > > + * We waited 1 sec, if a CPU still did not call idle > > + * it may be because it is in idle and not waking up > > + * because it has nothing to do. > > + * Give all the remaining CPUS a kick. > > + */ > > + smp_call_function_mask(map, do_nothing, 0, 0); > > } while (!cpus_empty(map)); > > > > set_cpus_allowed(current, tmp); > > This seems rather hacky. Although it may turn out to be the most efficient > fix, dunno. s/seems/is/ > > I'd have thought that the right fix would be to plug the race which you > described at the top-of-thread. That might require some redesign, but it > sounds like the design is wrong anyway. > > Maybe your proposed fix is suitable for a 2.6.24 bandaid.. I was thinking the same thing. > > <looks at cpu_idle_wait()> > > <pokes his tongue out at the person who put in a global, > exported-to-modules interface and didn't bother documenting it> > > OK, it's called infrequently, so a few extra IPIs there won't hurt. > > > btw, it's pretty damn sad that cpu_idle_wait() will always stall for at > least one second. That's a huge amount of time and I bet it's thousands of > times longer than is actually needed.. > I didn't like that either. But I was focusing on something else, and I was getting sick and tired of my box hanging on bootup every once in a while (usually when I reboot and walk away, just to come back to find the box hung). So this was my band-aid, and since it was only happening on the box running with my patches, I thought it may have been something I did. But then it finally hung on a reboot to a vanilla kernel, so I decided to at least send my band-aid out. If anything, this should get some notice and we can have a proper fix for .25. -- Steve ^ permalink raw reply [flat|nested] 17+ messages in thread
* RE: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait 2008-01-09 20:42 ` [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait Steven Rostedt 2008-01-09 22:12 ` Steven Rostedt 2008-01-09 23:42 ` Andrew Morton @ 2008-01-10 0:12 ` Pallipadi, Venkatesh [not found] ` <B5B0CFF685D7DF46A05CF1678CFB42ED20E00653@orsmsx423.amr.corp.intel.com> 3 siblings, 0 replies; 17+ messages in thread From: Pallipadi, Venkatesh @ 2008-01-10 0:12 UTC (permalink / raw) To: Steven Rostedt, LKML Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Thomas Gleixner, Brown, Len, Adam Belay, Peter Zijlstra, Andi Kleen >-----Original Message----- >From: Steven Rostedt [mailto:rostedt@goodmis.org] >Sent: Wednesday, January 09, 2008 12:42 PM >To: LKML >Cc: Linus Torvalds; Andrew Morton; Ingo Molnar; Thomas >Gleixner; Brown, Len; Pallipadi, Venkatesh; Adam Belay; Peter >Zijlstra; Andi Kleen >Subject: [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait > >This patch is different than the first patch I sent out. >This one just sends an IPI to all CPUS that don't check in after 1 sec. > > >Sometimes cpu_idle_wait gets stuck because it might miss CPUS that are >already in idle, have no tasks waiting to run and have no interrupts >going to them. This is common on bootup when switching cpu idle >governors. > >This patch gives those CPUS that don't check in an IPI kick. > I think your RFC patch is the right solution here. As I see it, there is no race with your RFC patch. As long as you call a dummy smp_call_function on all CPUs, we should be OK. We can get rid of cpu_idle_state and the current wait forever logic altogether with dummy smp_call_function. And so there wont be any wait forever scenario. The whole point of cpu_idle_wait() is to make all CPUs come out of idle loop atleast once. The caller will use cpu_idle_wait something like this. // Want to change idle handler - Switch global idle handler to always present default_idle - call cpu_idle_wait so that all cpus come out of idle for an instant and stop using old idle pointer and start using default idle - Change the idle handler to a new handler - optional cpu_idle_wait if you want all cpus to start using the new handler immediately. May be the below 1s patch is safe bet for .24. But for .25, I would say we just replace all complicated logic by simple dummy smp_call_function and remove cpu_idle_state altogether. Thanks, Venki >Signed-off-by: Steven Rostedt <srostedt@redhat.com> >--- > arch/x86/kernel/process_32.c | 11 +++++++++++ > arch/x86/kernel/process_64.c | 11 +++++++++++ > 2 files changed, 22 insertions(+) > >Index: linux-compile-i386.git/arch/x86/kernel/process_32.c >=================================================================== >--- linux-compile-i386.git.orig/arch/x86/kernel/process_32.c >2008-01-09 14:09:36.000000000 -0500 >+++ linux-compile-i386.git/arch/x86/kernel/process_32.c >2008-01-09 14:09:45.000000000 -0500 >@@ -204,6 +204,10 @@ void cpu_idle(void) > } > } > >+static void do_nothing(void *unused) >+{ >+} >+ > void cpu_idle_wait(void) > { > unsigned int cpu, this_cpu = get_cpu(); >@@ -228,6 +232,13 @@ void cpu_idle_wait(void) > cpu_clear(cpu, map); > } > cpus_and(map, map, cpu_online_map); >+ /* >+ * We waited 1 sec, if a CPU still did not call idle >+ * it may be because it is in idle and not waking up >+ * because it has nothing to do. >+ * Give all the remaining CPUS a kick. >+ */ >+ smp_call_function_mask(map, do_nothing, 0, 0); > } while (!cpus_empty(map)); > > set_cpus_allowed(current, tmp); >Index: linux-compile-i386.git/arch/x86/kernel/process_64.c >=================================================================== >--- linux-compile-i386.git.orig/arch/x86/kernel/process_64.c >2008-01-09 14:09:36.000000000 -0500 >+++ linux-compile-i386.git/arch/x86/kernel/process_64.c >2008-01-09 15:17:20.000000000 -0500 >@@ -135,6 +135,10 @@ static void poll_idle (void) > cpu_relax(); > } > >+static void do_nothing(void *unused) >+{ >+} >+ > void cpu_idle_wait(void) > { > unsigned int cpu, this_cpu = get_cpu(); >@@ -160,6 +164,13 @@ void cpu_idle_wait(void) > cpu_clear(cpu, map); > } > cpus_and(map, map, cpu_online_map); >+ /* >+ * We waited 1 sec, if a CPU still did not call idle >+ * it may be because it is in idle and not waking up >+ * because it has nothing to do. >+ * Give all the remaining CPUS a kick. >+ */ >+ smp_call_function_mask(map, do_nothing, 0, 0); > } while (!cpus_empty(map)); > > set_cpus_allowed(current, tmp); > > > ^ permalink raw reply [flat|nested] 17+ messages in thread
[parent not found: <B5B0CFF685D7DF46A05CF1678CFB42ED20E00653@orsmsx423.amr.corp.intel.com>]
* [PATCH] x86: Simplify cpu_idle_wait [not found] ` <B5B0CFF685D7DF46A05CF1678CFB42ED20E00653@orsmsx423.amr.corp.intel.com> @ 2008-02-08 1:05 ` Venki Pallipadi 2008-02-08 10:28 ` Andi Kleen 0 siblings, 1 reply; 17+ messages in thread From: Venki Pallipadi @ 2008-02-08 1:05 UTC (permalink / raw) To: Andrew Morton Cc: Steven Rostedt, LKML, Linus Torvalds, Ingo Molnar, Thomas Gleixner, Brown, Len, Adam Belay, Peter Zijlstra, Andi Kleen Earlier commit 40d6a146629b98d8e322b6f9332b182c7cbff3df added smp_call_function in cpu_idle_wait() to kick cpus that are in tickless idle. Looking at cpu_idle_wait code at that time, code seemed to be over-engineered for a case which is rarely used (while changing idle handler). Below is a simplified version of cpu_idle_wait, which just makes a dummy smp_call_function to all cpus, to make them come out of old idle handler and start using the new idle handler. It eliminates code in the idle loop to handle cpu_idle_wait. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Index: linux-2.6.25-rc/arch/x86/kernel/process_32.c =================================================================== --- linux-2.6.25-rc.orig/arch/x86/kernel/process_32.c +++ linux-2.6.25-rc/arch/x86/kernel/process_32.c @@ -82,7 +82,6 @@ unsigned long thread_saved_pc(struct tas */ void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); -static DEFINE_PER_CPU(unsigned int, cpu_idle_state); void disable_hlt(void) { @@ -181,9 +180,6 @@ void cpu_idle(void) while (!need_resched()) { void (*idle)(void); - if (__get_cpu_var(cpu_idle_state)) - __get_cpu_var(cpu_idle_state) = 0; - check_pgt_cache(); rmb(); idle = pm_idle; @@ -208,40 +204,19 @@ static void do_nothing(void *unused) { } +/* + * cpu_idle_wait - Used to ensure that all the CPUs discard old value of + * pm_idle and update to new pm_idle value. Required while changing pm_idle + * handler on SMP systems. + * + * Caller must have changed pm_idle to the new value before the call. Old + * pm_idle value will not be used by any CPU after the return of this function. + */ void cpu_idle_wait(void) { - unsigned int cpu, this_cpu = get_cpu(); - cpumask_t map, tmp = current->cpus_allowed; - - set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); - put_cpu(); - - cpus_clear(map); - for_each_online_cpu(cpu) { - per_cpu(cpu_idle_state, cpu) = 1; - cpu_set(cpu, map); - } - - __get_cpu_var(cpu_idle_state) = 0; - - wmb(); - do { - ssleep(1); - for_each_online_cpu(cpu) { - if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) - cpu_clear(cpu, map); - } - cpus_and(map, map, cpu_online_map); - /* - * We waited 1 sec, if a CPU still did not call idle - * it may be because it is in idle and not waking up - * because it has nothing to do. - * Give all the remaining CPUS a kick. - */ - smp_call_function_mask(map, do_nothing, 0, 0); - } while (!cpus_empty(map)); - - set_cpus_allowed(current, tmp); + smp_mb(); + /* kick all the CPUs so that they exit out of pm_idle */ + smp_call_function(do_nothing, NULL, 0, 0); } EXPORT_SYMBOL_GPL(cpu_idle_wait); Index: linux-2.6.25-rc/arch/x86/kernel/process_64.c =================================================================== --- linux-2.6.25-rc.orig/arch/x86/kernel/process_64.c +++ linux-2.6.25-rc/arch/x86/kernel/process_64.c @@ -64,7 +64,6 @@ EXPORT_SYMBOL(boot_option_idle_override) */ void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); -static DEFINE_PER_CPU(unsigned int, cpu_idle_state); static ATOMIC_NOTIFIER_HEAD(idle_notifier); @@ -139,41 +138,19 @@ static void do_nothing(void *unused) { } +/* + * cpu_idle_wait - Used to ensure that all the CPUs discard old value of + * pm_idle and update to new pm_idle value. Required while changing pm_idle + * handler on SMP systems. + * + * Caller must have changed pm_idle to the new value before the call. Old + * pm_idle value will not be used by any CPU after the return of this function. + */ void cpu_idle_wait(void) { - unsigned int cpu, this_cpu = get_cpu(); - cpumask_t map, tmp = current->cpus_allowed; - - set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); - put_cpu(); - - cpus_clear(map); - for_each_online_cpu(cpu) { - per_cpu(cpu_idle_state, cpu) = 1; - cpu_set(cpu, map); - } - - __get_cpu_var(cpu_idle_state) = 0; - - wmb(); - do { - ssleep(1); - for_each_online_cpu(cpu) { - if (cpu_isset(cpu, map) && - !per_cpu(cpu_idle_state, cpu)) - cpu_clear(cpu, map); - } - cpus_and(map, map, cpu_online_map); - /* - * We waited 1 sec, if a CPU still did not call idle - * it may be because it is in idle and not waking up - * because it has nothing to do. - * Give all the remaining CPUS a kick. - */ - smp_call_function_mask(map, do_nothing, 0, 0); - } while (!cpus_empty(map)); - - set_cpus_allowed(current, tmp); + smp_mb(); + /* kick all the CPUs so that they exit out of pm_idle */ + smp_call_function(do_nothing, NULL, 0, 0); } EXPORT_SYMBOL_GPL(cpu_idle_wait); @@ -215,9 +192,6 @@ void cpu_idle (void) while (!need_resched()) { void (*idle)(void); - if (__get_cpu_var(cpu_idle_state)) - __get_cpu_var(cpu_idle_state) = 0; - tick_nohz_stop_sched_tick(); rmb(); ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] x86: Simplify cpu_idle_wait 2008-02-08 1:05 ` [PATCH] x86: Simplify cpu_idle_wait Venki Pallipadi @ 2008-02-08 10:28 ` Andi Kleen 2008-02-08 17:24 ` Venki Pallipadi 0 siblings, 1 reply; 17+ messages in thread From: Andi Kleen @ 2008-02-08 10:28 UTC (permalink / raw) To: Venki Pallipadi Cc: Andrew Morton, Steven Rostedt, LKML, Linus Torvalds, Ingo Molnar, Thomas Gleixner, Brown, Len, Adam Belay, Peter Zijlstra > - set_cpus_allowed(current, tmp); > + smp_mb(); > + /* kick all the CPUs so that they exit out of pm_idle */ > + smp_call_function(do_nothing, NULL, 0, 0); I think the last argument (wait) needs to be 1 to make sure it is synchronous (for 32/64) Otherwise the patch looks great. -Andi ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] x86: Simplify cpu_idle_wait 2008-02-08 10:28 ` Andi Kleen @ 2008-02-08 17:24 ` Venki Pallipadi 2008-02-08 18:45 ` Andi Kleen 2008-02-09 9:33 ` Thomas Gleixner 0 siblings, 2 replies; 17+ messages in thread From: Venki Pallipadi @ 2008-02-08 17:24 UTC (permalink / raw) To: Andi Kleen Cc: Venki Pallipadi, Andrew Morton, Steven Rostedt, LKML, Linus Torvalds, Ingo Molnar, Thomas Gleixner, Brown, Len, Adam Belay, Peter Zijlstra On Fri, Feb 08, 2008 at 11:28:48AM +0100, Andi Kleen wrote: > > > - set_cpus_allowed(current, tmp); > > + smp_mb(); > > + /* kick all the CPUs so that they exit out of pm_idle */ > > + smp_call_function(do_nothing, NULL, 0, 0); > > I think the last argument (wait) needs to be 1 to make sure it is > synchronous (for 32/64) Otherwise the patch looks great. Yes. Below is the updated patch Earlier commit 40d6a146629b98d8e322b6f9332b182c7cbff3df added smp_call_function in cpu_idle_wait() to kick cpus that are in tickless idle. Looking at cpu_idle_wait code at that time, code seemed to be over-engineered for a case which is rarely used (while changing idle handler). Below is a simplified version of cpu_idle_wait, which just makes a dummy smp_call_function to all cpus, to make them come out of old idle handler and start using the new idle handler. It eliminates code in the idle loop to handle cpu_idle_wait. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Index: linux-2.6.25-rc/arch/x86/kernel/process_32.c =================================================================== --- linux-2.6.25-rc.orig/arch/x86/kernel/process_32.c +++ linux-2.6.25-rc/arch/x86/kernel/process_32.c @@ -82,7 +82,6 @@ unsigned long thread_saved_pc(struct tas */ void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); -static DEFINE_PER_CPU(unsigned int, cpu_idle_state); void disable_hlt(void) { @@ -181,9 +180,6 @@ void cpu_idle(void) while (!need_resched()) { void (*idle)(void); - if (__get_cpu_var(cpu_idle_state)) - __get_cpu_var(cpu_idle_state) = 0; - check_pgt_cache(); rmb(); idle = pm_idle; @@ -208,40 +204,19 @@ static void do_nothing(void *unused) { } +/* + * cpu_idle_wait - Used to ensure that all the CPUs discard old value of + * pm_idle and update to new pm_idle value. Required while changing pm_idle + * handler on SMP systems. + * + * Caller must have changed pm_idle to the new value before the call. Old + * pm_idle value will not be used by any CPU after the return of this function. + */ void cpu_idle_wait(void) { - unsigned int cpu, this_cpu = get_cpu(); - cpumask_t map, tmp = current->cpus_allowed; - - set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); - put_cpu(); - - cpus_clear(map); - for_each_online_cpu(cpu) { - per_cpu(cpu_idle_state, cpu) = 1; - cpu_set(cpu, map); - } - - __get_cpu_var(cpu_idle_state) = 0; - - wmb(); - do { - ssleep(1); - for_each_online_cpu(cpu) { - if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) - cpu_clear(cpu, map); - } - cpus_and(map, map, cpu_online_map); - /* - * We waited 1 sec, if a CPU still did not call idle - * it may be because it is in idle and not waking up - * because it has nothing to do. - * Give all the remaining CPUS a kick. - */ - smp_call_function_mask(map, do_nothing, 0, 0); - } while (!cpus_empty(map)); - - set_cpus_allowed(current, tmp); + smp_mb(); + /* kick all the CPUs so that they exit out of pm_idle */ + smp_call_function(do_nothing, NULL, 0, 1); } EXPORT_SYMBOL_GPL(cpu_idle_wait); Index: linux-2.6.25-rc/arch/x86/kernel/process_64.c =================================================================== --- linux-2.6.25-rc.orig/arch/x86/kernel/process_64.c +++ linux-2.6.25-rc/arch/x86/kernel/process_64.c @@ -64,7 +64,6 @@ EXPORT_SYMBOL(boot_option_idle_override) */ void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); -static DEFINE_PER_CPU(unsigned int, cpu_idle_state); static ATOMIC_NOTIFIER_HEAD(idle_notifier); @@ -139,41 +138,19 @@ static void do_nothing(void *unused) { } +/* + * cpu_idle_wait - Used to ensure that all the CPUs discard old value of + * pm_idle and update to new pm_idle value. Required while changing pm_idle + * handler on SMP systems. + * + * Caller must have changed pm_idle to the new value before the call. Old + * pm_idle value will not be used by any CPU after the return of this function. + */ void cpu_idle_wait(void) { - unsigned int cpu, this_cpu = get_cpu(); - cpumask_t map, tmp = current->cpus_allowed; - - set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); - put_cpu(); - - cpus_clear(map); - for_each_online_cpu(cpu) { - per_cpu(cpu_idle_state, cpu) = 1; - cpu_set(cpu, map); - } - - __get_cpu_var(cpu_idle_state) = 0; - - wmb(); - do { - ssleep(1); - for_each_online_cpu(cpu) { - if (cpu_isset(cpu, map) && - !per_cpu(cpu_idle_state, cpu)) - cpu_clear(cpu, map); - } - cpus_and(map, map, cpu_online_map); - /* - * We waited 1 sec, if a CPU still did not call idle - * it may be because it is in idle and not waking up - * because it has nothing to do. - * Give all the remaining CPUS a kick. - */ - smp_call_function_mask(map, do_nothing, 0, 0); - } while (!cpus_empty(map)); - - set_cpus_allowed(current, tmp); + smp_mb(); + /* kick all the CPUs so that they exit out of pm_idle */ + smp_call_function(do_nothing, NULL, 0, 1); } EXPORT_SYMBOL_GPL(cpu_idle_wait); @@ -215,9 +192,6 @@ void cpu_idle (void) while (!need_resched()) { void (*idle)(void); - if (__get_cpu_var(cpu_idle_state)) - __get_cpu_var(cpu_idle_state) = 0; - tick_nohz_stop_sched_tick(); rmb(); ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] x86: Simplify cpu_idle_wait 2008-02-08 17:24 ` Venki Pallipadi @ 2008-02-08 18:45 ` Andi Kleen 2008-02-09 9:33 ` Thomas Gleixner 1 sibling, 0 replies; 17+ messages in thread From: Andi Kleen @ 2008-02-08 18:45 UTC (permalink / raw) To: Venki Pallipadi Cc: Andi Kleen, Andrew Morton, Steven Rostedt, LKML, Linus Torvalds, Ingo Molnar, Thomas Gleixner, Brown, Len, Adam Belay, Peter Zijlstra On Fri, Feb 08, 2008 at 09:24:30AM -0800, Venki Pallipadi wrote: > On Fri, Feb 08, 2008 at 11:28:48AM +0100, Andi Kleen wrote: > > > > > - set_cpus_allowed(current, tmp); > > > + smp_mb(); > > > + /* kick all the CPUs so that they exit out of pm_idle */ > > > + smp_call_function(do_nothing, NULL, 0, 0); > > > > I think the last argument (wait) needs to be 1 to make sure it is > > synchronous (for 32/64) Otherwise the patch looks great. > > Yes. Below is the updated patch Acked-by: Andi Kleen <ak@suse.de> -Andi ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] x86: Simplify cpu_idle_wait 2008-02-08 17:24 ` Venki Pallipadi 2008-02-08 18:45 ` Andi Kleen @ 2008-02-09 9:33 ` Thomas Gleixner 2008-04-10 16:49 ` Venki Pallipadi 1 sibling, 1 reply; 17+ messages in thread From: Thomas Gleixner @ 2008-02-09 9:33 UTC (permalink / raw) To: Venki Pallipadi Cc: Andi Kleen, Andrew Morton, Steven Rostedt, LKML, Linus Torvalds, Ingo Molnar, Brown, Len, Adam Belay, Peter Zijlstra On Fri, 8 Feb 2008, Venki Pallipadi wrote: > On Fri, Feb 08, 2008 at 11:28:48AM +0100, Andi Kleen wrote: > > > > > - set_cpus_allowed(current, tmp); > > > + smp_mb(); > > > + /* kick all the CPUs so that they exit out of pm_idle */ > > > + smp_call_function(do_nothing, NULL, 0, 0); > > > > I think the last argument (wait) needs to be 1 to make sure it is > > synchronous (for 32/64) Otherwise the patch looks great. > > Yes. Below is the updated patch Applied. Thanks, tglx > Earlier commit 40d6a146629b98d8e322b6f9332b182c7cbff3df > added smp_call_function in cpu_idle_wait() to kick cpus that are in tickless > idle. Looking at cpu_idle_wait code at that time, code seemed to be > over-engineered for a case which is rarely used (while changing idle handler). > > Below is a simplified version of cpu_idle_wait, which just makes > a dummy smp_call_function to all cpus, to make them come out of old idle handler > and start using the new idle handler. It eliminates code in the idle loop > to handle cpu_idle_wait. > > Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> > > Index: linux-2.6.25-rc/arch/x86/kernel/process_32.c > =================================================================== > --- linux-2.6.25-rc.orig/arch/x86/kernel/process_32.c > +++ linux-2.6.25-rc/arch/x86/kernel/process_32.c > @@ -82,7 +82,6 @@ unsigned long thread_saved_pc(struct tas > */ > void (*pm_idle)(void); > EXPORT_SYMBOL(pm_idle); > -static DEFINE_PER_CPU(unsigned int, cpu_idle_state); > > void disable_hlt(void) > { > @@ -181,9 +180,6 @@ void cpu_idle(void) > while (!need_resched()) { > void (*idle)(void); > > - if (__get_cpu_var(cpu_idle_state)) > - __get_cpu_var(cpu_idle_state) = 0; > - > check_pgt_cache(); > rmb(); > idle = pm_idle; > @@ -208,40 +204,19 @@ static void do_nothing(void *unused) > { > } > > +/* > + * cpu_idle_wait - Used to ensure that all the CPUs discard old value of > + * pm_idle and update to new pm_idle value. Required while changing pm_idle > + * handler on SMP systems. > + * > + * Caller must have changed pm_idle to the new value before the call. Old > + * pm_idle value will not be used by any CPU after the return of this function. > + */ > void cpu_idle_wait(void) > { > - unsigned int cpu, this_cpu = get_cpu(); > - cpumask_t map, tmp = current->cpus_allowed; > - > - set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); > - put_cpu(); > - > - cpus_clear(map); > - for_each_online_cpu(cpu) { > - per_cpu(cpu_idle_state, cpu) = 1; > - cpu_set(cpu, map); > - } > - > - __get_cpu_var(cpu_idle_state) = 0; > - > - wmb(); > - do { > - ssleep(1); > - for_each_online_cpu(cpu) { > - if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) > - cpu_clear(cpu, map); > - } > - cpus_and(map, map, cpu_online_map); > - /* > - * We waited 1 sec, if a CPU still did not call idle > - * it may be because it is in idle and not waking up > - * because it has nothing to do. > - * Give all the remaining CPUS a kick. > - */ > - smp_call_function_mask(map, do_nothing, 0, 0); > - } while (!cpus_empty(map)); > - > - set_cpus_allowed(current, tmp); > + smp_mb(); > + /* kick all the CPUs so that they exit out of pm_idle */ > + smp_call_function(do_nothing, NULL, 0, 1); > } > EXPORT_SYMBOL_GPL(cpu_idle_wait); > > Index: linux-2.6.25-rc/arch/x86/kernel/process_64.c > =================================================================== > --- linux-2.6.25-rc.orig/arch/x86/kernel/process_64.c > +++ linux-2.6.25-rc/arch/x86/kernel/process_64.c > @@ -64,7 +64,6 @@ EXPORT_SYMBOL(boot_option_idle_override) > */ > void (*pm_idle)(void); > EXPORT_SYMBOL(pm_idle); > -static DEFINE_PER_CPU(unsigned int, cpu_idle_state); > > static ATOMIC_NOTIFIER_HEAD(idle_notifier); > > @@ -139,41 +138,19 @@ static void do_nothing(void *unused) > { > } > > +/* > + * cpu_idle_wait - Used to ensure that all the CPUs discard old value of > + * pm_idle and update to new pm_idle value. Required while changing pm_idle > + * handler on SMP systems. > + * > + * Caller must have changed pm_idle to the new value before the call. Old > + * pm_idle value will not be used by any CPU after the return of this function. > + */ > void cpu_idle_wait(void) > { > - unsigned int cpu, this_cpu = get_cpu(); > - cpumask_t map, tmp = current->cpus_allowed; > - > - set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); > - put_cpu(); > - > - cpus_clear(map); > - for_each_online_cpu(cpu) { > - per_cpu(cpu_idle_state, cpu) = 1; > - cpu_set(cpu, map); > - } > - > - __get_cpu_var(cpu_idle_state) = 0; > - > - wmb(); > - do { > - ssleep(1); > - for_each_online_cpu(cpu) { > - if (cpu_isset(cpu, map) && > - !per_cpu(cpu_idle_state, cpu)) > - cpu_clear(cpu, map); > - } > - cpus_and(map, map, cpu_online_map); > - /* > - * We waited 1 sec, if a CPU still did not call idle > - * it may be because it is in idle and not waking up > - * because it has nothing to do. > - * Give all the remaining CPUS a kick. > - */ > - smp_call_function_mask(map, do_nothing, 0, 0); > - } while (!cpus_empty(map)); > - > - set_cpus_allowed(current, tmp); > + smp_mb(); > + /* kick all the CPUs so that they exit out of pm_idle */ > + smp_call_function(do_nothing, NULL, 0, 1); > } > EXPORT_SYMBOL_GPL(cpu_idle_wait); > > @@ -215,9 +192,6 @@ void cpu_idle (void) > while (!need_resched()) { > void (*idle)(void); > > - if (__get_cpu_var(cpu_idle_state)) > - __get_cpu_var(cpu_idle_state) = 0; > - > tick_nohz_stop_sched_tick(); > > rmb(); > ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH] x86: Simplify cpu_idle_wait 2008-02-09 9:33 ` Thomas Gleixner @ 2008-04-10 16:49 ` Venki Pallipadi 0 siblings, 0 replies; 17+ messages in thread From: Venki Pallipadi @ 2008-04-10 16:49 UTC (permalink / raw) To: Thomas Gleixner Cc: Pallipadi, Venkatesh, Andi Kleen, Andrew Morton, Steven Rostedt, LKML, Linus Torvalds, Ingo Molnar, Brown, Len, Adam Belay, Peter Zijlstra, Len Brown, rjw On Sat, Feb 09, 2008 at 02:33:21AM -0700, Thomas Gleixner wrote: > On Fri, 8 Feb 2008, Venki Pallipadi wrote: > > > On Fri, Feb 08, 2008 at 11:28:48AM +0100, Andi Kleen wrote: > > > > > > > - set_cpus_allowed(current, tmp); > > > > + smp_mb(); > > > > + /* kick all the CPUs so that they exit out of pm_idle */ > > > > + smp_call_function(do_nothing, NULL, 0, 0); > > > > > > I think the last argument (wait) needs to be 1 to make sure it is > > > synchronous (for 32/64) Otherwise the patch looks great. > > > > Yes. Below is the updated patch > > Applied. Thanks, > > tglx thomas/ingo/hpa, Looks like this patch never made it to mainline. The earlier patch does not apply cleanly to mainline any more. Below is the updated patch. Thanks, Venki As a bonus, this patch seems to resolve the bug reported here http://bugzilla.kernel.org/show_bug.cgi?id=10093 The bug was causing once-in-few-reboots 10-15 sec wait during boot on certain laptops. Earlier commit 40d6a146629b98d8e322b6f9332b182c7cbff3df added smp_call_function in cpu_idle_wait() to kick cpus that are in tickless idle. Looking at cpu_idle_wait code at that time, code seemed to be over-engineered for a case which is rarely used (while changing idle handler). Below is a simplified version of cpu_idle_wait, which just makes a dummy smp_call_function to all cpus, to make them come out of old idle handler and start using the new idle handler. It eliminates code in the idle loop to handle cpu_idle_wait. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> --- arch/x86/kernel/process_32.c | 47 ++++++++++--------------------------------- arch/x86/kernel/process_64.c | 47 ++++++++++--------------------------------- 2 files changed, 22 insertions(+), 72 deletions(-) Index: linux-2.6/arch/x86/kernel/process_32.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/process_32.c 2008-03-24 04:40:54.000000000 -0700 +++ linux-2.6/arch/x86/kernel/process_32.c 2008-04-09 10:06:03.000000000 -0700 @@ -82,7 +82,6 @@ unsigned long thread_saved_pc(struct tas */ void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); -static DEFINE_PER_CPU(unsigned int, cpu_idle_state); void disable_hlt(void) { @@ -190,9 +189,6 @@ void cpu_idle(void) while (!need_resched()) { void (*idle)(void); - if (__get_cpu_var(cpu_idle_state)) - __get_cpu_var(cpu_idle_state) = 0; - check_pgt_cache(); rmb(); idle = pm_idle; @@ -220,40 +216,19 @@ static void do_nothing(void *unused) { } +/* + * cpu_idle_wait - Used to ensure that all the CPUs discard old value of + * pm_idle and update to new pm_idle value. Required while changing pm_idle + * handler on SMP systems. + * + * Caller must have changed pm_idle to the new value before the call. Old + * pm_idle value will not be used by any CPU after the return of this function. + */ void cpu_idle_wait(void) { - unsigned int cpu, this_cpu = get_cpu(); - cpumask_t map, tmp = current->cpus_allowed; - - set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); - put_cpu(); - - cpus_clear(map); - for_each_online_cpu(cpu) { - per_cpu(cpu_idle_state, cpu) = 1; - cpu_set(cpu, map); - } - - __get_cpu_var(cpu_idle_state) = 0; - - wmb(); - do { - ssleep(1); - for_each_online_cpu(cpu) { - if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) - cpu_clear(cpu, map); - } - cpus_and(map, map, cpu_online_map); - /* - * We waited 1 sec, if a CPU still did not call idle - * it may be because it is in idle and not waking up - * because it has nothing to do. - * Give all the remaining CPUS a kick. - */ - smp_call_function_mask(map, do_nothing, NULL, 0); - } while (!cpus_empty(map)); - - set_cpus_allowed(current, tmp); + smp_mb(); + /* kick all the CPUs so that they exit out of pm_idle */ + smp_call_function(do_nothing, NULL, 0, 1); } EXPORT_SYMBOL_GPL(cpu_idle_wait); Index: linux-2.6/arch/x86/kernel/process_64.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/process_64.c 2008-03-24 04:40:54.000000000 -0700 +++ linux-2.6/arch/x86/kernel/process_64.c 2008-04-09 10:07:48.000000000 -0700 @@ -63,7 +63,6 @@ EXPORT_SYMBOL(boot_option_idle_override) */ void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); -static DEFINE_PER_CPU(unsigned int, cpu_idle_state); static ATOMIC_NOTIFIER_HEAD(idle_notifier); @@ -173,9 +172,6 @@ void cpu_idle(void) while (!need_resched()) { void (*idle)(void); - if (__get_cpu_var(cpu_idle_state)) - __get_cpu_var(cpu_idle_state) = 0; - rmb(); idle = pm_idle; if (!idle) @@ -207,40 +203,19 @@ static void do_nothing(void *unused) { } +/* + * cpu_idle_wait - Used to ensure that all the CPUs discard old value of + * pm_idle and update to new pm_idle value. Required while changing pm_idle + * handler on SMP systems. + * + * Caller must have changed pm_idle to the new value before the call. Old + * pm_idle value will not be used by any CPU after the return of this function. + */ void cpu_idle_wait(void) { - unsigned int cpu, this_cpu = get_cpu(); - cpumask_t map, tmp = current->cpus_allowed; - - set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); - put_cpu(); - - cpus_clear(map); - for_each_online_cpu(cpu) { - per_cpu(cpu_idle_state, cpu) = 1; - cpu_set(cpu, map); - } - - __get_cpu_var(cpu_idle_state) = 0; - - wmb(); - do { - ssleep(1); - for_each_online_cpu(cpu) { - if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) - cpu_clear(cpu, map); - } - cpus_and(map, map, cpu_online_map); - /* - * We waited 1 sec, if a CPU still did not call idle - * it may be because it is in idle and not waking up - * because it has nothing to do. - * Give all the remaining CPUS a kick. - */ - smp_call_function_mask(map, do_nothing, 0, 0); - } while (!cpus_empty(map)); - - set_cpus_allowed(current, tmp); + smp_mb(); + /* kick all the CPUs so that they exit out of pm_idle */ + smp_call_function(do_nothing, NULL, 0, 1); } EXPORT_SYMBOL_GPL(cpu_idle_wait); ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2008-04-10 16:55 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2008-01-08 2:27 [RFC PATCH] kick sleeping idle CPUS on cpu_idle_wait Steven Rostedt 2008-01-08 3:33 ` Andi Kleen 2008-01-09 20:42 ` [PATCH] Kick CPUS that might be sleeping in cpus_idle_wait Steven Rostedt 2008-01-09 22:12 ` Steven Rostedt 2008-01-10 13:45 ` Ingo Molnar 2008-01-10 14:43 ` Steven Rostedt 2008-01-10 17:31 ` Pallipadi, Venkatesh 2008-01-10 18:03 ` Steven Rostedt 2008-01-09 23:42 ` Andrew Morton 2008-01-10 0:05 ` Steven Rostedt 2008-01-10 0:12 ` Pallipadi, Venkatesh [not found] ` <B5B0CFF685D7DF46A05CF1678CFB42ED20E00653@orsmsx423.amr.corp.intel.com> 2008-02-08 1:05 ` [PATCH] x86: Simplify cpu_idle_wait Venki Pallipadi 2008-02-08 10:28 ` Andi Kleen 2008-02-08 17:24 ` Venki Pallipadi 2008-02-08 18:45 ` Andi Kleen 2008-02-09 9:33 ` Thomas Gleixner 2008-04-10 16:49 ` Venki Pallipadi
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).