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;
}