diff options
author | Neil Fortner <nfortne2@hdfgroup.org> | 2009-04-08 18:53:36 (GMT) |
---|---|---|
committer | Neil Fortner <nfortne2@hdfgroup.org> | 2009-04-08 18:53:36 (GMT) |
commit | 559c385efc865ba839f6bb315e3cf213bba7fdf1 (patch) | |
tree | 271d6fc514bf793f2345e726e9f1a4f07f55cd9a /src | |
parent | a4aae55760919e2e4a66a58b2a66d1a28253ebd5 (diff) | |
download | hdf5-559c385efc865ba839f6bb315e3cf213bba7fdf1.zip hdf5-559c385efc865ba839f6bb315e3cf213bba7fdf1.tar.gz hdf5-559c385efc865ba839f6bb315e3cf213bba7fdf1.tar.bz2 |
[svn-r16702] Purpose: Improve performance of factory free lists.
Description:
Factory free lists were formerly implemented as block free lists. This was
inefficient as factories can only be one size, and implementing them as blocks
(which can be variable size) wastedd computation and space. They have been
rewritten with a separate implementation, which is simlar to regular free lists
except they can be dynamically created and destroyed.
Tested: jam, linew, smirom (h5committest)
Diffstat (limited to 'src')
-rw-r--r-- | src/H5.c | 10 | ||||
-rw-r--r-- | src/H5FL.c | 591 | ||||
-rw-r--r-- | src/H5FLprivate.h | 24 |
3 files changed, 459 insertions, 166 deletions
@@ -409,6 +409,9 @@ done: * global lists, up to 3 MB of total storage might be allocated (1MB on * each of regular, array and block type lists). * + * The settings for block free lists are duplicated to factory free lists. + * Factory free list limits cannot be set independently currently. + * * Parameters: * int reg_global_lim; IN: The limit on all "regular" free list memory used * int reg_list_lim; IN: The limit on memory used in each "regular" free list @@ -424,7 +427,9 @@ done: * Programmer: Quincey Koziol * Wednesday, August 2, 2000 * - * Modifications: + * Modifications: Neil Fortner + * Wednesday, April 8, 2009 + * Added support for factory free lists * *------------------------------------------------------------------------- */ @@ -439,7 +444,8 @@ H5set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim, arr_list_lim, blk_global_lim, blk_list_lim); /* Call the free list function to actually set the limits */ - if(H5FL_set_free_list_limits(reg_global_lim, reg_list_lim, arr_global_lim, arr_list_lim, blk_global_lim, blk_list_lim)<0) + if(H5FL_set_free_list_limits(reg_global_lim, reg_list_lim, arr_global_lim, arr_list_lim, + blk_global_lim, blk_list_lim, blk_global_lim, blk_list_lim)<0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSET, FAIL, "can't set garbage collection limits") done: @@ -52,6 +52,8 @@ static size_t H5FL_arr_glb_mem_lim=4*1024*1024; /* Default to 4MB limit on all a static size_t H5FL_arr_lst_mem_lim=4*65536; /* Default to 256KB limit on each array free list */ static size_t H5FL_blk_glb_mem_lim=16*1024*1024; /* Default to 16MB limit on all block free lists */ static size_t H5FL_blk_lst_mem_lim=1024*1024; /* Default to 1024KB (1MB) limit on each block free list */ +static size_t H5FL_fac_glb_mem_lim=16*1024*1024; /* Default to 16MB limit on all factory free lists */ +static size_t H5FL_fac_lst_mem_lim=1024*1024; /* Default to 1024KB (1MB) limit on each factory free list */ /* A garbage collection node for regular free lists */ typedef struct H5FL_reg_gc_node_t { @@ -98,6 +100,36 @@ typedef struct H5FL_blk_gc_list_t { /* The head of the list of PQs to garbage collect */ static H5FL_blk_gc_list_t H5FL_blk_gc_head={0,NULL}; +/* A garbage collection node for factory free lists */ +typedef struct H5FL_fac_gc_node_t { + H5FL_fac_head_t *list; /* Pointer to the head of the list to garbage collect */ + struct H5FL_fac_gc_node_t *next; /* Pointer to the next node in the list of things to garbage collect */ +} H5FL_fac_gc_node_t; + +/* The garbage collection head for factory free lists */ +typedef struct H5FL_fac_gc_list_t { + size_t mem_freed; /* Amount of free memory on list */ + struct H5FL_fac_gc_node_t *first; /* Pointer to the first node in the list of things to garbage collect */ +} H5FL_fac_gc_list_t; + +/* Data structure to store each block in factory free list */ +typedef struct H5FL_fac_node_t { + struct H5FL_fac_node_t *next; /* Pointer to next block in free list */ +} H5FL_fac_node_t; + +/* Data structure for free list block factory */ +struct H5FL_fac_head_t { + unsigned init; /* Whether the free list has been initialized */ + unsigned allocated; /* Number of blocks allocated */ + unsigned onlist; /* Number of blocks on free list */ + size_t size; /* Size of the blocks in the list */ + H5FL_fac_node_t *list; /* List of free blocks */ + H5FL_fac_gc_node_t *prev_gc; /* Previous garbage collection node in list */ +}; + +/* The head of the list of factory things to garbage collect */ +static H5FL_fac_gc_list_t H5FL_fac_gc_head={0,NULL}; + #ifdef H5FL_TRACK /* Extra headers needed */ @@ -114,14 +146,18 @@ static herr_t H5FL_arr_gc(void); static herr_t H5FL_arr_gc_list(H5FL_arr_head_t *head); static herr_t H5FL_blk_gc(void); static herr_t H5FL_blk_gc_list(H5FL_blk_head_t *head); -static herr_t H5FL_blk_unlink(H5FL_blk_head_t *pq); - -/* Declare a free list to manage the H5FL_fac_head_t struct */ -H5FL_DEFINE(H5FL_fac_head_t); +static herr_t H5FL_fac_gc(void); +static herr_t H5FL_fac_gc_list(H5FL_fac_head_t *head); /* Declare a free list to manage the H5FL_blk_node_t struct */ H5FL_DEFINE(H5FL_blk_node_t); +/* Declare a free list to manage the H5FL_fac_gc_node_t struct */ +H5FL_DEFINE(H5FL_fac_gc_node_t); + +/* Declare a free list to manage the H5FL_fac_head_t struct */ +H5FL_DEFINE(H5FL_fac_head_t); + /*-------------------------------------------------------------------------- NAME @@ -225,15 +261,15 @@ H5FL_reg_init(H5FL_reg_head_t *head) /* Indicate that the free list is initialized */ head->init=1; + /* Make certain that the space allocated is large enough to store a free list pointer (eventually) */ + if(head->size<sizeof(H5FL_reg_node_t)) + head->size=sizeof(H5FL_reg_node_t); + /* Make certain there's room for tracking information, if any */ #ifdef H5FL_TRACK head->size += sizeof(H5FL_track_t); #endif /* H5FL_TRACK */ - /* Make certain that the space allocated is large enough to store a free list pointer (eventually) */ - if(head->size<sizeof(void *)) - head->size=sizeof(void *); - done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FL_reg_init() */ @@ -259,11 +295,13 @@ H5FL_reg_free(H5FL_reg_head_t *head, void *obj) { void *ret_value=NULL; /* Return value */ - FUNC_ENTER_NOAPI(H5FL_reg_free, NULL) + /* NOINIT OK here because this must be called after H5FL_reg_malloc/calloc + * -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_reg_free) /* Double check parameters */ - assert(head); - assert(obj); + HDassert(head); + HDassert(obj); #ifdef H5FL_TRACK { @@ -294,7 +332,7 @@ H5FL_reg_free(H5FL_reg_head_t *head, void *obj) #endif /* H5FL_DEBUG */ /* Make certain that the free list is initialized */ - assert(head->init); + HDassert(head->init); /* Link into the free list */ ((H5FL_reg_node_t *)obj)->next=head->list; @@ -302,16 +340,15 @@ H5FL_reg_free(H5FL_reg_head_t *head, void *obj) /* Point free list at the node freed */ head->list=(H5FL_reg_node_t *)obj; - /* Increment the number of blocks & memory on free list */ + /* Increment the number of blocks on free list */ head->onlist++; - head->list_mem+=head->size; /* Increment the amount of "regular" freed memory globally */ H5FL_reg_gc_head.mem_freed+=head->size; /* Check for exceeding free list memory use limits */ /* First check this particular list */ - if(head->list_mem>H5FL_reg_lst_mem_lim) + if(head->onlist * head->size > H5FL_reg_lst_mem_lim) if(H5FL_reg_gc_list(head)<0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free") @@ -348,7 +385,7 @@ H5FL_reg_malloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_reg_malloc, NULL) /* Double check parameters */ - assert(head); + HDassert(head); /* Make certain the list is initialized first */ if(!head->init) @@ -365,7 +402,6 @@ H5FL_reg_malloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS) /* Decrement the number of blocks & memory on free list */ head->onlist--; - head->list_mem-=head->size; /* Decrement the amount of global "regular" free list memory in use */ H5FL_reg_gc_head.mem_freed-=(head->size); @@ -426,7 +462,7 @@ H5FL_reg_calloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_reg_calloc, NULL) /* Double check parameters */ - assert(head); + HDassert(head); /* Allocate the block */ if (NULL==(ret_value = H5FL_reg_malloc(head H5FL_TRACK_INFO_INT))) @@ -476,17 +512,11 @@ H5FL_reg_gc_list(H5FL_reg_head_t *head) /* Decrement the count of nodes allocated and free the node */ head->allocated--; - /* Decrement count of free memory on this list */ - head->list_mem-=head->size; - - H5MM_xfree(free_list); + H5MM_free(free_list); free_list = (H5FL_reg_node_t *)tmp; } /* end while */ - /* Double check that all the memory on this list is recycled */ - HDassert(0 == head->list_mem); - /* Indicate no free nodes on the free list */ head->list=NULL; head->onlist=0; @@ -535,7 +565,7 @@ H5FL_reg_gc(void) } /* end while */ /* Double check that all the memory on the free lists is recycled */ - assert(H5FL_reg_gc_head.mem_freed==0); + HDassert(H5FL_reg_gc_head.mem_freed==0); done: FUNC_LEAVE_NOAPI(ret_value) @@ -797,7 +827,7 @@ H5FL_blk_free_block_avail(H5FL_blk_head_t *head, size_t size) FUNC_ENTER_NOAPI(H5FL_blk_free_block_avail, FAIL) /* Double check parameters */ - assert(head); + HDassert(head); /* check if there is a free list for blocks of this size */ /* and if there are any blocks available on the list */ @@ -838,8 +868,8 @@ H5FL_blk_malloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_blk_malloc, NULL) /* Double check parameters */ - assert(head); - assert(size); + HDassert(head); + HDassert(size); /* Make certain the list is initialized first */ if(!head->init) @@ -928,8 +958,8 @@ H5FL_blk_calloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_blk_calloc, NULL) /* Double check parameters */ - assert(head); - assert(size); + HDassert(head); + HDassert(size); /* Allocate the block */ if (NULL==(ret_value = H5FL_blk_malloc(head,size H5FL_TRACK_INFO_INT))) @@ -969,11 +999,13 @@ H5FL_blk_free(H5FL_blk_head_t *head, void *block) size_t free_size; /* Size of the block freed */ void *ret_value=NULL; /* Return value */ - FUNC_ENTER_NOAPI(H5FL_blk_free, NULL) + /* NOINIT OK here because this must be called after H5FL_blk_malloc/calloc + * -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_blk_free) /* Double check parameters */ - assert(head); - assert(block); + HDassert(head); + HDassert(block); #ifdef H5FL_TRACK { @@ -1070,8 +1102,8 @@ H5FL_blk_realloc(H5FL_blk_head_t *head, void *block, size_t new_size H5FL_TRACK_ FUNC_ENTER_NOAPI(H5FL_blk_realloc, NULL) /* Double check parameters */ - assert(head); - assert(new_size); + HDassert(head); + HDassert(new_size); /* Check if we are actually re-allocating a block */ if(block!=NULL) { @@ -1119,67 +1151,6 @@ done: } /* end H5FL_blk_realloc() */ -/*-------------------------------------------------------------------------- - NAME - H5FL_blk_unlink - PURPOSE - Remove a block free list from the global list of initialized block free - lists. - USAGE - void H5FL_blk_unlink(H5FL_blk_head_t *pq) - H5FL_blk_head_t *pq; IN: Block free list to remove from global list - RETURNS - Success: Non-negative - Failure: Negative - DESCRIPTION - Search through the global list of initialized block free lists and remove - a particular free list. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5FL_blk_unlink(H5FL_blk_head_t *pq) -{ - H5FL_blk_gc_node_t *last; /* Pointer to the last garbage collection node examined */ - H5FL_blk_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5FL_blk_unlink) - - /* Find the node to remove from the global list */ - last=NULL; - tmp=H5FL_blk_gc_head.first; - while(tmp!=NULL) { - /* Check if the list has allocations outstanding */ - if(tmp->pq==pq) { - /* Unlink node from linked list */ - if(last==NULL) - H5FL_blk_gc_head.first=H5FL_blk_gc_head.first->next; - else - last->next=tmp->next; - - /* Free the block node */ - H5MM_xfree(tmp); - - /* Leave now */ - break; - } /* end if */ - - /* Advance to next node in list */ - last=tmp; - tmp=tmp->next; - } /* end while */ - - if(tmp==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't release block free list") - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5FL_blk_unlink() */ - - /*------------------------------------------------------------------------- * Function: H5FL_blk_gc_list * @@ -1221,7 +1192,7 @@ H5FL_blk_gc_list(H5FL_blk_head_t *head) H5FL_blk_gc_head.mem_freed-=head->head->size; /* Free the block */ - H5MM_xfree(list); + H5MM_free(list); list = (H5FL_blk_list_t *)next; } /* end while */ @@ -1279,7 +1250,7 @@ H5FL_blk_gc(void) } /* end while */ /* Double check that all the memory on the free lists are recycled */ - assert(H5FL_blk_gc_head.mem_freed==0); + HDassert(H5FL_blk_gc_head.mem_freed==0); done: FUNC_LEAVE_NOAPI(ret_value) @@ -1334,7 +1305,7 @@ printf("H5FL_blk_term: head->name=%s, head->allocated=%d\n", H5FL_blk_gc_head.fi H5FL_blk_gc_head.first->pq->init=0; /* Free the node from the garbage collection list */ - H5MM_xfree(H5FL_blk_gc_head.first); + H5MM_free(H5FL_blk_gc_head.first); } /* end else */ H5FL_blk_gc_head.first=tmp; @@ -1422,17 +1393,19 @@ H5FL_arr_free(H5FL_arr_head_t *head, void *obj) size_t free_nelem; /* Number of elements in node being free'd */ void *ret_value=NULL; /* Return value */ - FUNC_ENTER_NOAPI(H5FL_arr_free, NULL) + /* NOINIT OK here because this must be called after H5FL_arr_malloc/calloc + * -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_arr_free) /* The H5MM_xfree code allows obj to null */ if (!obj) HGOTO_DONE (NULL) /* Double check parameters */ - assert(head); + HDassert(head); /* Make certain that the free list is initialized */ - assert(head->init); + HDassert(head->init); /* Get the pointer to the info header in front of the block to free */ temp=(H5FL_arr_list_t *)((unsigned char *)obj-sizeof(H5FL_arr_list_t)); /*lint !e826 Pointer-to-pointer cast is appropriate here */ @@ -1441,7 +1414,7 @@ H5FL_arr_free(H5FL_arr_head_t *head, void *obj) free_nelem=temp->nelem; /* Double-check that there is enough room for arrays of this size */ - assert((int)free_nelem<=head->maxelem); + HDassert((int)free_nelem<=head->maxelem); /* Link into the free list */ temp->next=head->list_arr[free_nelem].list; @@ -1500,8 +1473,8 @@ H5FL_arr_malloc(H5FL_arr_head_t *head, size_t elem) FUNC_ENTER_NOAPI(H5FL_arr_malloc, NULL) /* Double check parameters */ - assert(head); - assert(elem); + HDassert(head); + HDassert(elem); /* Make certain the list is initialized first */ if(!head->init) @@ -1509,7 +1482,7 @@ H5FL_arr_malloc(H5FL_arr_head_t *head, size_t elem) HGOTO_ERROR (H5E_RESOURCE, H5E_CANTINIT, NULL, "can't initialize 'array' blocks") /* Sanity check that the number of elements is supported */ - assert(elem<=(unsigned) head->maxelem); + HDassert(elem<=(unsigned) head->maxelem); /* Get the set of the memory block */ mem_size=head->list_arr[elem].size; @@ -1573,8 +1546,8 @@ H5FL_arr_calloc(H5FL_arr_head_t *head, size_t elem) FUNC_ENTER_NOAPI(H5FL_arr_calloc, NULL) /* Double check parameters */ - assert(head); - assert(elem); + HDassert(head); + HDassert(elem); /* Allocate the array */ if (NULL==(ret_value = H5FL_arr_malloc(head,elem))) @@ -1611,8 +1584,8 @@ H5FL_arr_realloc(H5FL_arr_head_t *head, void * obj, size_t new_elem) FUNC_ENTER_NOAPI(H5FL_arr_realloc, NULL) /* Double check parameters */ - assert(head); - assert(new_elem); + HDassert(head); + HDassert(new_elem); /* Check if we are really allocating the object */ if(obj==NULL) @@ -1621,7 +1594,7 @@ H5FL_arr_realloc(H5FL_arr_head_t *head, void * obj, size_t new_elem) H5FL_arr_list_t *temp; /* Temp. ptr to the new free list node allocated */ /* Sanity check that the number of elements is supported */ - assert((int)new_elem<=head->maxelem); + HDassert((int)new_elem<=head->maxelem); /* Get the pointer to the info header in front of the block to free */ temp=(H5FL_arr_list_t *)((unsigned char *)obj-sizeof(H5FL_arr_list_t)); /*lint !e826 Pointer-to-pointer cast is appropriate here */ @@ -1687,7 +1660,7 @@ H5FL_arr_gc_list(H5FL_arr_head_t *head) /* Decrement the count of nodes allocated and free the node */ head->allocated--; - H5MM_xfree(arr_free_list); + H5MM_free(arr_free_list); arr_free_list = (H5FL_arr_list_t *)tmp; } /* end while */ @@ -1705,7 +1678,7 @@ H5FL_arr_gc_list(H5FL_arr_head_t *head) } /* end for */ /* Double check that all the memory on this list is recycled */ - assert(head->list_mem==0); + HDassert(head->list_mem==0); FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5FL_arr_gc_list() */ @@ -1746,7 +1719,7 @@ H5FL_arr_gc(void) } /* end while */ /* Double check that all the memory on the free lists are recycled */ - assert(H5FL_arr_gc_head.mem_freed==0); + HDassert(H5FL_arr_gc_head.mem_freed==0); done: FUNC_LEAVE_NOAPI(ret_value) @@ -1803,7 +1776,7 @@ printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_arr_gc_head.fi H5FL_arr_gc_head.first->list->init=0; /* Free the node from the garbage collection list */ - H5MM_xfree(H5FL_arr_gc_head.first); + H5MM_free(H5FL_arr_gc_head.first); } /* end else */ H5FL_arr_gc_head.first=tmp; @@ -1834,14 +1807,16 @@ printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_arr_gc_head.fi void * H5FL_seq_free(H5FL_seq_head_t *head, void *obj) { + /* NOINIT OK here because this must be called after H5FL_seq_malloc/calloc + * -NAF */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FL_seq_free) /* Double check parameters */ - assert(head); - assert(obj); + HDassert(head); + HDassert(obj); /* Make certain that the free list is initialized */ - assert(head->queue.init); + HDassert(head->queue.init); /* Use block routine */ H5FL_blk_free(&(head->queue),obj); @@ -1873,8 +1848,8 @@ H5FL_seq_malloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_seq_malloc, NULL) /* Double check parameters */ - assert(head); - assert(elem); + HDassert(head); + HDassert(elem); /* Use block routine */ ret_value=H5FL_blk_malloc(&(head->queue),head->size*elem H5FL_TRACK_INFO_INT); @@ -1907,8 +1882,8 @@ H5FL_seq_calloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS) FUNC_ENTER_NOAPI(H5FL_seq_calloc, NULL) /* Double check parameters */ - assert(head); - assert(elem); + HDassert(head); + HDassert(elem); /* Use block routine */ ret_value=H5FL_blk_calloc(&(head->queue),head->size*elem H5FL_TRACK_INFO_INT); @@ -1941,8 +1916,8 @@ H5FL_seq_realloc(H5FL_seq_head_t *head, void * obj, size_t new_elem H5FL_TRACK_P FUNC_ENTER_NOAPI(H5FL_seq_realloc, NULL) /* Double check parameters */ - assert(head); - assert(new_elem); + HDassert(head); + HDassert(new_elem); /* Use block routine */ ret_value=H5FL_blk_realloc(&(head->queue),obj,head->size*new_elem H5FL_TRACK_INFO_INT); @@ -1964,14 +1939,18 @@ done: * Wednesday, February 2, 2005 * * Modifications: + * Neil Fortner + * Friday, December 19, 2008 + * Totally rewritten to support new factory implementation * *------------------------------------------------------------------------- */ H5FL_fac_head_t * H5FL_fac_init(size_t size) { - H5FL_fac_head_t *factory; /* Pointer to new block factory */ - H5FL_fac_head_t *ret_value; /* Return value */ + H5FL_fac_gc_node_t *new_node; /* Pointer to the node for the new list to garbage collect */ + H5FL_fac_head_t *factory; /* Pointer to new block factory */ + H5FL_fac_head_t *ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5FL_fac_init, NULL) @@ -1979,15 +1958,38 @@ H5FL_fac_init(size_t size) HDassert(size>0); /* Allocate room for the new factory */ - if(NULL==(factory=H5FL_MALLOC(H5FL_fac_head_t))) + if(NULL == (factory = (H5FL_fac_head_t *)H5FL_CALLOC(H5FL_fac_head_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for factory object") - /* Initialize block header information */ - HDmemset(&(factory->queue),0,sizeof(H5FL_blk_head_t)); - /* Set size of blocks for factory */ factory->size=size; + /* Allocate a new garbage collection node */ + if(NULL == (new_node = (H5FL_fac_gc_node_t *)H5FL_MALLOC(H5FL_fac_gc_node_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Initialize the new garbage collection node */ + new_node->list = factory; + + /* Link in to the garbage collection list */ + new_node->next=H5FL_fac_gc_head.first; + H5FL_fac_gc_head.first=new_node; + if(new_node->next) + new_node->next->list->prev_gc=new_node; + /* The new factory's prev_gc field will be set to NULL */ + + /* Make certain that the space allocated is large enough to store a free list pointer (eventually) */ + if(factory->size<sizeof(H5FL_fac_node_t)) + factory->size=sizeof(H5FL_fac_node_t); + + /* Make certain there's room for tracking information, if any */ +#ifdef H5FL_TRACK + factory->size += sizeof(H5FL_track_t); +#endif /* H5FL_TRACK */ + + /* Indicate that the free list is initialized */ + factory->init=1; + /* Set return value */ ret_value=factory; @@ -2001,32 +2003,86 @@ done: * * Purpose: Release a block back to a factory & put on free list * - * Return: Success: Non-negative - * Failure: Negative + * Return: NULL * * Programmer: Quincey Koziol * Wednesday, February 2, 2005 * * Modifications: + * Neil Fortner + * Friday, December 19, 2008 + * Totally rewritten to support new factory implementation * *------------------------------------------------------------------------- */ void * H5FL_fac_free(H5FL_fac_head_t *head, void *obj) { - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FL_fac_free) + void *ret_value=NULL; /* Return value */ + + /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_free) /* Double check parameters */ - assert(head); - assert(obj); + HDassert(head); + HDassert(obj); + +#ifdef H5FL_TRACK + { + H5FL_track_t *trk = obj = ((unsigned char *)obj) - sizeof(H5FL_track_t); + + /* Free tracking information about the allocation location */ + H5CS_close_stack(trk->stack); + trk->stack = H5MM_xfree(trk->stack); + trk->file = H5MM_xfree(trk->file); + trk->func = H5MM_xfree(trk->func); + + /* Remove from "outstanding allocations" list */ + if(trk == H5FL_out_head_g) { + H5FL_out_head_g = H5FL_out_head_g->next; + if(H5FL_out_head_g) + H5FL_out_head_g->prev = NULL; + } /* end if */ + else { + trk->prev->next = trk->next; + if(trk->next) + trk->next->prev = trk->prev; + } /* end else */ + } +#endif /* H5FL_TRACK */ + +#ifdef H5FL_DEBUG + HDmemset(obj,255,head->size); +#endif /* H5FL_DEBUG */ /* Make certain that the free list is initialized */ - assert(head->queue.init); + HDassert(head->init); - /* Use block routine */ - H5FL_blk_free(&(head->queue),obj); + /* Link into the free list */ + ((H5FL_fac_node_t *)obj)->next=head->list; - FUNC_LEAVE_NOAPI(NULL) + /* Point free list at the node freed */ + head->list=(H5FL_fac_node_t *)obj; + + /* Increment the number of blocks on free list */ + head->onlist++; + + /* Increment the amount of "factory" freed memory globally */ + H5FL_fac_gc_head.mem_freed+=head->size; + + /* Check for exceeding free list memory use limits */ + /* First check this particular list */ + if(head->onlist * head->size > H5FL_fac_lst_mem_lim) + if(H5FL_fac_gc_list(head)<0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free") + + /* Then check the global amount memory on factory free lists */ + if(H5FL_fac_gc_head.mem_freed > H5FL_fac_glb_mem_lim) + if(H5FL_fac_gc()<0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, NULL, "garbage collection failed during free") + +done: + FUNC_LEAVE_NOAPI(ret_value) } /* end H5FL_fac_free() */ @@ -2042,6 +2098,9 @@ H5FL_fac_free(H5FL_fac_head_t *head, void *obj) * Wednesday, February 2, 2005 * * Modifications: + * Neil Fortner + * Friday, December 19, 2008 + * Totally rewritten to support new factory implementation * *------------------------------------------------------------------------- */ @@ -2050,13 +2109,54 @@ H5FL_fac_malloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS) { void *ret_value; /* Pointer to object to return */ - FUNC_ENTER_NOAPI(H5FL_fac_malloc, NULL) + /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_malloc) /* Double check parameters */ - assert(head); + HDassert(head); + HDassert(head->init); - /* Use block routine */ - ret_value=H5FL_blk_malloc(&(head->queue),head->size H5FL_TRACK_INFO_INT); + /* Check for nodes available on the free list first */ + if(head->list!=NULL) { + /* Get a pointer to the block on the free list */ + ret_value=(void *)(head->list); + + /* Remove node from free list */ + head->list=head->list->next; + + /* Decrement the number of blocks & memory on free list */ + head->onlist--; + + /* Decrement the amount of global "factory" free list memory in use */ + H5FL_fac_gc_head.mem_freed-=(head->size); + } /* end if */ + /* Otherwise allocate a node */ + else { + if (NULL==(ret_value = H5FL_malloc(head->size))) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Increment the number of blocks allocated in list */ + head->allocated++; + } /* end else */ + +#ifdef H5FL_TRACK + /* Copy allocation location information */ + ((H5FL_track_t *)ret_value)->stack = H5MM_calloc(sizeof(H5CS_t)); + H5CS_copy_stack(((H5FL_track_t *)ret_value)->stack); + ((H5FL_track_t *)ret_value)->file = H5MM_strdup(call_file); + ((H5FL_track_t *)ret_value)->func = H5MM_strdup(call_func); + ((H5FL_track_t *)ret_value)->line = call_line; + + /* Add to "outstanding allocations" list */ + ((H5FL_track_t *)ret_value)->prev = NULL; + ((H5FL_track_t *)ret_value)->next = H5FL_out_head_g; + if(H5FL_out_head_g) + H5FL_out_head_g->prev = (H5FL_track_t *)ret_value; + H5FL_out_head_g = (H5FL_track_t *)ret_value; + + /* Adjust for allocation tracking information */ + ret_value = ((unsigned char *)ret_value) + sizeof(H5FL_track_t); +#endif /* H5FL_TRACK */ done: FUNC_LEAVE_NOAPI(ret_value) @@ -2075,6 +2175,9 @@ done: * Wednesday, February 2, 2005 * * Modifications: + * Neil Fortner + * Friday, December 19, 2008 + * Totally rewritten to support new factory implementation * *------------------------------------------------------------------------- */ @@ -2083,17 +2186,115 @@ H5FL_fac_calloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS) { void *ret_value; /* Pointer to object to return */ - FUNC_ENTER_NOAPI(H5FL_fac_calloc, NULL) + /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */ + FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_calloc) /* Double check parameters */ - assert(head); + HDassert(head); - /* Use block routine */ - ret_value=H5FL_blk_calloc(&(head->queue),head->size H5FL_TRACK_INFO_INT); + /* Allocate the block */ + if (NULL==(ret_value = H5FL_fac_malloc(head H5FL_TRACK_INFO_INT))) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Clear to zeros */ + /* (Accomodate tracking information, if present) */ + HDmemset(ret_value,0,head->size - H5FL_TRACK_SIZE); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FL_fac_calloc() */ + +/*------------------------------------------------------------------------- + * Function: H5FL_fac_gc_list + * + * Purpose: Garbage collect on a particular factory free list + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Neil Fortner + * Friday, December 19, 2008 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FL_fac_gc_list(H5FL_fac_head_t *head) +{ + H5FL_fac_node_t *free_list; /* Pointer to nodes in free list being garbage collected */ + void *tmp; /* Temporary node pointer */ + size_t total_mem; /* Total memory used on list */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FL_fac_gc_list) + + /* Calculate the total memory used on this list */ + total_mem=head->onlist*head->size; + + /* For each free list being garbage collected, walk through the nodes and free them */ + free_list=head->list; + while(free_list!=NULL) { + tmp=free_list->next; + + /* Decrement the count of nodes allocated and free the node */ + head->allocated--; + + H5MM_free(free_list); + + free_list = (H5FL_fac_node_t *)tmp; + } /* end while */ + + /* Indicate no free nodes on the free list */ + head->list=NULL; + head->onlist=0; + + /* Decrement global count of free memory on "factory" lists */ + H5FL_fac_gc_head.mem_freed-=total_mem; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5FL_fac_gc_list() */ + + +/*------------------------------------------------------------------------- + * Function: H5FL_fac_gc + * + * Purpose: Garbage collect on all the factory free lists + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Neil Fortner + * Friday, December 19, 2008 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FL_fac_gc(void) +{ + H5FL_fac_gc_node_t *gc_node; /* Pointer into the list of things to garbage collect */ + herr_t ret_value=SUCCEED; /* return value*/ + + FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_gc) + + /* Walk through all the free lists, free()'ing the nodes */ + gc_node=H5FL_fac_gc_head.first; + while(gc_node!=NULL) { + /* Release the free nodes on the list */ + if(H5FL_fac_gc_list(gc_node->list)<0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "garbage collection of list failed") + + /* Go on to the next free list to garbage collect */ + gc_node=gc_node->next; + } /* end while */ + + /* Double check that all the memory on the free lists is recycled */ + HDassert(H5FL_fac_gc_head.mem_freed==0); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FL_fac_gc() */ /*------------------------------------------------------------------------- @@ -2108,29 +2309,50 @@ done: * Wednesday, February 2, 2005 * * Modifications: + * Neil Fortner + * Friday, December 19, 2008 + * Totally rewritten to support new factory implementation * *------------------------------------------------------------------------- */ herr_t H5FL_fac_term(H5FL_fac_head_t *factory) { - herr_t ret_value=SUCCEED; /* Return value */ + H5FL_fac_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */ + herr_t ret_value = SUCCEED; /* Return value */ + /* NOINIT OK here because this must be called after H5FL_fac_init -NAF */ FUNC_ENTER_NOAPI_NOINIT(H5FL_fac_term) /* Sanity check */ HDassert(factory); /* Garbage collect all the blocks in the factory's free list */ - if(H5FL_blk_gc_list(&(factory->queue))<0) + if(H5FL_fac_gc_list(factory)<0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "garbage collection of factory failed") /* Verify that all the blocks have been freed */ - if(factory->queue.allocated>0) + if(factory->allocated>0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "factory still has objects allocated") /* Unlink block free list for factory from global free list */ - H5FL_blk_unlink(&(factory->queue)); + if(factory->prev_gc) { + H5FL_fac_gc_node_t *last = factory->prev_gc; /* Garbage collection node before the one being removed */ + + HDassert(last->next->list == factory); + tmp = last->next->next; + (void)H5FL_FREE(H5FL_fac_gc_node_t, last->next); + last->next = tmp; + if(tmp) + tmp->list->prev_gc = last; + } else { + HDassert(H5FL_fac_gc_head.first->list == factory); + tmp = H5FL_fac_gc_head.first->next; + (void)H5FL_FREE(H5FL_fac_gc_node_t, H5FL_fac_gc_head.first); + H5FL_fac_gc_head.first = tmp; + if(tmp) + tmp->list->prev_gc = NULL; + } /* end else */ /* Free factory info */ (void)H5FL_FREE(H5FL_fac_head_t, factory); @@ -2141,6 +2363,52 @@ done: /*------------------------------------------------------------------------- + * Function: H5FL_fac_term_all + * + * Purpose: Terminate all block factories + * + * Return: 0. There should never be any outstanding allocations + * when this is called. + * + * Programmer: Neil Fortner + * Friday, December 19, 2008 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +H5FL_fac_term_all(void) +{ + H5FL_fac_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5FL_fac_term_all) + + /* Free the nodes on the garbage collection list */ + while(H5FL_fac_gc_head.first != NULL) { + tmp=H5FL_fac_gc_head.first->next; + +#ifdef H5FL_DEBUG +printf("H5FL_fac_term: head->size=%d, head->allocated=%d\n", (int)H5FL_fac_gc_head.first->list->size,(int)H5FL_fac_gc_head.first->list->allocated); +#endif /* H5FL_DEBUG */ + + /* The list cannot have any allocations outstanding */ + HDassert(H5FL_fac_gc_head.first->list->allocated == 0); + + /* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */ + H5FL_fac_gc_head.first->list->init = 0; + + /* Free the node from the garbage collection list */ + (void)H5FL_FREE(H5FL_fac_gc_node_t, H5FL_fac_gc_head.first); + + H5FL_fac_gc_head.first = tmp; + } /* end while */ + + FUNC_LEAVE_NOAPI(0) +} /* end H5FL_fac_term_all() */ + + +/*------------------------------------------------------------------------- * Function: H5FL_garbage_coll * * Purpose: Garbage collect on all the free lists @@ -2160,7 +2428,7 @@ H5FL_garbage_coll(void) { herr_t ret_value = SUCCEED; - FUNC_ENTER_NOAPI_NOINIT(H5FL_garbage_coll) + FUNC_ENTER_NOAPI(H5FL_garbage_coll, FAIL) /* Garbage collect the free lists for array objects */ if(H5FL_arr_gc()<0) @@ -2174,6 +2442,10 @@ H5FL_garbage_coll(void) if(H5FL_reg_gc()<0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect regular objects") + /* Garbage collect the free lists for factory objects */ + if(H5FL_fac_gc()<0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGC, FAIL, "can't garbage collect regular objects") + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FL_garbage_coll() */ @@ -2204,13 +2476,16 @@ done: * Programmer: Quincey Koziol * Wednesday, August 2, 2000 * - * Modifications: + * Modifications: Neil Fortner + * Wednesday, April 8, 2009 + * Added support for factory free lists * *------------------------------------------------------------------------- */ herr_t H5FL_set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_lim, - int arr_list_lim, int blk_global_lim, int blk_list_lim) + int arr_list_lim, int blk_global_lim, int blk_list_lim, int fac_global_lim, + int fac_list_lim) { herr_t ret_value = SUCCEED; @@ -2229,6 +2504,10 @@ H5FL_set_free_list_limits(int reg_global_lim, int reg_list_lim, int arr_global_l H5FL_blk_glb_mem_lim=(blk_global_lim==-1 ? UINT_MAX : (size_t)blk_global_lim); /* limit on each block free list */ H5FL_blk_lst_mem_lim=(blk_list_lim==-1 ? UINT_MAX : (size_t)blk_list_lim); + /* limit on all factory free lists */ + H5FL_fac_glb_mem_lim=(fac_global_lim==-1 ? UINT_MAX : (size_t)fac_global_lim); + /* limit on each factory free list */ + H5FL_fac_lst_mem_lim=(fac_list_lim==-1 ? UINT_MAX : (size_t)fac_list_lim); done: FUNC_LEAVE_NOAPI(ret_value) @@ -2264,7 +2543,7 @@ H5FL_term_interface(void) /* Garbage collect any nodes on the free lists */ (void)H5FL_garbage_coll(); - ret_value=H5FL_reg_term()+H5FL_arr_term()+H5FL_blk_term(); + ret_value=H5FL_reg_term()+H5FL_fac_term_all()+H5FL_arr_term()+H5FL_blk_term(); #ifdef H5FL_TRACK /* If we haven't freed all the allocated memory, dump out the list now */ diff --git a/src/H5FLprivate.h b/src/H5FLprivate.h index a799dc4..c1a865a 100644 --- a/src/H5FLprivate.h +++ b/src/H5FLprivate.h @@ -100,7 +100,6 @@ typedef struct H5FL_reg_head_t { unsigned init; /* Whether the free list has been initialized */ unsigned allocated; /* Number of blocks allocated */ unsigned onlist; /* Number of blocks on free list */ - size_t list_mem; /* Amount of memory on free list */ const char *name; /* Name of the type */ size_t size; /* Size of the blocks in the list */ H5FL_reg_node_t *list; /* List of free blocks */ @@ -112,7 +111,7 @@ typedef struct H5FL_reg_head_t { #define H5FL_REG_NAME(t) H5_##t##_reg_free_list #ifndef H5_NO_REG_FREE_LISTS /* Common macros for H5FL_DEFINE & H5FL_DEFINE_STATIC */ -#define H5FL_DEFINE_COMMON(t) H5FL_reg_head_t H5FL_REG_NAME(t)={0,0,0,0,#t,sizeof(t),NULL} +#define H5FL_DEFINE_COMMON(t) H5FL_reg_head_t H5FL_REG_NAME(t)={0,0,0,#t,sizeof(t),NULL} /* Declare a free list to manage objects of type 't' */ #define H5FL_DEFINE(t) H5_DLL H5FL_DEFINE_COMMON(t) @@ -349,11 +348,8 @@ typedef struct H5FL_seq_head_t { #define H5FL_SEQ_REALLOC(t,obj,new_elem) (t *)H5MM_realloc(obj,(new_elem)*sizeof(t)) #endif /* H5_NO_SEQ_FREE_LISTS */ -/* Data structure for free list block factory */ -typedef struct H5FL_fac_head_t { - H5FL_blk_head_t queue; /* Priority queue of blocks */ - size_t size; /* Size of the blocks managed */ -} H5FL_fac_head_t; +/* Forward declaration of the data structure for free list block factory */ +typedef struct H5FL_fac_head_t H5FL_fac_head_t; /* * Macros for defining & using free list factories @@ -381,30 +377,42 @@ typedef struct H5FL_fac_head_t { /* * Library prototypes. */ + /* Block free lists */ H5_DLL void * H5FL_blk_malloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS); H5_DLL void * H5FL_blk_calloc(H5FL_blk_head_t *head, size_t size H5FL_TRACK_PARAMS); H5_DLL void * H5FL_blk_free(H5FL_blk_head_t *head, void *block); H5_DLL void * H5FL_blk_realloc(H5FL_blk_head_t *head, void *block, size_t new_size H5FL_TRACK_PARAMS); H5_DLL htri_t H5FL_blk_free_block_avail(H5FL_blk_head_t *head, size_t size); + +/* Regular free lists */ H5_DLL void * H5FL_reg_malloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS); H5_DLL void * H5FL_reg_calloc(H5FL_reg_head_t *head H5FL_TRACK_PARAMS); H5_DLL void * H5FL_reg_free(H5FL_reg_head_t *head, void *obj); + +/* Array free lists */ H5_DLL void * H5FL_arr_malloc(H5FL_arr_head_t *head, size_t elem); H5_DLL void * H5FL_arr_calloc(H5FL_arr_head_t *head, size_t elem); H5_DLL void * H5FL_arr_free(H5FL_arr_head_t *head, void *obj); H5_DLL void * H5FL_arr_realloc(H5FL_arr_head_t *head, void *obj, size_t new_elem); + +/* Sequence free lists */ H5_DLL void * H5FL_seq_malloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS); H5_DLL void * H5FL_seq_calloc(H5FL_seq_head_t *head, size_t elem H5FL_TRACK_PARAMS); H5_DLL void * H5FL_seq_free(H5FL_seq_head_t *head, void *obj); H5_DLL void * H5FL_seq_realloc(H5FL_seq_head_t *head, void *obj, size_t new_elem H5FL_TRACK_PARAMS); + +/* Factory free lists */ H5_DLL H5FL_fac_head_t *H5FL_fac_init(size_t size); H5_DLL void * H5FL_fac_malloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS); H5_DLL void * H5FL_fac_calloc(H5FL_fac_head_t *head H5FL_TRACK_PARAMS); H5_DLL void * H5FL_fac_free(H5FL_fac_head_t *head, void *obj); H5_DLL herr_t H5FL_fac_term(H5FL_fac_head_t *head); + +/* General free list routines */ H5_DLL herr_t H5FL_garbage_coll(void); H5_DLL herr_t H5FL_set_free_list_limits(int reg_global_lim, int reg_list_lim, - int arr_global_lim, int arr_list_lim, int blk_global_lim, int blk_list_lim); + int arr_global_lim, int arr_list_lim, int blk_global_lim, int blk_list_lim, + int fac_global_lim, int fac_list_lim); H5_DLL int H5FL_term_interface(void); #endif |