summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>2000-07-27 21:17:35 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>2000-07-27 21:17:35 (GMT)
commit55ea4084df14d187b308c35b7e0cc42d83e647ee (patch)
tree6212884eef667e55776a0dd9d9ef34ed9f23e69c
parent2c8c5f96924b1e143d6047b802eda1aed9003d1c (diff)
downloadhdf5-55ea4084df14d187b308c35b7e0cc42d83e647ee.zip
hdf5-55ea4084df14d187b308c35b7e0cc42d83e647ee.tar.gz
hdf5-55ea4084df14d187b308c35b7e0cc42d83e647ee.tar.bz2
[svn-r2445] Check in initial coding effort for automatically garbage collecting the free
lists. Each kind of list one has hard-coded limits on when to garbage collect, which will be replaced with user-controllable knobs (through property list settings, I think) once I finish debugging some related performance problems.
-rw-r--r--src/H5FL.c497
-rw-r--r--src/H5FLprivate.h10
2 files changed, 350 insertions, 157 deletions
diff --git a/src/H5FL.c b/src/H5FL.c
index e4dd7a4..2edd919 100644
--- a/src/H5FL.c
+++ b/src/H5FL.c
@@ -30,32 +30,61 @@ static intn interface_initialize_g = 0;
* Private type definitions
*/
-/* A garbage collection node for priority queues */
-typedef struct H5FL_blk_gc_list_t {
- H5FL_blk_head_t *pq; /* Pointer to the head of the PQ to garbage collect */
- struct H5FL_blk_gc_list_t *next; /* Pointer to the next node in the list of things to garbage collect */
-} H5FL_blk_gc_list_t;
+/*
+ Default limits on how much memory can accumulate on each free list before
+ it is garbage collected.
+ */
+#define H5FL_REG_GLB_MEM_LIM (10*1024*1024) /* Default to 10MB total on all regular free lists */
+#define H5FL_REG_LST_MEM_LIM (512*1024) /* Default to 512KB on each regular free list */
+#define H5FL_ARR_GLB_MEM_LIM (10*1024*1024) /* Default to 10MB total on all array free lists */
+#define H5FL_ARR_LST_MEM_LIM (2*1024*1024) /* Default to 2MB on each array free list */
+#define H5FL_BLK_GLB_MEM_LIM (10*1024*1024) /* Default to 10MB total on all block free lists */
+#define H5FL_BLK_LST_MEM_LIM (2*1024*1024) /* Default to 2MB on each block free list */
/* A garbage collection node for regular free lists */
-typedef struct H5FL_gc_list_t {
+typedef struct H5FL_gc_node_t {
H5FL_head_t *list; /* Pointer to the head of the list to garbage collect */
- struct H5FL_gc_list_t *next; /* Pointer to the next node in the list of things to garbage collect */
+ struct H5FL_gc_node_t *next; /* Pointer to the next node in the list of things to garbage collect */
+} H5FL_gc_node_t;
+
+/* The garbage collection head for regular free lists */
+typedef struct H5FL_gc_list_t {
+ size_t mem_freed; /* Amount of free memory on list */
+ struct H5FL_gc_node_t *first; /* Pointer to the first node in the list of things to garbage collect */
} H5FL_gc_list_t;
+/* The head of the list of things to garbage collect */
+static H5FL_gc_list_t H5FL_gc_head={0,NULL};
+
/* A garbage collection node for array free lists */
-typedef struct H5FL_gc_arr_list_t {
+typedef struct H5FL_gc_arr_node_t {
H5FL_arr_head_t *list; /* Pointer to the head of the list to garbage collect */
- struct H5FL_gc_arr_list_t *next; /* Pointer to the next node in the list of things to garbage collect */
+ struct H5FL_gc_arr_node_t *next; /* Pointer to the next node in the list of things to garbage collect */
+} H5FL_gc_arr_node_t;
+
+/* The garbage collection head for array free lists */
+typedef struct H5FL_gc_arr_list_t {
+ size_t mem_freed; /* Amount of free memory on list */
+ struct H5FL_gc_arr_node_t *first; /* Pointer to the first node in the list of things to garbage collect */
} H5FL_gc_arr_list_t;
-/* The head of the list of PQs to garbage collect */
-static H5FL_blk_gc_list_t *H5FL_blk_gc_head=NULL;
+/* The head of the list of array things to garbage collect */
+static H5FL_gc_arr_list_t H5FL_arr_gc_head={0,NULL};
-/* The head of the list of things to garbage collect */
-static H5FL_gc_list_t *H5FL_gc_head=NULL;
+/* A garbage collection node for blocks */
+typedef struct H5FL_blk_gc_node_t {
+ H5FL_blk_head_t *pq; /* Pointer to the head of the PQ to garbage collect */
+ struct H5FL_blk_gc_node_t *next; /* Pointer to the next node in the list of things to garbage collect */
+} H5FL_blk_gc_node_t;
-/* The head of the list of array things to garbage collect */
-static H5FL_gc_arr_list_t *H5FL_gc_arr_head=NULL;
+/* The garbage collection head for blocks */
+typedef struct H5FL_blk_gc_list_t {
+ size_t mem_freed; /* Amount of free memory on list */
+ struct H5FL_blk_gc_node_t *first; /* Pointer to the first node in the list of things to garbage collect */
+} 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};
/* Macros for turning off free lists in the library */
/* #define NO_FREE_LISTS */
@@ -65,6 +94,14 @@ static H5FL_gc_arr_list_t *H5FL_gc_arr_head=NULL;
#define NO_BLK_FREE_LISTS
#endif /* NO_FREE_LISTS */
+/* Forward declarations of local static functions */
+static herr_t H5FL_gc(void);
+static herr_t H5FL_gc_list(H5FL_head_t *head);
+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);
+
/*-------------------------------------------------------------------------
* Function: H5FL_init
@@ -85,21 +122,21 @@ static H5FL_gc_arr_list_t *H5FL_gc_arr_head=NULL;
static herr_t
H5FL_init(H5FL_head_t *head)
{
- H5FL_gc_list_t *new_list; /* Pointer to the node for the new list to garbage collect */
- herr_t ret_value=SUCCEED; /* return value*/
+ H5FL_gc_node_t *new_node; /* Pointer to the node for the new list to garbage collect */
+ herr_t ret_value=SUCCEED; /* return value*/
FUNC_ENTER (H5FL_init, FAIL);
/* Allocate a new garbage collection node */
- if (NULL==(new_list = H5MM_malloc(sizeof(H5FL_gc_list_t))))
+ if (NULL==(new_node = H5MM_malloc(sizeof(H5FL_gc_node_t))))
HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
/* Initialize the new garbage collection node */
- new_list->list=head;
+ new_node->list=head;
/* Link in to the garbage collection list */
- new_list->next=H5FL_gc_head;
- H5FL_gc_head=new_list;
+ new_node->next=H5FL_gc_head.first;
+ H5FL_gc_head.first=new_node;
/* Indicate that the free list is initialized */
head->init=1;
@@ -160,6 +197,19 @@ H5FL_free(H5FL_head_t *head, void *obj)
/* Increment the number of blocks on free list */
head->onlist++;
+
+ /* Increment the amount of "regular" freed memory globally */
+ H5FL_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_REG_LST_MEM_LIM)
+ H5FL_gc_list(head);
+
+ /* Then check the global amount memory on regular free lists */
+ if(H5FL_gc_head.mem_freed>H5FL_REG_GLB_MEM_LIM)
+ H5FL_gc();
+
#endif /* NO_REG_FREE_LISTS */
FUNC_LEAVE(NULL);
@@ -216,6 +266,10 @@ H5FL_alloc(H5FL_head_t *head, uintn clear)
/* Decrement the number of blocks on free list */
head->onlist--;
+
+ /* Decrement the amount of global "regular" free list memory in use */
+ H5FL_gc_head.mem_freed-=(head->size);
+
} /* end if */
/* Otherwise allocate a node */
else {
@@ -243,62 +297,100 @@ H5FL_alloc(H5FL_head_t *head, uintn clear)
/*-------------------------------------------------------------------------
- * Function: H5FL_gc
+ * Function: H5FL_gc_list
*
- * Purpose: Garbage collect on all the object free lists
+ * Purpose: Garbage collect on a particular object free list
*
* Return: Success: Non-negative
* Failure: Negative
*
* Programmer: Quincey Koziol
- * Friday, March 24, 2000
+ * Tuesday, July 25, 2000
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
static herr_t
-H5FL_gc(void)
+H5FL_gc_list(H5FL_head_t *head)
{
- H5FL_gc_list_t *gc_list; /* Pointer into the list of things to garbage collect */
- H5FL_head_t *list_head; /* Pointer to head of free list to garbage collect */
H5FL_node_t *free_list; /* Pointer to nodes in free list being garbage collected */
- void *tmp; /* Temporary node pointer */
+ void *tmp; /* Temporary node pointer */
+ size_t total_mem; /* Total memory used on list */
/* FUNC_ENTER_INIT() should not be called, it causes an infinite loop at library termination */
- H5_trace(FALSE, "H5FL_gc", "");
+ H5_trace(FALSE, "H5FL_gc_list", "");
- /* Walk through all the free lists, free()'ing the nodes */
- gc_list=H5FL_gc_head;
- while(gc_list!=NULL) {
- /* Get the pointer to the list head */
- list_head=gc_list->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=list_head->list;
- while(free_list!=NULL) {
- tmp=free_list->next;
+ /* 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 */
- list_head->allocated--;
+ /* Decrement the count of nodes allocated and free the node */
+ head->allocated--;
#ifdef H5FL_DEBUG
- assert(!free_list->inuse);
+ assert(!free_list->inuse);
#endif /* H5FL_DEBUG */
- H5MM_xfree(free_list);
+ H5MM_xfree(free_list);
- free_list=tmp;
- } /* end while */
+ free_list=tmp;
+ } /* end while */
- /* Indicate no free nodes on the free list */
- list_head->list=NULL;
- list_head->onlist=0;
+ /* Indicate no free nodes on the free list */
+ head->list=NULL;
+ head->onlist=0;
+
+ /* Decrement global count of free memory on "regular" lists */
+ H5FL_gc_head.mem_freed-=total_mem;
+
+ H5_trace(TRUE, NULL, "e", SUCCEED);
+ return(SUCCEED);
+} /* end H5FL_gc_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_gc
+ *
+ * Purpose: Garbage collect on all the object free lists
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Friday, March 24, 2000
+ *
+ * Modifications:
+ * Broke into two parts, one for looping over all the free lists and
+ * another for freeing each list - QAK 7/25/00
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL_gc(void)
+{
+ H5FL_gc_node_t *gc_node; /* Pointer into the list of things to garbage collect */
+
+ /* FUNC_ENTER_INIT() should not be called, it causes an infinite loop at library termination */
+ H5_trace(FALSE, "H5FL_gc", "");
+
+ /* Walk through all the free lists, free()'ing the nodes */
+ gc_node=H5FL_gc_head.first;
+ while(gc_node!=NULL) {
+ /* Release the free nodes on the list */
+ H5FL_gc_list(gc_node->list);
/* Go on to the next free list to garbage collect */
- gc_list=gc_list->next;
+ gc_node=gc_node->next;
} /* end while */
+ /* Double check that all the memory on the free lists is recycled */
+ assert(H5FL_gc_head.mem_freed==0);
+
H5_trace(TRUE, NULL, "e", SUCCEED);
return(SUCCEED);
} /* end H5FL_gc() */
@@ -332,44 +424,45 @@ H5FL_gc(void)
static intn
H5FL_term(void)
{
- H5FL_gc_list_t *left; /* pointer to garbage collection lists with work left */
- H5FL_gc_list_t *tmp; /* Temporary pointer to a garbage collection node */
+ H5FL_gc_node_t *left; /* pointer to garbage collection lists with work left */
+ H5FL_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */
if (interface_initialize_g) {
/* Free the nodes on the garbage collection list, keeping nodes with allocations outstanding */
left=NULL;
- while(H5FL_gc_head!=NULL) {
- tmp=H5FL_gc_head->next;
+ while(H5FL_gc_head.first!=NULL) {
+ tmp=H5FL_gc_head.first->next;
#ifdef H5FL_DEBUG
- printf("H5FL_term: head->name=%s, head->allocated=%d\n", H5FL_gc_head->list->name,(int)H5FL_gc_head->list->allocated);
+ printf("H5FL_term: head->name=%s, head->allocated=%d\n", H5FL_gc_head.first->list->name,(int)H5FL_gc_head.first->list->allocated);
#endif /* H5FL_DEBUG */
/* Check if the list has allocations outstanding */
- if(H5FL_gc_head->list->allocated>0) {
+ if(H5FL_gc_head.first->list->allocated>0) {
/* Add free list to the list of nodes with allocations open still */
- H5FL_gc_head->next=left;
- left=H5FL_gc_head;
+ H5FL_gc_head.first->next=left;
+ left=H5FL_gc_head.first;
} /* end if */
/* No allocations left open for list, get rid of it */
else {
/* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */
- H5FL_gc_head->list->init=0;
+ H5FL_gc_head.first->list->init=0;
/* Free the node from the garbage collection list */
- H5MM_xfree(H5FL_gc_head);
+ H5MM_xfree(H5FL_gc_head.first);
} /* end else */
- H5FL_gc_head=tmp;
+ H5FL_gc_head.first=tmp;
} /* end while */
/* Point to the list of nodes left with allocations open, if any */
- H5FL_gc_head=left;
- if (!left) interface_initialize_g = 0; /*this layer has reached its initial state*/
+ H5FL_gc_head.first=left;
+ if (!left)
+ interface_initialize_g = 0; /*this layer has reached its initial state*/
}
/* Terminating this layer never affects other layers; rather, other layers affect
* the termination of this layer. */
- return 0;
+ return(0);
} /* end H5FL_term() */
@@ -500,21 +593,21 @@ done:
static herr_t
H5FL_blk_init(H5FL_blk_head_t *head)
{
- H5FL_blk_gc_list_t *new_pq; /* Pointer to the node for the new list to garbage collect */
+ H5FL_blk_gc_node_t *new_node; /* Pointer to the node for the new list to garbage collect */
herr_t ret_value=SUCCEED; /* return value*/
FUNC_ENTER (H5FL_blk_init, FAIL);
/* Allocate a new garbage collection node */
- if (NULL==(new_pq = H5MM_malloc(sizeof(H5FL_blk_gc_list_t))))
+ if (NULL==(new_node = H5MM_malloc(sizeof(H5FL_blk_gc_node_t))))
HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
/* Initialize the new garbage collection node */
- new_pq->pq=head;
+ new_node->pq=head;
/* Link in to the garbage collection list */
- new_pq->next=H5FL_blk_gc_head;
- H5FL_blk_gc_head=new_pq;
+ new_node->next=H5FL_blk_gc_head.first;
+ H5FL_blk_gc_head.first=new_node;
/* Indicate that the PQ is initialized */
head->init=1;
@@ -570,8 +663,13 @@ H5FL_blk_alloc(H5FL_blk_head_t *head, size_t size, uintn clear)
ret_value=((char *)(free_list->list))+sizeof(H5FL_blk_list_t);
free_list->list=free_list->list->next;
- /* Decrement the number of blocks on free list */
+ /* Decrement the number of blocks & memory on free list */
head->onlist--;
+ head->list_mem-=size;
+
+ /* Decrement the amount of global "block" free list memory in use */
+ H5FL_blk_gc_head.mem_freed-=size;
+
} /* end if */
/* No free list available, or there are no nodes on the list, allocate a new node to give to the user */
else {
@@ -650,6 +748,28 @@ H5FL_blk_free(H5FL_blk_head_t *head, void *block)
/* Increment the number of blocks on free list */
head->onlist++;
+ head->list_mem+=temp->size;
+
+ /* Increment the amount of "block" freed memory globally */
+ H5FL_blk_gc_head.mem_freed+=temp->size;
+
+ /* Check for exceeding free list memory use limits */
+ /* First check this particular list */
+ if(head->list_mem>H5FL_BLK_LST_MEM_LIM) {
+#ifdef QAK
+printf("%s: temp->size=%u, head->name=%s, head->list_mem=%u, H5FL_blk_gc_head.mem_freed=%u, garbage collecting list\n",FUNC,(unsigned)temp->size,head->name,(unsigned)head->list_mem,(unsigned)H5FL_blk_gc_head.mem_freed);
+#endif /* QAK */
+ H5FL_blk_gc_list(head);
+ } /* end if */
+
+ /* Then check the global amount memory on block free lists */
+ if(H5FL_blk_gc_head.mem_freed>H5FL_BLK_GLB_MEM_LIM) {
+#ifdef QAK
+printf("%s: head->name=%s, garbage collecting all block lists\n",FUNC,head->name);
+#endif /* QAK */
+ H5FL_blk_gc();
+ } /* end if */
+
#endif /* NO_BLK_FREE_LISTS */
FUNC_LEAVE(NULL);
@@ -746,8 +866,12 @@ H5FL_blk_gc_list(H5FL_blk_head_t *head)
while(list!=NULL) {
next=list->next;
- /* Decrement the number of blocks allocated from this PQ */
+ /* Decrement the number of blocks & memory allocated from this PQ */
head->allocated--;
+ head->list_mem-=list->size;
+
+ /* Decrement global count of free memory on "block" lists */
+ H5FL_blk_gc_head.mem_freed-=list->size;
/* Free the block */
H5MM_xfree(list);
@@ -762,6 +886,13 @@ H5FL_blk_gc_list(H5FL_blk_head_t *head)
head->head=temp;
} /* end while */
+ /* Indicate no free nodes on the free list */
+ head->head=NULL;
+ head->onlist=0;
+
+ /* Double check that all the memory on this lists is recycled */
+ assert(head->list_mem==0);
+
H5_trace(TRUE, NULL, "e", SUCCEED);
return(SUCCEED);
} /* end H5FL_blk_gc_list() */
@@ -785,29 +916,24 @@ H5FL_blk_gc_list(H5FL_blk_head_t *head)
static herr_t
H5FL_blk_gc(void)
{
- H5FL_blk_gc_list_t *gc_list; /* Pointer into the list of things to garbage collect */
- H5FL_blk_head_t *pq_head; /* Pointer to head of PQ to garbage collect */
+ H5FL_blk_gc_node_t *gc_node; /* Pointer into the list of things to garbage collect */
/* FUNC_ENTER_INIT() should not be called, it causes an infinite loop at library termination */
H5_trace(FALSE, "H5FL_blk_gc", "");
/* Walk through all the free lists, free()'ing the nodes */
- gc_list=H5FL_blk_gc_head;
- while(gc_list!=NULL) {
- /* Get the pointer to the list head */
- pq_head=gc_list->pq;
-
+ gc_node=H5FL_blk_gc_head.first;
+ while(gc_node!=NULL) {
/* For each free list being garbage collected, walk through the nodes and free them */
- H5FL_blk_gc_list(gc_list->pq);
-
- /* Indicate no free nodes on the free list */
- pq_head->head=NULL;
- pq_head->onlist=0;
+ H5FL_blk_gc_list(gc_node->pq);
/* Go on to the next free list to garbage collect */
- gc_list=gc_list->next;
+ gc_node=gc_node->next;
} /* end while */
+ /* Double check that all the memory on the free lists are recycled */
+ assert(H5FL_blk_gc_head.mem_freed==0);
+
H5_trace(TRUE, NULL, "e", SUCCEED);
return(SUCCEED);
} /* end H5FL_blk_gc() */
@@ -835,40 +961,40 @@ H5FL_blk_gc(void)
static intn
H5FL_blk_term(void)
{
- H5FL_blk_gc_list_t *left; /* pointer to garbage collection lists with work left */
- H5FL_blk_gc_list_t *tmp; /* Temporary pointer to a garbage collection node */
+ H5FL_blk_gc_node_t *left; /* pointer to garbage collection lists with work left */
+ H5FL_blk_gc_node_t *tmp; /* Temporary pointer to a garbage collection node */
/* Free the nodes on the garbage collection list, keeping nodes with allocations outstanding */
left=NULL;
- while(H5FL_blk_gc_head!=NULL) {
- tmp=H5FL_blk_gc_head->next;
+ while(H5FL_blk_gc_head.first!=NULL) {
+ tmp=H5FL_blk_gc_head.first->next;
#ifdef H5FL_DEBUG
-printf("H5FL_blk_term: head->name=%s, head->allocated=%d\n", H5FL_blk_gc_head->pq->name,(int)H5FL_blk_gc_head->pq->allocated);
+printf("H5FL_blk_term: head->name=%s, head->allocated=%d\n", H5FL_blk_gc_head.first->pq->name,(int)H5FL_blk_gc_head.first->pq->allocated);
#endif /* H5FL_DEBUG */
/* Check if the list has allocations outstanding */
- if(H5FL_blk_gc_head->pq->allocated>0) {
+ if(H5FL_blk_gc_head.first->pq->allocated>0) {
/* Add free list to the list of nodes with allocations open still */
- H5FL_blk_gc_head->next=left;
- left=H5FL_blk_gc_head;
+ H5FL_blk_gc_head.first->next=left;
+ left=H5FL_blk_gc_head.first;
} /* end if */
/* No allocations left open for list, get rid of it */
else {
/* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */
- H5FL_blk_gc_head->pq->init=0;
+ H5FL_blk_gc_head.first->pq->init=0;
/* Free the node from the garbage collection list */
- H5MM_xfree(H5FL_blk_gc_head);
+ H5MM_xfree(H5FL_blk_gc_head.first);
} /* end else */
- H5FL_blk_gc_head=tmp;
+ H5FL_blk_gc_head.first=tmp;
} /* end while */
/* Point to the list of nodes left with allocations open, if any */
- H5FL_blk_gc_head=left;
+ H5FL_blk_gc_head.first=left;
- return (H5FL_blk_gc_head!=NULL ? 1 : 0);
-}
+ return (H5FL_blk_gc_head.first!=NULL ? 1 : 0);
+} /* end H5FL_blk_term() */
/*-------------------------------------------------------------------------
@@ -890,31 +1016,34 @@ printf("H5FL_blk_term: head->name=%s, head->allocated=%d\n", H5FL_blk_gc_head->p
static herr_t
H5FL_arr_init(H5FL_arr_head_t *head)
{
- H5FL_gc_arr_list_t *new_list; /* Pointer to the node for the new list to garbage collect */
+ H5FL_gc_arr_node_t *new_node; /* Pointer to the node for the new list to garbage collect */
herr_t ret_value=SUCCEED; /* return value*/
FUNC_ENTER (H5FL_arr_init, FAIL);
/* Allocate a new garbage collection node */
- if (NULL==(new_list = H5MM_malloc(sizeof(H5FL_gc_arr_list_t))))
+ if (NULL==(new_node = H5MM_malloc(sizeof(H5FL_gc_arr_node_t))))
HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
/* Initialize the new garbage collection node */
- new_list->list=head;
+ new_node->list=head;
/* Link in to the garbage collection list */
- new_list->next=H5FL_gc_arr_head;
- H5FL_gc_arr_head=new_list;
+ new_node->next=H5FL_arr_gc_head.first;
+ H5FL_arr_gc_head.first=new_node;
/* Allocate room for the free lists, if the arrays have a maximum size */
if(head->maxelem>0) {
if (NULL==(head->u.list_arr = H5MM_calloc(head->maxelem*sizeof(H5FL_arr_node_t *))))
HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
+ if (NULL==(head->onlist = H5MM_calloc(head->maxelem*sizeof(uintn))))
+ HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
} /* end if */
else {
head->u.queue.init=0;
head->u.queue.allocated=0;
head->u.queue.onlist=0;
+ head->u.queue.list_mem=0;
head->u.queue.name=head->name;
head->u.queue.head=NULL;
} /* end else */
@@ -945,6 +1074,8 @@ void *
H5FL_arr_free(H5FL_arr_head_t *head, void *obj)
{
H5FL_arr_node_t *temp; /* Temp. ptr to the new free list node allocated */
+ intn i; /* Counter for array of free lists */
+ size_t list_mem; /* Memory used on list */
FUNC_ENTER (H5FL_arr_free, NULL);
@@ -973,9 +1104,24 @@ H5FL_arr_free(H5FL_arr_head_t *head, void *obj)
head->u.list_arr[temp->nelem]=temp;
/* Increment the number of blocks on free lists */
- head->onlist++;
+ head->onlist[temp->nelem]++;
+
+ /* Increment the amount of "array" freed memory globally */
+ H5FL_arr_gc_head.mem_freed+=head->size*temp->nelem;
+
+ /* Check for exceeding free list memory use limits */
+ /* First check this particular list */
+ for(list_mem=0, i=0; i<head->maxelem; i++)
+ list_mem+=head->onlist[i]*i*head->size;
+ if(list_mem>H5FL_ARR_LST_MEM_LIM)
+ H5FL_arr_gc_list(head);
+
+ /* Then check the global amount memory on array free lists */
+ if(H5FL_arr_gc_head.mem_freed>H5FL_ARR_GLB_MEM_LIM)
+ H5FL_arr_gc();
+
} /* end if */
- /* No maximum number of elements, use PQ routine */
+ /* No maximum number of elements, use block routine */
else {
H5FL_blk_free(&(head->u.queue),obj);
} /* end else */
@@ -1032,7 +1178,11 @@ H5FL_arr_alloc(H5FL_arr_head_t *head, uintn elem, uintn clear)
head->u.list_arr[elem]=head->u.list_arr[elem]->next;
/* Decrement the number of blocks on free list */
- head->onlist--;
+ head->onlist[elem]--;
+
+ /* Decrement the amount of global "array" free list memory in use */
+ H5FL_arr_gc_head.mem_freed-=(head->size*elem);
+
} /* end if */
/* Otherwise allocate a node */
else {
@@ -1129,69 +1279,107 @@ H5FL_arr_realloc(H5FL_arr_head_t *head, void * obj, uintn new_elem)
/*-------------------------------------------------------------------------
- * Function: H5FL_arr_gc
+ * Function: H5FL_arr_gc_list
*
- * Purpose: Garbage collect on all the array object free lists
+ * Purpose: Garbage collect on an array object free list
*
* Return: Success: Non-negative
* Failure: Negative
*
* Programmer: Quincey Koziol
- * Saturday, March 25, 2000
+ * Tuesday, July 25, 2000
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
static herr_t
-H5FL_arr_gc(void)
+H5FL_arr_gc_list(H5FL_arr_head_t *head)
{
- H5FL_gc_arr_list_t *gc_arr_list; /* Pointer into the list of things to garbage collect */
- H5FL_arr_head_t *arr_list_head; /* Pointer to head of free list to garbage collect */
H5FL_arr_node_t *arr_free_list; /* Pointer to nodes in free list being garbage collected */
void *tmp; /* Temporary node pointer */
intn i; /* Counter for array of free lists */
+ size_t total_mem; /* Total memory used on list */
/* FUNC_ENTER_INIT() should not be called, it causes an infinite loop at library termination */
- H5_trace(FALSE, "H5FL_arr_gc", "");
+ H5_trace(FALSE, "H5FL_arr_gc_list", "");
- /* Walk through all the free lists, free()'ing the nodes */
- gc_arr_list=H5FL_gc_arr_head;
- while(gc_arr_list!=NULL) {
- /* Get the pointer to the list head */
- arr_list_head=gc_arr_list->list;
-
- /* Check if the array has a fixed maximum number of elements */
- if(arr_list_head->maxelem>0) {
- /* Walk through the array of free lists */
- for(i=0; i<arr_list_head->maxelem; i++) {
+ /* Check if the array has a fixed maximum number of elements */
+ if(head->maxelem>0) {
+ /* Walk through the array of free lists */
+ for(i=0; i<head->maxelem; i++) {
+ if(head->onlist[i]>0) {
+ /* Calculate the total memory used on this list */
+ total_mem=head->onlist[i]*i*head->size;
/* For each free list being garbage collected, walk through the nodes and free them */
- arr_free_list=arr_list_head->u.list_arr[i];
+ arr_free_list=head->u.list_arr[i];
while(arr_free_list!=NULL) {
tmp=arr_free_list->next;
/* Decrement the count of nodes allocated and free the node */
- arr_list_head->allocated--;
+ head->allocated--;
H5MM_xfree(arr_free_list);
arr_free_list=tmp;
} /* end while */
/* Indicate no free nodes on the free list */
- arr_list_head->u.list_arr[i]=NULL;
- arr_list_head->onlist=0;
- } /* end for */
- } /* end if */
- /* No maximum number of elements, just use the PQ call to garbage collect */
- else {
- H5FL_blk_gc_list(&(arr_list_head->u.queue));
- } /* end else */
+ head->u.list_arr[i]=NULL;
+ head->onlist[i]=0;
+
+ /* Decrement global count of free memory on "array" lists */
+ H5FL_arr_gc_head.mem_freed-=total_mem;
+ } /* end if */
+
+ } /* end for */
+ } /* end if */
+ /* No maximum number of elements, use the block call to garbage collect */
+ else {
+ H5FL_blk_gc_list(&(head->u.queue));
+ } /* end else */
+
+ H5_trace(TRUE, NULL, "e", SUCCEED);
+ return(SUCCEED);
+} /* end H5FL_arr_gc_list() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5FL_arr_gc
+ *
+ * Purpose: Garbage collect on all the array object free lists
+ *
+ * Return: Success: Non-negative
+ * Failure: Negative
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, March 25, 2000
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5FL_arr_gc(void)
+{
+ H5FL_gc_arr_node_t *gc_arr_node; /* Pointer into the list of things to garbage collect */
+
+ /* FUNC_ENTER_INIT() should not be called, it causes an infinite loop at library termination */
+ H5_trace(FALSE, "H5FL_arr_gc", "");
+
+ /* Walk through all the free lists, free()'ing the nodes */
+ gc_arr_node=H5FL_arr_gc_head.first;
+ while(gc_arr_node!=NULL) {
+ /* Release the free nodes on the list */
+ H5FL_arr_gc_list(gc_arr_node->list);
/* Go on to the next free list to garbage collect */
- gc_arr_list=gc_arr_list->next;
+ gc_arr_node=gc_arr_node->next;
} /* end while */
+ /* Double check that all the memory on the free lists are recycled */
+ assert(H5FL_arr_gc_head.mem_freed==0);
+
H5_trace(TRUE, NULL, "e", SUCCEED);
return(SUCCEED);
} /* end H5FL_arr_gc() */
@@ -1219,65 +1407,68 @@ H5FL_arr_gc(void)
static intn
H5FL_arr_term(void)
{
- H5FL_gc_arr_list_t *left; /* pointer to garbage collection lists with work left */
- H5FL_gc_arr_list_t *tmp; /* Temporary pointer to a garbage collection node */
+ H5FL_gc_arr_node_t *left; /* pointer to garbage collection lists with work left */
+ H5FL_gc_arr_node_t *tmp; /* Temporary pointer to a garbage collection node */
/* Free the nodes on the garbage collection list, keeping nodes with allocations outstanding */
left=NULL;
- while(H5FL_gc_arr_head!=NULL) {
- tmp=H5FL_gc_arr_head->next;
+ while(H5FL_arr_gc_head.first!=NULL) {
+ tmp=H5FL_arr_gc_head.first->next;
/* Check if the array has a fixed maximum number of elements */
- if(H5FL_gc_arr_head->list->maxelem>0) {
+ if(H5FL_arr_gc_head.first->list->maxelem>0) {
/* Check if the list has allocations outstanding */
#ifdef H5FL_DEBUG
-printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_gc_arr_head->list->name,(int)H5FL_gc_arr_head->list->allocated);
+printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_arr_gc_head.first->list->name,(int)H5FL_arr_gc_head.first->list->allocated);
#endif /* H5FL_DEBUG */
- if(H5FL_gc_arr_head->list->allocated>0) {
+ if(H5FL_arr_gc_head.first->list->allocated>0) {
/* Add free list to the list of nodes with allocations open still */
- H5FL_gc_arr_head->next=left;
- left=H5FL_gc_arr_head;
+ H5FL_arr_gc_head.first->next=left;
+ left=H5FL_arr_gc_head.first;
} /* end if */
/* No allocations left open for list, get rid of it */
else {
/* Free the array of free lists */
- H5MM_xfree(H5FL_gc_arr_head->list->u.list_arr);
+ H5MM_xfree(H5FL_arr_gc_head.first->list->u.list_arr);
+
+ /* Free the array of "onlist" counts */
+ H5MM_xfree(H5FL_arr_gc_head.first->list->onlist);
/* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */
- H5FL_gc_arr_head->list->init=0;
+ H5FL_arr_gc_head.first->list->init=0;
/* Free the node from the garbage collection list */
- H5MM_xfree(H5FL_gc_arr_head);
+ H5MM_xfree(H5FL_arr_gc_head.first);
} /* end else */
} /* end if */
/* No maximum number of elements, use the PQ information */
else {
#ifdef H5FL_DEBUG
-printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_gc_arr_head->list->name,(int)H5FL_gc_arr_head->list->u.queue.allocated);
+printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_arr_gc_head->list->name,(int)H5FL_arr_gc_head->list->u.queue.allocated);
#endif /* H5FL_DEBUG */
/* Check if the list has allocations outstanding */
- if(H5FL_gc_arr_head->list->u.queue.allocated>0) {
+ if(H5FL_arr_gc_head.first->list->u.queue.allocated>0) {
/* Add free list to the list of nodes with allocations open still */
- H5FL_gc_arr_head->next=left;
- left=H5FL_gc_arr_head;
+ H5FL_arr_gc_head.first->next=left;
+ left=H5FL_arr_gc_head.first;
} /* end if */
/* No allocations left open for list, get rid of it */
else {
/* Reset the "initialized" flag, in case we restart this list somehow (I don't know how..) */
- H5FL_gc_arr_head->list->init=0;
+ H5FL_arr_gc_head.first->list->init=0;
/* Free the node from the garbage collection list */
- H5MM_xfree(H5FL_gc_arr_head);
+ H5MM_xfree(H5FL_arr_gc_head.first);
} /* end else */
} /* end else */
- H5FL_gc_arr_head=tmp;
+ H5FL_arr_gc_head.first=tmp;
} /* end while */
/* Point to the list of nodes left with allocations open, if any */
- H5FL_gc_arr_head=left;
+ H5FL_arr_gc_head.first=left;
- return (H5FL_gc_arr_head!=NULL ? 1 : 0);
+ return (H5FL_arr_gc_head.first!=NULL ? 1 : 0);
} /* end H5FL_arr_term() */
diff --git a/src/H5FLprivate.h b/src/H5FLprivate.h
index e64ba1e..56739e9 100644
--- a/src/H5FLprivate.h
+++ b/src/H5FLprivate.h
@@ -95,15 +95,16 @@ typedef struct H5FL_blk_head_t {
uintn init; /* Whether the free list has been initialized */
uintn allocated; /* Number of blocks allocated */
uintn onlist; /* Number of blocks on free list */
+ size_t list_mem; /* Amount of memory in block on free list */
const char *name; /* Name of the type */
H5FL_blk_node_t *head; /* Pointer to first free list in queue */
-}H5FL_blk_head_t;
+} H5FL_blk_head_t;
/*
* Macros for defining & using priority queues
*/
/* Declare a free list to manage objects of type 't' */
-#define H5FL_BLK_DEFINE(t) H5FL_blk_head_t t##_pq={0,0,0,#t,NULL}
+#define H5FL_BLK_DEFINE(t) H5FL_blk_head_t t##_pq={0,0,0,0,#t,NULL}
/* Reference a free list for type 't' defined in another file */
#define H5FL_BLK_EXTERN(t) extern H5FL_blk_head_t t##_pq
@@ -134,7 +135,8 @@ typedef struct H5FL_arr_node_t {
typedef struct H5FL_arr_head_t {
uintn init; /* Whether the free list has been initialized */
uintn allocated; /* Number of blocks allocated */
- uintn onlist; /* Number of blocks on free list */
+ uintn *onlist; /* Number of blocks on free list */
+ size_t list_mem; /* Amount of memory in block on free list */
const char *name; /* Name of the type */
intn maxelem; /* Maximum number of elements in an array */
size_t size; /* Size of the array elements in the list */
@@ -148,7 +150,7 @@ typedef struct H5FL_arr_head_t {
* Macros for defining & using free lists for an array of a type
*/
/* Declare a free list to manage arrays of type 't' */
-#define H5FL_ARR_DEFINE(t,m) H5FL_arr_head_t t##_arr_free_list={0,0,0,#t##"_arr",m,sizeof(t),{NULL}}
+#define H5FL_ARR_DEFINE(t,m) H5FL_arr_head_t t##_arr_free_list={0,0,NULL,0,#t##"_arr",m,sizeof(t),{NULL}}
/* Reference a free list for arrays of type 't' defined in another file */
#define H5FL_ARR_EXTERN(t) extern H5FL_arr_head_t t##_arr_free_list