public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Fix WARN_ON / WARN_ON_ONCE regression
@ 2006-10-03 23:04 Tim Chen
  2006-10-03 23:19 ` Tim Chen
                   ` (2 more replies)
  0 siblings, 3 replies; 44+ messages in thread
From: Tim Chen @ 2006-10-03 23:04 UTC (permalink / raw)
  To: herbert, akpm; +Cc: linux-kernel, leonid.ananiev

Hi Herbet,

The patch "Let WARN_ON/WARN_ON_ONCE return the condition"
http://kernel.org/git/?
p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=684f978347deb42d180373ac4c427f82ef963171

introduced 40% more 2nd level cache miss to tbench workload
being run in a loop back mode on a Core 2 machine.  I think the
introduction of the local variables to WARN_ON and WARN_ON_ONCE

typeof(x) __ret_warn_on = (x);
typeof(condition) __ret_warn_once = (condition);

results in the extra cache misses.  In our test workload profile, we see
heavily used functions like do_softirq and local_bh_enable 
takes a lot longer to execute.  

The modification below helps fix the problem.  I made a slight
modification to sched.c to get around a gcc bug.

Signed-off-by: Tim Chen <tim.c.chen@intel.com>
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index a525089..05ed388 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -17,13 +17,12 @@ #endif
 
 #ifndef HAVE_ARCH_WARN_ON
 #define WARN_ON(condition)
({                                          \
-       typeof(condition) __ret_warn_on =
(condition);                  \
-       if (unlikely(__ret_warn_on))
{                                  \
+       if (unlikely(condition))
{                                      \
                printk("BUG: warning at %s:%d/%s()\n",
__FILE__,        \
                        __LINE__,
__FUNCTION__);                        \
                dump_stack
();                                           \
        }                                                               \
-       unlikely
(__ret_warn_on);                                        \
+       unlikely
(condition);                                            \
 })
 #endif
 
@@ -43,12 +42,16 @@ #endif
 
 #define WARN_ON_ONCE(condition)        ({                      \
        static int __warn_once = 1;                     \
-       typeof(condition) __ret_warn_once = (condition);\
                                                        \
-       if (likely(__warn_once))                        \
-               if (WARN_ON(__ret_warn_once))           \
-                       __warn_once = 0;                \
-       unlikely(__ret_warn_once);                      \
+       if (unlikely(condition)){                       \
+               if (likely(__warn_once)){               \
+                       __warn_once=0;                  \
+                       printk("BUG: warning at %s:%d/%s()\n", __FILE__,
\
+                               __LINE__, __FUNCTION__);\
+                       dump_stack();                   \
+               }                                       \
+       }                                               \
+       unlikely(condition);                            \
 })
 
 #ifdef CONFIG_SMP
