Sunday, July 11, 2004
“Hey! What's that code doing there?”
While the __builtin_expect()
aspect of GCC didn't work, all the recent profiling I've done on mod_blog
(which reminds me, I need to make the current codebase available) did
however, bring my attention to BufferIOCtl()
, which if you noticed, was one of the top four
functions in term of CPU
utilization.
int (BufferIOCtl)(const Buffer buf,int cmd, ... ) { va_list alist; int rc; ddt(buf != NULL); ddt(buf->ioreq != NULL); ddt(cmd > -1); if (buf == NULL) return(ErrorPush(CgiErr,BUFFERIOCTL,BUFERR_NULLPTR,"i",cmd)); if (buf->ioreq == NULL) return(ErrorPush(CgiErr,BUFFERIOCTL,BUFERR_NULLHANDLER,"i",cmd)); va_start(alist,cmd); rc = (*buf->ioreq)(buf,cmd,alist); va_end(alist); return(rc); }
ddt()
is similar to the ANSI C call assert()
, which
basically states a condition that should exist (and if that condition isn't
met, the program aborts—this action can be turned off for production code;
it's meant for debugging). But you'll notice that the code first checks to
see if buf
is not NULL
within ddt()
,
then the first thing it does is check to see if buff
is
NULL
.
It shouldn't be NULL
to begin with.
The same for the tests of buf->ioreq
. When I removed
the extraneous code:
int (BufferIOCtl)(const Buffer buf,int cmd, ... ) { va_list alist; int rc; ddt(buf != NULL); ddt(buf->ioreq != NULL); ddt(cmd > -1); va_start(alist,cmd); rc = (*buf->ioreq)(buf,cmd,alist); va_end(alist); return(rc); }
The runtime of BufferIOCtl()
dropped to 1/3 the original
time.
Not much in the grand scheme of things, but just goes to show you how
expensive extraneous if
statements can be. Especially if it's
called 6,646,086 times.