A couple of questions come up from an application perspective:

am I leaking memory?  if so, on what operation?
how much memory does it take to perform a certain operation?

If the application can find out how much heap memory is presently owned by a certain allocator, it can be easier to address such questions.

The attached apr.patch adds apr_allocator_memsize_get() to find the amount of heap memory presently owned by the allocator. (debug pool flavor not implemented; what is implemented isn't tested much ;) )

The attached httpd.patch adds %Z log format to mod_log_config to log the memory size of the allocator used by the request pool. (I would lean towards implementing this feature in a debug module instead of in mod_log_config.)

The last two fields in the access log below are PID/TID and MEMSIZE.

"GET / HTTP/1.1" 200 517 23818/5 57448
"GET / HTTP/1.1" 304 - 23818/5 57448
"GET /cgi-bin/printenv HTTP/1.1" 200 1241 23818/5 65640
"GET /cgi-bin/printenv HTTP/1.1" 200 1272 23818/5 65640
"GET /manual/mod/mod_rewrite.html HTTP/1.1" 200 84992 23819/27 73832
"GET /manual/style/css/manual.css HTTP/1.1" 200 18172 23819/27 73832
"GET /manual/style/css/manual-loose-100pc.css HTTP/1.1" 200 2882 23819/27 73832
"GET /manual/style/css/manual-print.css HTTP/1.1" 200 12977 23818/5 49256
"GET /manual/images/favicon.ico HTTP/1.1" 200 1078 23819/27 73832
"GET /manual/images/feather.gif HTTP/1.1" 200 6471 23818/5 49256
"GET /manual/images/left.gif HTTP/1.1" 200 60 23819/27 73832
"GET /manual/images/down.gif HTTP/1.1" 200 56 23818/5 49256  <- lower; bug in 
tracking?
"GET /manual/images/up.gif HTTP/1.1" 200 57 23819/27 73832
"GET /manual/images/mod_rewrite_fig1.gif HTTP/1.1" 200 3525 23818/5 49256
"GET /manual/images/mod_rewrite_fig2.gif HTTP/1.1" 200 2553 23819/27 73832

httpd isn't such a great example of an app where this would be interesting, as its pool usage has relatively few surprises. Other applications in earlier stages of development might benefit a lot more.


W.r.t. httpd, there is also an issue that this idea may not help understand bad memory behavior when some arbitrary plug-in is active. Some commercial plug-ins are written for multiple web servers and have a relatively small piece which is specific to Apache httpd (i.e., which utilizes APR pools), so you could still have lots of memory allocated during the processing of certain requests without it showing up in the mod_log_config memory trace above. Any ideas for tracking memory usage regardless of how the memory is allocated from the heap? The best I can think of is pretty poor for a threaded server: logging the current break value (sbrk()) and hoping for a rough pattern to emerge out of lots of data.
Index: include/apr_allocator.h
===================================================================
RCS file: /home/cvs/apr/include/apr_allocator.h,v
retrieving revision 1.19
diff -u -r1.19 apr_allocator.h
--- include/apr_allocator.h     13 Feb 2004 09:38:28 -0000      1.19
+++ include/apr_allocator.h     28 Jul 2004 11:18:00 -0000
@@ -130,6 +130,14 @@
 APR_DECLARE(void) apr_allocator_max_free_set(apr_allocator_t *allocator,
                                              apr_size_t size);
 
+/**
+ * Get the amount of storage allocated for the allocator (e.g., from the
+ * heap)
+ * @param allocator The allocator in question
+ * @return The amount of memory allocated for this allocator
+ */
+APR_DECLARE(apr_size_t) apr_allocator_memsize_get(apr_allocator_t *allocator);
+
 #include "apr_thread_mutex.h"
 
 #if APR_HAS_THREADS
Index: memory/unix/apr_pools.c
===================================================================
RCS file: /home/cvs/apr/memory/unix/apr_pools.c,v
retrieving revision 1.206
diff -u -r1.206 apr_pools.c
--- memory/unix/apr_pools.c     17 Jun 2004 14:13:58 -0000      1.206
+++ memory/unix/apr_pools.c     28 Jul 2004 11:18:01 -0000
@@ -70,6 +70,7 @@
     apr_thread_mutex_t *mutex;
 #endif /* APR_HAS_THREADS */
     apr_pool_t         *owner;
+    apr_size_t          memsize;
     apr_memnode_t      *free[MAX_INDEX];
 };
 
@@ -91,7 +92,7 @@
 
     memset(new_allocator, 0, SIZEOF_ALLOCATOR_T);
     new_allocator->max_free_index = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
-
+    new_allocator->memsize = SIZEOF_ALLOCATOR_T;
     *allocator = new_allocator;
 
     return APR_SUCCESS;
@@ -297,6 +298,8 @@
     node->first_avail = (char *)node + APR_MEMNODE_T_SIZE;
     node->endp = (char *)node + size;
 
+    allocator->memsize += size;
+
     return node;
 }
 
@@ -360,6 +363,7 @@
     while (freelist != NULL) {
         node = freelist;
         freelist = node->next;
+        allocator->memsize -= node->endp - (char *)node;
         free(node);
     }
 }
@@ -376,7 +380,10 @@
     allocator_free(allocator, node);
 }
 
-
+APR_DECLARE(apr_size_t) apr_allocator_memsize_get(apr_allocator_t *allocator)
+{
+    return allocator->memsize;
+}
 
 /*
  * Debug level
Index: modules/loggers/mod_log_config.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/loggers/mod_log_config.c,v
retrieving revision 1.119
diff -u -r1.119 mod_log_config.c
--- modules/loggers/mod_log_config.c    20 Jun 2004 13:08:06 -0000      1.119
+++ modules/loggers/mod_log_config.c    28 Jul 2004 11:16:23 -0000
@@ -675,6 +675,14 @@
     return "-";
 }
 
+static const char *log_allocator_memsize(request_rec *r, char *a)
+{
+    apr_allocator_t *allocator = apr_pool_allocator_get(r->pool);
+    apr_size_t memsize = apr_allocator_memsize_get(allocator);
+
+    return apr_psprintf(r->pool, "%" APR_SIZE_T_FMT, memsize);
+}
+
 /*****************************************************************
  *
  * Parsing the log format string
@@ -1484,6 +1492,7 @@
         log_pfn_register(p, "T", log_request_duration, 1);
         log_pfn_register(p, "U", log_request_uri, 1);
         log_pfn_register(p, "s", log_status, 1);
+        log_pfn_register(p, "Z", log_allocator_memsize, 1);
     }
 
     return OK;

Reply via email to