Brian Pane wrote:

Bill Stoddard wrote:
...


The time spent in ap_brigade_puts is
suprising... This particular run indicate that it tool 74355 instructions
to serve a keep alive request.



I've seen the brigade_puts overhead in my testing, too...and it
is definitely surprising, since the code is relatively minimal.
The only obvious (potential) speedup I can think of would be to
replace the char-at-a-time loop with a memcpy (with checks to
make sure it doesn't overflow the available size). I'll try this
over the weekend.


I remembered why memcpy won't help here: we don't know the
length in advance.  But I managed to speed up apr_brigade_puts()
by about 30% in my tests by optimizing its main loop.  Does this
patch reduce the apr_brigade_puts() overhead in your test environment?

--Brian

Index: srclib/apr-util/buckets/apr_brigade.c
===================================================================
RCS file: /home/cvs/apr-util/buckets/apr_brigade.c,v
retrieving revision 1.44
diff -u -r1.44 apr_brigade.c
--- srclib/apr-util/buckets/apr_brigade.c       29 Jun 2002 03:18:36 -0000      
1.44
+++ srclib/apr-util/buckets/apr_brigade.c       29 Jun 2002 04:48:02 -0000
@@ -465,11 +465,60 @@
         apr_size_t bytes_avail = h->alloc_len - bkt->length;
         const char *saved_start = str;
 
-        while (bytes_avail && *str) {
+        /* Optimization:
+         * The loop that follows is an unrolled version of the original:
+         *   while (bytes_avail && *str) {
+         *       *buf++ = *str++;
+         *       bytes_avail--;
+         *   }
+         * With that original loop, apr_brigade_puts() was showing
+         * up as a surprisingly expensive function in httpd performance
+         * profiling (it gets called a *lot*).  This new loop reduces
+         * the overhead from two conditional branch ops per character
+         * to 1+1/8.  The result is a 30% reduction in the cost of
+         * apr_brigade_puts() in typical usage within the httpd.
+         */
+        while (bytes_avail >= 8) {
+            /* Copy the next 8 characters (or fewer if we hit end of string) */
+            if (!*str) {
+                break;
+            }
             *buf++ = *str++;
-            bytes_avail--;
+            if (!*str) {
+                break;
+            }
+            *buf++ = *str++;
+            if (!*str) {
+                break;
+            }
+            *buf++ = *str++;
+            if (!*str) {
+                break;
+            }
+            *buf++ = *str++;
+            if (!*str) {
+                break;
+            }
+            *buf++ = *str++;
+            if (!*str) {
+                break;
+            }
+            *buf++ = *str++;
+            if (!*str) {
+                break;
+            }
+            *buf++ = *str++;
+            if (!*str) {
+                break;
+            }
+            *buf++ = *str++;
+            bytes_avail -= 8;
         }
         bkt->length += (str - saved_start);
+
+        /* If we had enough free space in the bucket to copy
+         * the entire string, we're done
+         */
         if (!*str) {
             return APR_SUCCESS;
         }

Reply via email to