From aeb88422a0f7c8813dc04a3a3a14a414dd2ad2eb Mon Sep 17 00:00:00 2001 From: Thomas Porzelt Date: Sat, 26 Nov 2011 15:56:45 +0100 Subject: [PATCH] [profiler] export li_profiler_enabled and li_profiler_hashtable_insert/remove. add heap base/break/size to dump output --- include/lighttpd/profiler.h | 4 + src/common/profiler.c | 235 +++++++++++++++++++----------------- 2 files changed, 127 insertions(+), 112 deletions(-) diff --git a/include/lighttpd/profiler.h b/include/lighttpd/profiler.h index cea9999..5e2764c 100644 --- a/include/lighttpd/profiler.h +++ b/include/lighttpd/profiler.h @@ -1,6 +1,8 @@ #ifndef _LIGHTTPD_PROFILER_H_ #define _LIGHTTPD_PROFILER_H_ +extern gboolean li_profiler_enabled; /* read only */ + typedef struct liProfilerMem liProfilerMem; struct liProfilerMem { @@ -18,5 +20,7 @@ struct liProfilerMem { LI_API void li_profiler_enable(gchar *output_path); /* enables the profiler */ LI_API void li_profiler_finish(); LI_API void li_profiler_dump(gint minsize); /* dumps memory statistics to file specified in LI_PROFILE_MEM env var */ +LI_API void li_profiler_hashtable_insert(const gpointer addr, gsize size); /* registers an allocated block with the profiler */ +LI_API void li_profiler_hashtable_remove(const gpointer addr); /* unregisters an allocated block with the profiler */ #endif diff --git a/src/common/profiler.c b/src/common/profiler.c index 9f1fc08..f218b58 100644 --- a/src/common/profiler.c +++ b/src/common/profiler.c @@ -49,6 +49,9 @@ static GStaticMutex profiler_mutex = G_STATIC_MUTEX_INIT; static profiler_block *block_free_list = NULL; static profiler_block **profiler_hashtable = NULL; static gint profiler_output_fd = 0; +static gpointer profiler_heap_base = NULL; + +gboolean li_profiler_enabled = FALSE; static guint profiler_hash(gpointer addr) { @@ -80,62 +83,18 @@ static void profiler_block_free(profiler_block *block) { block_free_list = block; } -static void profiler_hashtable_insert(gpointer addr, gsize size) { - profiler_block *block; - guint hash; - - hash = profiler_hash(addr); - - block = profiler_block_new(); - block->addr = addr; - block->size = size; -#ifdef HAVE_EXECINFO_H - block->stackframes_num = backtrace(block->stackframes, PROFILER_STACKFRAMES); -#endif - - block->next = profiler_hashtable[hash % PROFILER_HASHTABLE_SIZE]; - profiler_hashtable[hash % PROFILER_HASHTABLE_SIZE] = block; -} - -static void profiler_hashtable_remove(gpointer addr) { - profiler_block *block, *block_prev; - guint hash; - - hash = profiler_hash(addr); - - block = profiler_hashtable[hash % PROFILER_HASHTABLE_SIZE]; - - if (block->addr == addr) { - profiler_hashtable[hash % PROFILER_HASHTABLE_SIZE] = block->next; - profiler_block_free(block); - return; - } - - block_prev = block; - for (block = block->next; block != NULL; block = block->next) { - if (block->addr == addr) { - block_prev->next = block->next; - profiler_block_free(block); - return; - } - block_prev = block; - } -} - static gpointer profiler_try_malloc(gsize n_bytes) { gsize *p; p = malloc(n_bytes); if (p) { - g_static_mutex_lock(&profiler_mutex); #if defined(LIGHTY_OS_MACOSX) n_bytes = malloc_size(p); #elif defined(LIGHTY_OS_LINUX) n_bytes = malloc_usable_size(p); #endif - profiler_hashtable_insert(p, n_bytes); - g_static_mutex_unlock(&profiler_mutex); + li_profiler_hashtable_insert(p, n_bytes); } return p; @@ -163,15 +122,13 @@ static gpointer profiler_try_realloc(gpointer mem, gsize n_bytes) { p = realloc(mem, n_bytes); if (p) { - g_static_mutex_lock(&profiler_mutex); - profiler_hashtable_remove(mem); + li_profiler_hashtable_remove(mem); #if defined(LIGHTY_OS_MACOSX) n_bytes = malloc_size(p); #elif defined(LIGHTY_OS_LINUX) n_bytes = malloc_usable_size(p); #endif - profiler_hashtable_insert(p, n_bytes); - g_static_mutex_unlock(&profiler_mutex); + li_profiler_hashtable_insert(p, n_bytes); } return p; @@ -192,14 +149,12 @@ static gpointer profiler_calloc(gsize n_blocks, gsize n_bytes) { p = calloc(1, size); if (p) { - g_static_mutex_lock(&profiler_mutex); #if defined(LIGHTY_OS_MACOSX) n_bytes = malloc_size(p); #elif defined(LIGHTY_OS_LINUX) n_bytes = malloc_usable_size(p); #endif - profiler_hashtable_insert(p, n_bytes); - g_static_mutex_unlock(&profiler_mutex); + li_profiler_hashtable_insert(p, n_bytes); } assert(p); @@ -209,11 +164,7 @@ static gpointer profiler_calloc(gsize n_blocks, gsize n_bytes) { static void profiler_free(gpointer mem) { assert(mem); - - g_static_mutex_lock(&profiler_mutex); - profiler_hashtable_remove(mem); - g_static_mutex_unlock(&profiler_mutex); - + li_profiler_hashtable_remove(mem); free(mem); } @@ -234,59 +185,7 @@ static void profiler_write(gchar *str, gint len) { } } -/* public functions */ -void li_profiler_enable(gchar *output_path) { - GMemVTable t; - - if (g_str_equal(output_path, "stdout")) { - profiler_output_fd = STDOUT_FILENO; - } else if (g_str_equal(output_path, "stderr")) { - profiler_output_fd = STDERR_FILENO; - } else { - profiler_output_fd = open(output_path, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (-1 == profiler_output_fd) { - fputs("error opening profiler output file\n", stderr); - fflush(stderr); - abort(); - } - } - - block_free_list = profiler_block_new(); - profiler_hashtable = calloc(sizeof(profiler_block), PROFILER_HASHTABLE_SIZE); - - t.malloc = profiler_malloc; - t.realloc = profiler_realloc; - t.free = profiler_free; - - t.calloc = profiler_calloc; - t.try_malloc = profiler_try_malloc; - t.try_realloc = profiler_try_realloc; - - g_mem_set_vtable(&t); -} - -void li_profiler_finish() { - guint i; - profiler_block *block, *block_tmp; - - for (i = 0; i < PROFILER_HASHTABLE_SIZE; i++) { - for (block = profiler_hashtable[i]; block != NULL;) { - block_tmp = block->next; - free(block); - block = block_tmp; - } - } - - for (block = block_free_list; block != NULL;) { - block_tmp = block->next; - free(block); - block = block_tmp; - } - - free(profiler_hashtable); -} - - +#ifdef HAVE_EXECINFO_H static void profiler_dump_frame(guint level, profiler_stackframe *frame, gsize minsize) { gchar str[1024]; gint len; @@ -344,6 +243,64 @@ static void profiler_dump_frame(guint level, profiler_stackframe *frame, gsize m frame = f; } } +#endif + +/* public functions */ +void li_profiler_enable(gchar *output_path) { + GMemVTable t; + + profiler_heap_base = sbrk(0); + + if (g_str_equal(output_path, "stdout")) { + profiler_output_fd = STDOUT_FILENO; + } else if (g_str_equal(output_path, "stderr")) { + profiler_output_fd = STDERR_FILENO; + } else { + profiler_output_fd = open(output_path, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (-1 == profiler_output_fd) { + fputs("error opening profiler output file\n", stderr); + fflush(stderr); + abort(); + } + } + + block_free_list = profiler_block_new(); + profiler_hashtable = calloc(sizeof(profiler_block), PROFILER_HASHTABLE_SIZE); + + t.malloc = profiler_malloc; + t.realloc = profiler_realloc; + t.free = profiler_free; + + t.calloc = profiler_calloc; + t.try_malloc = profiler_try_malloc; + t.try_realloc = profiler_try_realloc; + + g_mem_set_vtable(&t); + + li_profiler_enabled = TRUE; +} + +void li_profiler_finish() { + guint i; + profiler_block *block, *block_tmp; + + for (i = 0; i < PROFILER_HASHTABLE_SIZE; i++) { + for (block = profiler_hashtable[i]; block != NULL;) { + block_tmp = block->next; + free(block); + block = block_tmp; + } + } + + for (block = block_free_list; block != NULL;) { + block_tmp = block->next; + free(block); + block = block_tmp; + } + + free(profiler_hashtable); +} + void li_profiler_dump(gint minsize) { profiler_stackframe *tree_cur, *frame; @@ -411,10 +368,12 @@ void li_profiler_dump(gint minsize) { len = sprintf(str, "--------------- memory profiler summary ---------------\n" "total blocks: %u\n" - "total size: %"G_GSIZE_FORMAT" %s\n", + "total size: %"G_GSIZE_FORMAT" %s\n" + "heap base / break / size: %p / %p / %"G_GSIZE_FORMAT"\n", total_blocks, (total_size > 1024) ? total_size / 1024 : total_size, - (total_size > 1024) ? "kilobytes" : "bytes" + (total_size > 1024) ? "kilobytes" : "bytes", + profiler_heap_base, sbrk(0), (guintptr)sbrk(0) - (guintptr)profiler_heap_base ); profiler_write(str, len); @@ -426,3 +385,55 @@ void li_profiler_dump(gint minsize) { g_static_mutex_unlock(&profiler_mutex); } + +void li_profiler_hashtable_insert(const gpointer addr, gsize size) { + profiler_block *block; + guint hash; + + g_static_mutex_lock(&profiler_mutex); + + hash = profiler_hash(addr); + + block = profiler_block_new(); + block->addr = addr; + block->size = size; +#ifdef HAVE_EXECINFO_H + block->stackframes_num = backtrace(block->stackframes, PROFILER_STACKFRAMES); +#endif + + block->next = profiler_hashtable[hash % PROFILER_HASHTABLE_SIZE]; + profiler_hashtable[hash % PROFILER_HASHTABLE_SIZE] = block; + + g_static_mutex_unlock(&profiler_mutex); +} + +void li_profiler_hashtable_remove(const gpointer addr) { + profiler_block *block, *block_prev; + guint hash; + + g_static_mutex_lock(&profiler_mutex); + + hash = profiler_hash(addr); + + block = profiler_hashtable[hash % PROFILER_HASHTABLE_SIZE]; + + if (block->addr == addr) { + profiler_hashtable[hash % PROFILER_HASHTABLE_SIZE] = block->next; + profiler_block_free(block); + g_static_mutex_unlock(&profiler_mutex); + return; + } + + block_prev = block; + for (block = block->next; block != NULL; block = block->next) { + if (block->addr == addr) { + block_prev->next = block->next; + profiler_block_free(block); + g_static_mutex_unlock(&profiler_mutex); + return; + } + block_prev = block; + } + + g_static_mutex_unlock(&profiler_mutex); +}