You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Bill Stoddard <bi...@wstoddard.com> on 2002/08/16 20:33:43 UTC

What evil lurks beneath macros... (an AIX xlc optimizer bug)

While trying to create a simple testcase demonstrating a bug in the xlc
compiler, I did a little experiment.  Here is a code snip from core.c:

<snip>
  /* Code from core.c */
  if (mode == AP_MODE_INIT) {
     return APR_SUCCESS;
  }
  if (!ctx)
  {
     ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
     ctx->b = apr_brigade_create(f->c->pool, f->c->bucket_alloc);

     e = apr_bucket_socket_create(net->client_socket, f->c->bucket_alloc);
     APR_BRIGADE_INSERT_TAIL(ctx->b, e);
     net->in_ctx = ctx;
  }
  else if (APR_BRIGADE_EMPTY(ctx->b)) {
     return APR_EOF;
  }
  avoid_xlc_bug(f->c->base_server);
  BRIGADE_NORMALIZE(ctx->b);
</snip>

And here is that same code with the macros unrolled. The xlc optimizer
chokes on this. avoid_xlc_bug() just returns 1 and does nothing else (and
makes the optimzer happy again). This is just nasty.

/* Code from core.c with macros unrolled. */
if (mode == AP_MODE_INIT) {
#line 3330
   return 0;
}
if (!ctx)
{
   ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
   ctx->b = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
#line 3339
   e = apr_bucket_socket_create(net->client_socket, f->c->bucket_alloc);
   do { apr_bucket *ap__b = (e); do { ((((ap__b))))->link.next = ((struct
apr_bucket
*)((char *)(((&(ctx->b)->list))) - ((l
ong) (((char *) (&(((struct apr_bucket*)0)->link))) - ((char *) 0)))));
((((ap__b))))->link.prev = (((struct apr_bucket *)((char
 *)(((&(ctx->b)->list))) - ((long) (((char *) (&(((struct
apr_bucket*)0)->link))) - ((char
*) 0))))))->link.prev; ((((struct apr
_bucket *)((char *)(((&(ctx->b)->list))) - ((long) (((char *) (&(((struct
apr_bucket*)0)->link))) - ((char *) 0))))))->link.prev
)->link.next = (((ap__b))); (((struct apr_bucket *)((char
*)(((&(ctx->b)->list))) -
((long) (((char *) (&(((struct apr_bucket*)0
)->link))) - ((char *) 0))))))->link.prev = (((ap__b))); } while (0); }
while (0);
        net->in_ctx = ctx;
    }
    else if ((((&(ctx->b)->list))->next == (struct apr_bucket *)((char
*)((&(ctx->b)->list)) - ((long) (((char *) (&(((struct ap
r_bucket*)0)->link))) - ((char *) 0)))))) {
        return ((20000 + 500) + 14);
    }

    avoid_xlc_bug(f->c->base_server);
#line 3350
    do { apr_bucket *e = (&(ctx->b)->list)->next; do { if (e->length == 0)
{ apr_bucket
*d; d = ((e))->link.next; do { do { ((((
(e))))->link.prev)->link.next = ((((e))))->link.next;
(((((e))))->link.next)->link.prev =
((((e))))->link.prev; } while (0); do
{ (e)->type->destroy((e)->data); (e)->free(e); } while (0); } while (0); e =
d; } e =
((e))->link.next; } while (!(((&(ctx->b)->
list))->next == (struct apr_bucket *)((char *)((&(ctx->b)->list)) - ((long)
(((char *)
(&(((struct apr_bucket*)0)->link))) - ((c
har *) 0))))) && (e != (struct apr_bucket *)((char *)(&(ctx->b)->list) -
((long) (((char
*) (&(((struct apr_bucket*)0)->link)))
- ((char *) 0)))))); } while (0);
#line 3358
    if ((((&(ctx->b)->list))->next == (struct apr_bucket *)((char
*)((&(ctx->b)->list)) -
((long) (((char *) (&(((struct apr_buc
ket*)0)->link))) - ((char *) 0)))))) {
        return ((20000 + 500) + 14);
    }
#line 3365


Re: What evil lurks beneath macros... (an AIX xlc optimizer bug)

Posted by Rodent of Unusual Size <Ke...@Golux.Com>.
Bill Stoddard wrote:
> 
> And here is that same code with the macros unrolled. The xlc
> optimizer chokes on this. This is just nasty.

/me vomits