diff --git a/kernel/sched.c b/kernel/sched.c
index 5c848fd..8ae972c 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -5629,7 +5629,8 @@ static unsigned long domain_distance(int
        struct sched_domain *sd;
 
        for_each_domain(cpu1, sd) {
-               WARN_ON(!cpu_isset(cpu1, sd->span));
+               if (unlikely(!cpu_isset(cpu1, sd->span)))
+                       WARN_ON(1);
                if (cpu_isset(cpu2, sd->span))
                        return distance;
                distance++;



^ permalink raw reply related	[flat|nested] 44+ messages in thread
* RE: [PATCH] Fix WARN_ON / WARN_ON_ONCE regression
@ 2006-10-04 16:57 Ananiev, Leonid I
  2006-10-04 17:28 ` Andrew Morton
  0 siblings, 1 reply; 44+ messages in thread
From: Ananiev, Leonid I @ 2006-10-04 16:57 UTC (permalink / raw)
  To: Andrew Morton, tim.c.chen; +Cc: Jeremy Fitzhardinge, herbert, linux-kernel

>Guys.  Please.  Help us out here.  None of this makes sense, and it's
> possible that we have an underlying problem in there which we need to
know
> about.
 This is explantion:

The static variable __warn_once was "never" read (until there is no bug)
before patch "Let WARN_ON/WARN_ON_ONCE return the condition"
http://kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commi
t;h=684f978347deb42d180373ac4c427f82ef963171
 in WARN_ON_ONCE's line 
- if (unlikely((condition) && __warn_once)) { \
because 'condition' is false. There was no cache miss as a result.

Cache miss for __warn_once is happened in new lines
+ if (likely(__warn_once)) \
+ if (WARN_ON(__ret_warn_once)) \

Proposed patch is tested by tbench.

>From Leonid Ananiev

Cache miss eliminating in WARN_ON_ONCE  by testing expression value
before static variable value.

Signed-off-by: Leonid Ananiev <leonid.i.ananiev@intel.com>
--- linux-2.6.18-git14/include/asm-generic/bug.h
+++ linux-2.6.18-git14b/include/asm-generic/bug.h
@@ -45,9 +45,12 @@
        static int __warn_once = 1;                     \
        typeof(condition) __ret_warn_once = (condition);\
                                                        \
-       if (likely(__warn_once))                        \
-               if (WARN_ON(__ret_warn_once))           \
+       /* check 'condition' first to avoid cache miss with __warn_once
*/\
+       if (unlikely(__ret_warn_once))                  \
+               if (__warn_once) {                      \
                        __warn_once = 0;                \
+                       WARN_ON(1);                     \
+               }                                       \
        unlikely(__ret_warn_once);                      \
 })
-----Original Message-----
From: Andrew Morton [mailto:akpm@osdl.org] 
Sent: Wednesday, October 04, 2006 8:30 PM
To: tim.c.chen@linux.intel.com
Cc: Jeremy Fitzhardinge; herbert@gondor.apana.org.au;
linux-kernel@vger.kernel.org; Ananiev, Leonid I
Subject: Re: [PATCH] Fix WARN_ON / WARN_ON_ONCE regression

On Wed, 04 Oct 2006 06:21:35 -0700
Tim Chen <tim.c.chen@linux.intel.com> wrote:

> On Tue, 2006-10-03 at 21:39 -0700, Jeremy Fitzhardinge wrote:
> 
> > 
> > I don't think you've proved your case here.  Do you *know* there are

> > extra cache misses (ie, measuring them), or is it just your theory
to 
> > explain a performance regression?
> > 
> 
> I have measured the cache miss with tool.  So it is not just my
theory.
> 

And what did that tool tell you?

Guys.  Please.  Help us out here.  None of this makes sense, and it's
possible that we have an underlying problem in there which we need to
know
about.

Please don't just ignore my questions.  *why* are we getting a cache
miss
rate on that integer which is causing measurable performance changes?
If
we're reading it that frequently then the variable should be in
cache(!).

Again: do you know which callsite is causing the problem?  I assume one
of
the ones in softirq.c?  Do you know what the cache miss frequency is?
etc.

Because if we don't answer these questions there's an excellent chance
that
the problem (whatever it is) will come back and bite us again.

^ permalink raw reply	[flat|nested] 44+ messages in thread
* RE: [PATCH] Fix WARN_ON / WARN_ON_ONCE regression
@ 2006-10-04 21:55 Ananiev, Leonid I
  2006-10-05 21:37 ` Andrew Morton
  0 siblings, 1 reply; 44+ messages in thread
From: Ananiev, Leonid I @ 2006-10-04 21:55 UTC (permalink / raw)
  To: Andrew Morton; +Cc: tim.c.chen, Jeremy Fitzhardinge, herbert, linux-kernel

> That's one cache miss.  One.  For the remainder of the benchmark,
> __warn_once is in cache and there are no more misses.  That's how
caches
> work ;)

Before patch for WARN_ON_ONCE we never had risk to get a cache miss for
__warn_once.
After patch we have.
> __warn_once is in cache and there are no more misses.
There is no insuerence that it is in the cache.

Next:
CPU 1Mb cache cache_alignment : 128  => -16% degradation of tbench
CPU 2Mb cache cache_alignment : 128  => -1%  degradation
CPU 4Mb cache cache_alignment : 64  => -70% degradation

An evictees depends from cache size and line size. last is more
essential in considered case.

Leonid
-----Original Message-----
From: Andrew Morton [mailto:akpm@osdl.org] 
Sent: Wednesday, October 04, 2006 9:28 PM
To: Ananiev, Leonid I
Cc: tim.c.chen@linux.intel.com; Jeremy Fitzhardinge;
herbert@gondor.apana.org.au; linux-kernel@vger.kernel.org
Subject: Re: [PATCH] Fix WARN_ON / WARN_ON_ONCE regression

On Wed, 4 Oct 2006 20:57:57 +0400
"Ananiev, Leonid I" <leonid.i.ananiev@intel.com> wrote:

> >Guys.  Please.  Help us out here.  None of this makes sense, and it's
> > possible that we have an underlying problem in there which we need
to
> know
> > about.
>  This is explantion:
> 
> The static variable __warn_once was "never" read (until there is no
bug)
> before patch "Let WARN_ON/WARN_ON_ONCE return the condition"
>
http://kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commi
> t;h=684f978347deb42d180373ac4c427f82ef963171
>  in WARN_ON_ONCE's line 
> - if (unlikely((condition) && __warn_once)) { \
> because 'condition' is false. There was no cache miss as a result.
> 
> Cache miss for __warn_once is happened in new lines
> + if (likely(__warn_once)) \
> + if (WARN_ON(__ret_warn_once)) \
> 

That's one cache miss.  One.  For the remainder of the benchmark,
__warn_once is in cache and there are no more misses.  That's how caches
work ;)

But it appears this isn't happening.  Why?

^ permalink raw reply	[flat|nested] 44+ messages in thread
* RE: [PATCH] Fix WARN_ON / WARN_ON_ONCE regression
@ 2006-10-06  4:06 Ananiev, Leonid I
  0 siblings, 0 replies; 44+ messages in thread
From: Ananiev, Leonid I @ 2006-10-06  4:06 UTC (permalink / raw)
  To: Andrew Morton; +Cc: tim.c.chen, Jeremy Fitzhardinge, herbert, linux-kernel

> Apparently due to the access to the
> newly-added static variable.

The cache miss was increased as a result of instructions reordering but
not due to the newly-added static variable. The original patch have
added local but not static variable. Newly-added local variable compiler
has placed in register.
The original patch made reordering of tests-register-and-jump and
test-memory-and-jump instructions. That was a side effect of the patch.
To watch closely ordering of 'if (a && b)' or 'if (b && a)' becomes more
weight than 'unlikely()' using if 'a' is in register and 'b' is in
memory. I would say: unlikely() cost is 10:1; ordering cost is 1000:1.

Leonid 

-----Original Message-----
From: Andrew Morton [mailto:akpm@osdl.org] 
Sent: Friday, October 06, 2006 1:38 AM
To: Ananiev, Leonid I
Cc: tim.c.chen@linux.intel.com; Jeremy Fitzhardinge;
herbert@gondor.apana.org.au; linux-kernel@vger.kernel.org
Subject: Re: [PATCH] Fix WARN_ON / WARN_ON_ONCE regression


So how's this look?

I worry a bit that someone's hardware might go and prefetch that static
variable even when we didn't ask it to.  Can that happen?




Tim and Ananiev report that the recent WARN_ON_ONCE changes cause
increased
cache misses with the tbench workload.  Apparently due to the access to
the
newly-added static variable.

Rearrange the code so that we don't touch that variable unless the
warning is
going to trigger.

Also rework the logic so that the static variable starts out at zero, so
we
can move it into bss.

It would seem logical to mark the static variable as __read_mostly too.
But
it would be wrong, because that would put it back into the vmlinux
image, and
the kernel will never read from this variable in normal operation
anyway. 
Unless the compiler or hardware go and do some prefetching on us?

For some reason this patch shrinks softirq.o text by 40 bytes.

Cc: Tim Chen <tim.c.chen@intel.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: "Ananiev, Leonid I" <leonid.i.ananiev@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 include/asm-generic/bug.h |   16 ++++++++--------
 1 files changed, 8 insertions(+), 8 deletions(-)

diff -puN include/asm-generic/bug.h~fix-warn_on--warn_on_once-regression
include/asm-generic/bug.h
--- a/include/asm-generic/bug.h~fix-warn_on--warn_on_once-regression
+++ a/include/asm-generic/bug.h
@@ -41,14 +41,14 @@
 #endif
 #endif
 
-#define WARN_ON_ONCE(condition)	({			\
-	static int __warn_once = 1;			\
-	typeof(condition) __ret_warn_once = (condition);\
-							\
-	if (likely(__warn_once))			\
-		if (WARN_ON(__ret_warn_once)) 		\
-			__warn_once = 0;		\
-	unlikely(__ret_warn_once);			\
+#define WARN_ON_ONCE(condition)	({
\
+	static int __warned;					\
+	typeof(condition) __ret_warn_once = (condition);	\
+								\
+	if (unlikely(__ret_warn_once))				\
+		if (WARN_ON(!__warned)) 			\
+			__warned = 1;				\
+	unlikely(__ret_warn_once);				\
 })
 
 #ifdef CONFIG_SMP
