From 8d3fed09443faa6a3c79b68b7800ed3472877a1c Mon Sep 17 00:00:00 2001 From: Jean Cyr Date: Tue, 13 May 2014 19:59:44 -0400 Subject: [PATCH 1/2] Reduce potential dataman memory fragmentation The data manager dynamically allocates relatively small work item blocks on an as needed basis. It never frees these, instead maintaining then in a list of available block for reuse when needed. Even if these blocks are small, the are required at non-deterministic times and can end up scattered in memory thus causing memory fragmentation. In order to mitigate this problems work item blocks are allocated in groups of 8 in contiguous memory to reduce the number of scattered memory allocations. In reality, based on current usage, rarely will more than one group of 8 be allocated. --- src/modules/dataman/dataman.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/modules/dataman/dataman.c b/src/modules/dataman/dataman.c index 7505ba3584..cbd9b2d7cd 100644 --- a/src/modules/dataman/dataman.c +++ b/src/modules/dataman/dataman.c @@ -100,6 +100,8 @@ typedef struct { }; } work_q_item_t; +const size_t k_work_item_allocation_chunk_size = 8; + /* Usage statistics */ static unsigned g_func_counts[dm_number_of_funcs]; @@ -177,9 +179,20 @@ create_work_item(void) unlock_queue(&g_free_q); - /* If we there weren't any free items then obtain memory for a new one */ - if (item == NULL) - item = (work_q_item_t *)malloc(sizeof(work_q_item_t)); + /* If we there weren't any free items then obtain memory for a new ones */ + if (item == NULL) { + item = (work_q_item_t *)malloc(k_work_item_allocation_chunk_size * sizeof(work_q_item_t)); + if (item) { + lock_queue(&g_free_q); + for (int i = 1; i < k_work_item_allocation_chunk_size; i++) + sq_addfirst(&(item + i)->link, &(g_free_q.q)); + /* Update the queue size and potentially the maximum queue size */ + g_free_q.size += k_work_item_allocation_chunk_size - 1; + if (g_free_q.size > g_free_q.max_size) + g_free_q.max_size = g_free_q.size; + unlock_queue(&g_free_q); + } + } /* If we got one then lock the item*/ if (item) From cd9a72e391948fbf620c8cb129020ae7ecc9cab3 Mon Sep 17 00:00:00 2001 From: Jean Cyr Date: Tue, 13 May 2014 20:24:19 -0400 Subject: [PATCH 2/2] Free data manager work items the same way they were allocated Since data manager work items are allocated in groups of 8, they need to be freed the same way should the manager need to stop. --- src/modules/dataman/dataman.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/modules/dataman/dataman.c b/src/modules/dataman/dataman.c index cbd9b2d7cd..16703899db 100644 --- a/src/modules/dataman/dataman.c +++ b/src/modules/dataman/dataman.c @@ -75,7 +75,8 @@ typedef enum { typedef struct { sq_entry_t link; /**< list linkage */ sem_t wait_sem; - dm_function_t func; + unsigned char first; + unsigned char func; ssize_t result; union { struct { @@ -183,9 +184,12 @@ create_work_item(void) if (item == NULL) { item = (work_q_item_t *)malloc(k_work_item_allocation_chunk_size * sizeof(work_q_item_t)); if (item) { + item->first = 1; lock_queue(&g_free_q); - for (int i = 1; i < k_work_item_allocation_chunk_size; i++) + for (int i = 1; i < k_work_item_allocation_chunk_size; i++) { + (item + i)->first = 0; sq_addfirst(&(item + i)->link, &(g_free_q.q)); + } /* Update the queue size and potentially the maximum queue size */ g_free_q.size += k_work_item_allocation_chunk_size - 1; if (g_free_q.size > g_free_q.max_size) @@ -730,8 +734,8 @@ task_main(int argc, char *argv[]) for (;;) { if ((work = (work_q_item_t *)sq_remfirst(&(g_free_q.q))) == NULL) break; - - free(work); + if (work->first) + free(work); } destroy_q(&g_work_q);