brianp 2002/06/29 15:39:43
Modified: . CHANGES
buckets apr_brigade.c
Log:
Optimized apr_brigade_puts() because it was showing up as
a performance problem in httpd benchmarking
Revision Changes Path
1.68 +2 -0 apr-util/CHANGES
Index: CHANGES
===================================================================
RCS file: /home/cvs/apr-util/CHANGES,v
retrieving revision 1.67
retrieving revision 1.68
diff -u -r1.67 -r1.68
--- CHANGES 23 May 2002 21:04:25 -0000 1.67
+++ CHANGES 29 Jun 2002 22:39:42 -0000 1.68
@@ -1,5 +1,7 @@
Changes with APR-util b1
+ *) Faster implementation of apr_brigade_puts() [Brian Pane]
+
*) Fixed a segfault in apr_date_parse_rfc() for some date formats
where it was trying to overlay a potentially static input
string even though it didn't really need to.
1.45 +51 -2 apr-util/buckets/apr_brigade.c
Index: apr_brigade.c
===================================================================
RCS file: /home/cvs/apr-util/buckets/apr_brigade.c,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -r1.44 -r1.45
--- apr_brigade.c 29 Jun 2002 03:18:36 -0000 1.44
+++ apr_brigade.c 29 Jun 2002 22:39:43 -0000 1.45
@@ -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;
}