On Sun, 8 Jul 2001, Justin Erenkrantz wrote:
> Also, I did try having the pools use malloc/free directly
> (ALLOC_USE_MALLOC) and the performance was dreadful. At least on
> Solaris. -- justin
yes, ALLOC_USE_MALLOC is dreadful -- that's not what i meant.
what i mean is something like the below patch, which i haven't even tried
to compile or test ;) (the patch needs work to rescue some of the
debugging code in new_block).
it removes block_freelist and uses malloc/free for blocks. this is much
less expensive than malloc/free on each allocation (amortization).
-dean
Index: apr_pools.c
===================================================================
RCS file: /home/cvs/apr/memory/unix/apr_pools.c,v
retrieving revision 1.100
diff -u -r1.100 apr_pools.c
--- apr_pools.c 2001/07/07 22:23:54 1.100
+++ apr_pools.c 2001/07/08 18:17:36
@@ -248,7 +248,6 @@
/*
* Static cells for managing our internal synchronisation.
*/
-static union block_hdr *block_freelist = NULL;
#if APR_HAS_THREADS
static apr_lock_t *alloc_mutex;
@@ -417,120 +416,20 @@
static void free_blocks(union block_hdr *blok)
{
-#ifdef ALLOC_USE_MALLOC
union block_hdr *next;
for ( ; blok; blok = next) {
next = blok->h.next;
DO_FREE(blok);
}
-#else /* ALLOC_USE_MALLOC */
-
-#ifdef ALLOC_STATS
- unsigned num_blocks;
-#endif /* ALLOC_STATS */
-
- /*
- * First, put new blocks at the head of the free list ---
- * we'll eventually bash the 'next' pointer of the last block
- * in the chain to point to the free blocks we already had.
- */
-
- union block_hdr *old_free_list;
-
- if (blok == NULL) {
- return; /* Sanity check --- freeing empty pool? */
- }
-
-#if APR_HAS_THREADS
- if (alloc_mutex) {
- apr_lock_acquire(alloc_mutex);
- }
-#endif
- old_free_list = block_freelist;
- block_freelist = blok;
-
- /*
- * Next, adjust first_avail pointers of each block --- have to do it
- * sooner or later, and it simplifies the search in new_block to do it
- * now.
- */
-
-#ifdef ALLOC_STATS
- num_blocks = 1;
-#endif /* ALLOC_STATS */
-
- while (blok->h.next != NULL) {
-
-#ifdef ALLOC_STATS
- ++num_blocks;
-#endif /* ALLOC_STATS */
-
- chk_on_blk_list(blok, old_free_list);
- blok->h.first_avail = (char *) (blok + 1);
- debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail);
-#ifdef APR_POOL_DEBUG
- blok->h.owning_pool = FREE_POOL;
-#endif /* APR_POOL_DEBUG */
- blok = blok->h.next;
- }
-
- chk_on_blk_list(blok, old_free_list);
- blok->h.first_avail = (char *) (blok + 1);
- debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail);
-#ifdef APR_POOL_DEBUG
- blok->h.owning_pool = FREE_POOL;
-#endif /* APR_POOL_DEBUG */
-
- /* Finally, reset next pointer to get the old free blocks back */
-
- blok->h.next = old_free_list;
-
-#ifdef ALLOC_STATS
- if (num_blocks > max_blocks_in_one_free) {
- max_blocks_in_one_free = num_blocks;
- }
- ++num_free_blocks_calls;
- num_blocks_freed += num_blocks;
-#endif /* ALLOC_STATS */
-
-#if APR_HAS_THREADS
- if (alloc_mutex) {
- apr_lock_release(alloc_mutex);
- }
-#endif /* APR_HAS_THREADS */
-#endif /* ALLOC_USE_MALLOC */
}
/*
- * Get a new block, from our own free list if possible, from the system
- * if necessary. Must be called with alarms blocked.
+ * get a new block from the system
*/
static union block_hdr *new_block(apr_size_t min_size, apr_abortfunc_t
abortfunc)
{
- union block_hdr **lastptr = &block_freelist;
- union block_hdr *blok = block_freelist;
-
- /* First, see if we have anything of the required size
- * on the free list...
- */
-
- while (blok != NULL) {
- if ((apr_ssize_t)min_size + BLOCK_MINFREE <= blok->h.endp -
blok->h.first_avail) {
- *lastptr = blok->h.next;
- blok->h.next = NULL;
- debug_verify_filled(blok->h.first_avail, blok->h.endp,
- "[new_block] Ouch! Someone trounced a block "
- "on the free list!\n");
- return blok;
- }
- else {
- lastptr = &blok->h.next;
- blok = blok->h.next;
- }
- }
-
- /* Nope. */
+ union block_hdr *blok;
min_size += BLOCK_MINFREE;
blok = malloc_block((min_size > BLOCK_MINALLOC)
@@ -586,7 +485,6 @@
union block_hdr *blok;
apr_pool_t *new_pool;
-
#if APR_HAS_THREADS
if (alloc_mutex) {
apr_lock_acquire(alloc_mutex);
@@ -960,7 +858,7 @@
APR_DECLARE(apr_size_t) apr_pool_free_blocks_num_bytes(void)
{
- return bytes_in_block_list(block_freelist);
+ return 0;
}
/* the unix linker defines this symbol as the last byte + 1 of
@@ -1255,13 +1153,7 @@
cur_len = strp - blok->h.first_avail;
/* must try another blok */
-#if APR_HAS_THREADS
- apr_lock_acquire(alloc_mutex);
-#endif
nblok = new_block(2 * cur_len, NULL);
-#if APR_HAS_THREADS
- apr_lock_release(alloc_mutex);
-#endif
memcpy(nblok->h.first_avail, blok->h.first_avail, cur_len);
ps->vbuff.curpos = nblok->h.first_avail + cur_len;
/* save a byte for the NUL terminator */
@@ -1270,14 +1162,7 @@
/* did we allocate the current blok? if so free it up */
if (ps->got_a_new_block) {
debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail);
-#if APR_HAS_THREADS
- apr_lock_acquire(alloc_mutex);
-#endif
- blok->h.next = block_freelist;
- block_freelist = blok;
-#if APR_HAS_THREADS
- apr_lock_release(alloc_mutex);
-#endif
+ DO_FREE(blok);
}
ps->blok = nblok;
ps->got_a_new_block = 1;