I've hated the concealment of code inside these macros from
Day 1.  One or two lines of code in a macro, fine; functionality
like this.. megasuckage.
-- 
#ken	P-)}

Ken Coar, Sanagendamgagwedweinini  http://Golux.Com/coar/
Author, developer, opinionist      http://Apache-Server.Com/

"Millennium hand and shrimp!"

Re: What evil lurks beneath macros... (an AIX xlc optimizer bug)

Posted by Ryan Bloom <rb...@ntrnet.net>.
On Fri, 16 Aug 2002, Cliff Woolley wrote:

> On Fri, 16 Aug 2002, Ryan Bloom wrote:
> 
> > A better question IMHO, is whether any of those macros can be made less
> > complex.
> 
> It's a good question, but IMO the answer is no.  The ring macros are very
> tight and easy to read... like I said, they're about four lines each.
> The brigade macros are, for the most part, one line wrappers around those.
> I don't see how they could get any less complicated than they are.

The problem is that many of the macros are implemented in terms of other
macros.  For example, the INSERT_TAIL macro seems overly complex.  It may
not be, but it is not the easiest macro to chase down.

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
550 Jean St
Oakland CA 94610
-------------------------------------------------------------------------------


Re: What evil lurks beneath macros... (an AIX xlc optimizer bug)

Posted by Cliff Woolley <jw...@virginia.edu>.
On Fri, 16 Aug 2002, Ryan Bloom wrote:

> A better question IMHO, is whether any of those macros can be made less
> complex.

It's a good question, but IMO the answer is no.  The ring macros are very
tight and easy to read... like I said, they're about four lines each.
The brigade macros are, for the most part, one line wrappers around those.
I don't see how they could get any less complicated than they are.

--Cliff


Re: What evil lurks beneath macros... (an AIX xlc optimizer bug)

Posted by Ryan Bloom <rb...@ntrnet.net>.
On Fri, 16 Aug 2002, Cliff Woolley wrote:

> On Fri, 16 Aug 2002, Ian Holsman wrote:
> 
> > I'm just wondering if there is any kind of measureable performance
> > benefit in keeping these as a macro vs putting them in a  function
> > (possibly inline if the compiler can support it).
> 
> I'm quite sure there is a performance benefit, though admittedly I don't
> have numbers on hand to support that at the moment.
> 
> It's as simple as this: many of the operations, once you get rid of the
> typecasts and other noise, optimize down to just a few adds/subtracts and
> a few assignments.  Four lines of code in most cases.  Adding the overhead
> of a function call (actually probably two or three function calls) for
> each operation would be substantial.
> 
> It just looks messy when you expand the macros because it all gets
> squished on one line and because lots of noise gets shoved in.  But you
> could say that about most macros when read in fully expanded form.

I agree 100%.  These macros are relatively simple, just doing a bunch of
casting and pointer manipulation.  The cost of putting those in functions
would most likely be very high.  A better question IMHO, is whether any of
those macros can be made less complex.

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
550 Jean St
Oakland CA 94610
-------------------------------------------------------------------------------


Re: What evil lurks beneath macros... (an AIX xlc optimizer bug)

Posted by Cliff Woolley <jw...@virginia.edu>.
On Fri, 16 Aug 2002, Ian Holsman wrote:

> I'm just wondering if there is any kind of measureable performance
> benefit in keeping these as a macro vs putting them in a  function
> (possibly inline if the compiler can support it).

I'm quite sure there is a performance benefit, though admittedly I don't
have numbers on hand to support that at the moment.

It's as simple as this: many of the operations, once you get rid of the
typecasts and other noise, optimize down to just a few adds/subtracts and
a few assignments.  Four lines of code in most cases.  Adding the overhead
of a function call (actually probably two or three function calls) for
each operation would be substantial.

It just looks messy when you expand the macros because it all gets
squished on one line and because lots of noise gets shoved in.  But you
could say that about most macros when read in fully expanded form.

--Cliff


Re: What evil lurks beneath macros... (an AIX xlc optimizer bug)

Posted by Ian Holsman <ia...@apache.org>.
Bill Stoddard wrote:
> While trying to create a simple testcase demonstrating a bug in the xlc
> compiler, I did a little experiment.  Here is a code snip from core.c:
> 

