In profiling the httpd, I've found the conv_10 function
(used in the implementation of "%d" for the apr_*printf
functions) to be one of the top 10 consumers of user-mode
CPU time.  There are a small number of places in the httpd
that cause most of the calls to this function.

The attached patch fixes the problem.  It includes two
changes to APR:
  * new functions apr_itoa, apr_ltoa, and apr_off_t_toa
    that provide itoa-type functionality based on pools
  * Inline code in inet_ntop4 to replace sprintf for converting
    binary IP addresses into dotted-decimal format
and two changes to Apache:
  * use the apr_itoa functions in setting the content length,
    in place of apr_psprintf
  * use the apr_itoa functions to replace frequent uses of
    'sprintf("%d",...)' in mod_log_config.

--Brian

Index: apr_strings.h
===================================================================
RCS file: /home/cvspublic/apr/include/apr_strings.h,v
retrieving revision 1.18
diff -u -r1.18 apr_strings.h
--- apr_strings.h       2001/06/15 15:08:22     1.18
+++ apr_strings.h       2001/07/15 10:11:57
@@ -279,6 +279,33 @@
 APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format,
                                va_list ap);
 
+/**
+ * create a string representation of an int, allocated from a pool
+ * @param p The pool from which to allocate
+ * @param n The number to format
+ * @return The string representation of the number
+ * @deffunc int apr_itoa(apr_pool_t *p, int n)
+ */
+APR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n);
+
+/**
+ * create a string representation of a long, allocated from a pool
+ * @param p The pool from which to allocate
+ * @param n The number to format
+ * @return The string representation of the number
+ * @deffunc int apr_ltoa(apr_pool_t *p, long n)
+ */
+APR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n);
+
+/**
+ * create a string representation of an apr_off_t, allocated from a pool
+ * @param p The pool from which to allocate
+ * @param n The number to format
+ * @return The string representation of the number
+ * @deffunc int apr_ltoa(apr_pool_t *p, apr_off_t n)
+ */
+APR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, apr_off_t n);
+
 #ifdef __cplusplus
 }
 #endif
Index: apr_strings.c
===================================================================
RCS file: /home/cvspublic/apr/strings/apr_strings.c,v
retrieving revision 1.15
diff -u -r1.15 apr_strings.c
--- apr_strings.c       2001/06/20 19:50:29     1.15
+++ apr_strings.c       2001/07/15 10:14:45
@@ -163,3 +163,75 @@
     return NULL;
 }
 #endif
+
+APR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n)
+{
+    const int BUFFER_SIZE = sizeof(int) * 3 + 2;
+    char *buf = apr_palloc(p, BUFFER_SIZE);
+    char *start = buf + BUFFER_SIZE - 1;
+    int negative;
+    if (n < 0) {
+       negative = 1;
+       n = -n;
+    }
+    else {
+       negative = 0;
+    }
+    *start = 0;
+    do {
+       *--start = '0' + (n % 10);
+       n /= 10;
+    } while (n);
+    if (negative) {
+       *--start = '-';
+    }
+    return start;
+}
+
+APR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n)
+{
+    const int BUFFER_SIZE = sizeof(long) * 3 + 2;
+    char *buf = apr_palloc(p, BUFFER_SIZE);
+    char *start = buf + BUFFER_SIZE - 1;
+    int negative;
+    if (n < 0) {
+       negative = 1;
+       n = -n;
+    }
+    else {
+       negative = 0;
+    }
+    *start = 0;
+    do {
+       *--start = '0' + (n % 10);
+       n /= 10;
+    } while (n);
+    if (negative) {
+       *--start = '-';
+    }
+    return start;
+}
+
+APR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, long n)
+{
+    const int BUFFER_SIZE = sizeof(apr_off_t) * 3 + 2;
+    char *buf = apr_palloc(p, BUFFER_SIZE);
+    char *start = buf + BUFFER_SIZE - 1;
+    int negative;
+    if (n < 0) {
+       negative = 1;
+       n = -n;
+    }
+    else {
+       negative = 0;
+    }
+    *start = 0;
+    do {
+       *--start = '0' + (n % 10);
+       n /= 10;
+    } while (n);
+    if (negative) {
+       *--start = '-';
+    }
+    return start;
+}
Index: inet_ntop.c
===================================================================
RCS file: /home/cvspublic/apr/network_io/unix/inet_ntop.c,v
retrieving revision 1.10
diff -u -r1.10 inet_ntop.c
--- inet_ntop.c 2001/06/06 15:22:04     1.10
+++ inet_ntop.c 2001/07/15 10:16:53
@@ -99,15 +99,32 @@
 static const char *
 inet_ntop4(const unsigned char *src, char *dst, apr_size_t size)
 {
-       static const char fmt[] = "%u.%u.%u.%u";
-       char tmp[sizeof "255.255.255.255"];
+       const int MIN_SIZE = 16; /* space for 255.255.255.255\0 */
+       int n = 0;
+       char *next = dst;
 
-       if (apr_snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3]) > 
(int)size) {
-               errno = ENOSPC;
-               return (NULL);
+       if (size < MIN_SIZE) {
+           errno = ENOSPC;
+           return NULL;
        }
-       strcpy(dst, tmp);
-       return (dst);
+       do {
+           unsigned char u = *src++;
+           if (u > 99) {
+               *next++ = '0' + u/100;
+               u %= 100;
+               *next++ = '0' + u/10;
+               u %= 10;
+           }
+           else if (u > 9) {
+               *next++ = '0' + u/10;
+               u %= 10;
+           }
+           *next++ = '0' + u;
+           *next++ = '.';
+           n++;
+       } while (n < 4);
+       *--next = 0;
+       return dst;
 }
 
 #if APR_HAVE_IPV6
Index: protocol.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/protocol.c,v
retrieving revision 1.31
diff -u -r1.31 protocol.c
--- protocol.c  2001/07/06 19:49:47     1.31
+++ protocol.c  2001/07/15 10:15:50
@@ -154,7 +154,7 @@
 {
     r->clength = clength;
     apr_table_setn(r->headers_out, "Content-Length",
-                   apr_psprintf(r->pool, "%" APR_OFF_T_FMT, clength));
+                  apr_off_t_toa(r->pool, clength));
 }
 
 /*
Index: mod_log_config.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/loggers/mod_log_config.c,v
retrieving revision 1.60
diff -u -r1.60 mod_log_config.c
--- mod_log_config.c    2001/05/22 01:31:06     1.60
+++ mod_log_config.c    2001/07/15 10:18:07
@@ -284,7 +284,7 @@
 
 static char *format_integer(apr_pool_t *p, int i)
 {
-    return apr_psprintf(p, "%d", i);
+    return apr_itoa(p, i);
 }
 
 static char *pfmt(apr_pool_t *p, int i)
@@ -381,7 +381,7 @@
         return "-";
     }
     else {
-       return apr_psprintf(r->pool, "%ld", r->bytes_sent);
+       return apr_ltoa(r->pool, r->bytes_sent);
     }
 }
 

Reply via email to