_

^ permalink raw reply	[flat|nested] 44+ messages in thread
* RE: [PATCH] Fix WARN_ON / WARN_ON_ONCE regression
@ 2006-10-10 21:05 Ananiev, Leonid I
  2006-10-10 21:17 ` Steven Rostedt
  0 siblings, 1 reply; 44+ messages in thread
From: Ananiev, Leonid I @ 2006-10-10 21:05 UTC (permalink / raw)
  To: Jeremy Fitzhardinge, Steven Rostedt
  Cc: tim.c.chen, Andrew Morton, herbert, linux-kernel



-----Original Message-----
From: Jeremy Fitzhardinge [mailto:jeremy@goop.org] 
Sent: Wednesday, October 11, 2006 12:04 AM
To: Steven Rostedt
Cc: tim.c.chen@linux.intel.com; Andrew Morton;
herbert@gondor.apana.org.au; linux-kernel@vger.kernel.org; Ananiev,
Leonid I
Subject: Re: [PATCH] Fix WARN_ON / WARN_ON_ONCE regression

Steven Rostedt wrote:
> Holy crap!  I wonder where else in the kernel gcc is doing this. 
Jeremy Fitzhardinge wrote:
> annotation which makes gcc consider writes to the variable relatively
expensive

I should underline that cache miss is a result of invalidating of cache
line with __warn_once in each other CPUs performed by hw for cache
coherence.
__warn_once is a common data. It is costly to test-and-modify it just in
SMP. But it is not costly to write to the variable in memory just after
reading it. As a compiler have understood source code. 
A read-and-modify for common variable are performed under lock usually.

Leonid

Steven Rostedt wrote:
> Holy crap!  I wonder where else in the kernel gcc is doing this. (of
> course I'm using gcc4 so I don't know).  Is there another gcc
attribute
> to actually tell gcc that a variable is really mostly read only
(besides
> placing it in a mostly read only elf section)?
>   

That would be nice, but I don't know of one (apart from "volatile", 
which has its own downsides).  Once could imagine an annotation which 
makes gcc consider writes to the variable relatively expensive, so that 
it avoids generating unnecessary/excessive writes.

    J

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2006-10-10 22:59 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-03 23:04 [PATCH] Fix WARN_ON / WARN_ON_ONCE regression Tim Chen
2006-10-03 23:19 ` Tim Chen
2006-10-04  0:06 ` Jeremy Fitzhardinge
2006-10-03 23:47   ` Tim Chen
2006-10-04  4:39     ` Jeremy Fitzhardinge
2006-10-04 13:21       ` Tim Chen
2006-10-04 16:30         ` Andrew Morton
2006-10-04 16:22           ` Tim Chen
2006-10-04 17:34             ` Andrew Morton
2006-10-04 20:43               ` Tim Chen
2006-10-10  1:09               ` Tim Chen
2006-10-10 13:04                 ` Steven Rostedt
2006-10-10 15:41                   ` Tim Chen
2006-10-10 20:03                   ` Jeremy Fitzhardinge
2006-10-04  0:07 ` Andrew Morton
2006-10-03 23:42   ` Tim Chen
2006-10-04  0:09   ` Tim Chen
2006-10-04  1:14     ` Andrew Morton
2006-10-04  1:47       ` Nick Piggin
2006-10-04  3:24       ` Andrew James Wade
2006-10-04  3:32         ` Andrew Morton
2006-10-04 16:47           ` Andrew James Wade
2006-10-04 22:06             ` Andrew Morton
2006-10-05  8:13               ` Andrew James Wade
2006-10-05  8:36                 ` Andrew Morton
2006-10-05 21:31                   ` Andrew James Wade
2006-10-05 21:01                     ` Tim Chen
  -- strict thread matches above, loose matches on Subject: below --
2006-10-04 16:57 Ananiev, Leonid I
2006-10-04 17:28 ` Andrew Morton
2006-10-08  0:28   ` Steven Rostedt
2006-10-08  0:39     ` Jeremy Fitzhardinge
2006-10-04 21:55 Ananiev, Leonid I
2006-10-05 21:37 ` Andrew Morton
2006-10-05 21:43   ` Jeremy Fitzhardinge
2006-10-05 21:52     ` Andrew Morton
2006-10-05 22:02       ` Herbert Xu
2006-10-05 22:40         ` Jeremy Fitzhardinge
2006-10-05 21:51   ` Tim Chen
2006-10-06 16:11   ` Andrew James Wade
2006-10-06  4:06 Ananiev, Leonid I
2006-10-10 21:05 Ananiev, Leonid I
2006-10-10 21:17 ` Steven Rostedt
2006-10-10 21:41   ` Roland Dreier
2006-10-10 22:59   ` Jeremy Fitzhardinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox