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