apr-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ian Holsman <i...@cnet.com>
Subject Re: Observations on fragmentation in SMS pools
Date Sun, 08 Jul 2001 18:29:41 GMT
dean gaudet wrote:

>
>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
>

If you can wait till monday, and you are interested, I'll put it through 
the ringer on a 8-CPU Sun4500
..Ian

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




Mime
View raw message