I'm just wondering if there is any kind of measureable performance 
benefit in keeping these as a macro vs putting them in a  function 
(possibly inline if the compiler can support it).
> <snip>
>   /* Code from core.c */
>   if (mode == AP_MODE_INIT) {
>      return APR_SUCCESS;
>   }
>   if (!ctx)
>   {
>      ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
>      ctx->b = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
> 
>      e = apr_bucket_socket_create(net->client_socket, f->c->bucket_alloc);
>      APR_BRIGADE_INSERT_TAIL(ctx->b, e);
>      net->in_ctx = ctx;
>   }
>   else if (APR_BRIGADE_EMPTY(ctx->b)) {
>      return APR_EOF;
>   }
>   avoid_xlc_bug(f->c->base_server);
>   BRIGADE_NORMALIZE(ctx->b);
> </snip>
> 
> And here is that same code with the macros unrolled. The xlc optimizer
> chokes on this. avoid_xlc_bug() just returns 1 and does nothing else (and
> makes the optimzer happy again). This is just nasty.
> 
> /* Code from core.c with macros unrolled. */
> if (mode == AP_MODE_INIT) {
> #line 3330
>    return 0;
> }
> if (!ctx)
> {
>    ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
>    ctx->b = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
> #line 3339
>    e = apr_bucket_socket_create(net->client_socket, f->c->bucket_alloc);
>    do { apr_bucket *ap__b = (e); do { ((((ap__b))))->link.next = ((struct
> apr_bucket
> *)((char *)(((&(ctx->b)->list))) - ((l
> ong) (((char *) (&(((struct apr_bucket*)0)->link))) - ((char *) 0)))));
> ((((ap__b))))->link.prev = (((struct apr_bucket *)((char
>  *)(((&(ctx->b)->list))) - ((long) (((char *) (&(((struct
> apr_bucket*)0)->link))) - ((char
> *) 0))))))->link.prev; ((((struct apr
> _bucket *)((char *)(((&(ctx->b)->list))) - ((long) (((char *) (&(((struct
> apr_bucket*)0)->link))) - ((char *) 0))))))->link.prev
> )->link.next = (((ap__b))); (((struct apr_bucket *)((char
> *)(((&(ctx->b)->list))) -
> ((long) (((char *) (&(((struct apr_bucket*)0
> )->link))) - ((char *) 0))))))->link.prev = (((ap__b))); } while (0); }
> while (0);
>         net->in_ctx = ctx;
>     }
>     else if ((((&(ctx->b)->list))->next == (struct apr_bucket *)((char
> *)((&(ctx->b)->list)) - ((long) (((char *) (&(((struct ap
> r_bucket*)0)->link))) - ((char *) 0)))))) {
>         return ((20000 + 500) + 14);
>     }
> 
>     avoid_xlc_bug(f->c->base_server);
> #line 3350
>     do { apr_bucket *e = (&(ctx->b)->list)->next; do { if (e->length == 0)
> { apr_bucket
> *d; d = ((e))->link.next; do { do { ((((
> (e))))->link.prev)->link.next = ((((e))))->link.next;
> (((((e))))->link.next)->link.prev =
> ((((e))))->link.prev; } while (0); do
> { (e)->type->destroy((e)->data); (e)->free(e); } while (0); } while (0); e =
> d; } e =
> ((e))->link.next; } while (!(((&(ctx->b)->
> list))->next == (struct apr_bucket *)((char *)((&(ctx->b)->list)) - ((long)
> (((char *)
> (&(((struct apr_bucket*)0)->link))) - ((c
> har *) 0))))) && (e != (struct apr_bucket *)((char *)(&(ctx->b)->list) -
> ((long) (((char
> *) (&(((struct apr_bucket*)0)->link)))
> - ((char *) 0)))))); } while (0);
> #line 3358
>     if ((((&(ctx->b)->list))->next == (struct apr_bucket *)((char
> *)((&(ctx->b)->list)) -
> ((long) (((char *) (&(((struct apr_buc
> ket*)0)->link))) - ((char *) 0)))))) {
>         return ((20000 + 500) + 14);
>     }
> #line 3365
> 



Re: What evil lurks beneath macros... (an AIX xlc optimizer bug)

Posted by Cliff Woolley <jw...@virginia.edu>.
On Fri, 16 Aug 2002, Bill Stoddard wrote:

> And here is that same code with the macros unrolled. The xlc optimizer
> chokes on this. avoid_xlc_bug() just returns 1 and does nothing else (and
> makes the optimzer happy again). This is just nasty.

Can you be more specific about what the bug is, please?  What is it that
gets evaluated incorrectly by the incorrectly-optimized code?

--Cliff