Renamed stacktrace to memtrace
authorPekka Riikonen <priikone@localhost.localdomain>
Wed, 1 Oct 2008 09:27:49 +0000 (12:27 +0300)
committerPekka Riikonen <priikone@localhost.localdomain>
Wed, 1 Oct 2008 09:27:49 +0000 (12:27 +0300)
Also rewrote the internals to use SilcTree for tracking allocations for
increased performance when there are tens of thousands of allocations.
Changed AVL tree to not do any allocations in debug version.

configure.ad
lib/silcutil/Makefile.ad
lib/silcutil/memtrace.c [moved from lib/silcutil/stacktrace.c with 86% similarity]
lib/silcutil/memtrace.h [moved from lib/silcutil/stacktrace.h with 92% similarity]
lib/silcutil/silcavltree.c
lib/silcutil/silcmemory.c
lib/silcutil/silcmemory.h
lib/silcutil/silcruntime.h.in

index 1fe945ea7c33a5d22345b3cf764deeb0a6eced70..b2b9b3d4cf8b24ed9e694057761cb715bc6938ad 100644 (file)
@@ -716,17 +716,17 @@ AC_ARG_WITH(alignment,
     AC_DEFINE([SILC_ALIGNMENT], SILC_SIZEOF_VOID_P, [SILC_ALIGNMENT])
   ])
 
-# Stack trace checking
-__SILC_ENABLE_STACKTRACE=""
-AC_MSG_CHECKING(whether to enable stack tracing)
-AC_ARG_ENABLE(stack-trace,
-  [  --enable-stack-trace    enable memory stack trace],
+# Memory trace checking
+__SILC_ENABLE_MEMTRACE=""
+AC_MSG_CHECKING(whether to enable memory tracing)
+AC_ARG_ENABLE(mem-trace,
+  [  --enable-mem-trace      enable memory tracing],
   [
     case "${enableval}" in
     yes)
       AC_MSG_RESULT(yes)
-      AC_DEFINE([SILC_STACKTRACE], [], [SILC_STACKTRACE])
-      __SILC_ENABLE_STACKTRACE="#define __SILC_ENABLE_STACKTRACE 1"
+      AC_DEFINE([SILC_MEMTRACE], [], [SILC_MEMTRACE])
+      __SILC_ENABLE_MEMTRACE="#define __SILC_ENABLE_MEMTRACE 1"
       CFLAGS="$CFLAGS -rdynamic"
       PC_CFLAGS="$PC_CFLAGS -rdynamic"
       ;;
@@ -1248,7 +1248,7 @@ AC_SUBST(LIBS)
 AC_SUBST(SILC_LIB_INCLUDES)
 AC_SUBST(PC_CFLAGS)
 AC_SUBST(__SILC_ENABLE_DEBUG)
-AC_SUBST(__SILC_ENABLE_STACKTRACE)
+AC_SUBST(__SILC_ENABLE_MEMTRACE)
 AC_SUBST(__SILC_HAVE_PTHREAD)
 AC_SUBST(__RUNTIME_PACKAGE_VERSION)
 
index a3898ffbcb07fc63da0aa3a94c8dec372c945108..9ddeb19e79e0f68788a592405962281bb6ac545a 100644 (file)
@@ -29,8 +29,8 @@ endif
 
 DIST_SUBDIRS=win32 symbian unix tests
 
-SILC_DIST_SOURCE = stacktrace.c
-SILC_DIST_HEADER = stacktrace.h
+SILC_DIST_SOURCE = memtrace.c
+SILC_DIST_HEADER = memtrace.h
 
 noinst_LTLIBRARIES = libsilcutil.la
 
similarity index 86%
rename from lib/silcutil/stacktrace.c
rename to lib/silcutil/memtrace.c
index 60d8f056cea0180df85a20ce47d6c6e3d47881d2..4c14f2b4b799c897e7c5e458bfba97c84f1b070a 100644 (file)
@@ -1,6 +1,6 @@
 /*
 
-  stacktrace.c
+  memtrace.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
      setting this variable the program will show where the memory was
      originally allocated and freed.
 
+   SILC_MALLOC_NO_ALLOCATED
+
+     When set to value 1, the program will not check if given memory was
+     allocated.  This will speed up debugging but will not detect if freeing
+     memory that was never allocated.
+
    SILC_MALLOC_DUMP
 
      When set to value 1, in case of fatal error, dumps the memory location,
 
 #include "silcruntime.h"
 
-#ifdef SILC_STACKTRACE
+#ifdef SILC_MEMTRACE
 #include <execinfo.h>
 #include <signal.h>
 #include <malloc.h>
 #include <sys/mman.h>
 
-static void *st_blocks = NULL;
-static unsigned long st_blocks_count = 0;
+static SilcTree st_blocks;
 static unsigned long st_num_malloc = 0;
 static SilcBool dump = FALSE;
 static SilcBool no_free = FALSE;
 static SilcBool dump_mem = FALSE;
+static SilcBool no_allocated = FALSE;
 static SilcUInt32 pg = 0;
 static SilcMutex lock = NULL;
 
@@ -92,8 +98,7 @@ static SilcMutex lock = NULL;
 
 /* Memory block with stack trace */
 typedef struct SilcStBlockStruct {
-  struct SilcStBlockStruct *next;
-  struct SilcStBlockStruct *prev;
+  SilcTreeHeader h;
   void *stack[SILC_ST_DEPTH];  /* Stack trace */
   const char *file;            /* Allocation file in program */
   const char *free_file;       /* Free file in program */
@@ -125,6 +130,15 @@ typedef struct SilcStBlockStruct {
   ((SilcStBlock)(((unsigned char *)p) + (SILC_ST_GET_SIZE_ALIGN(size, pg) - \
                                         SILC_ST_GET_SIZE(size)) + 4))
 
+SilcCompareValue silc_st_compare(void *val1, void *val2, void *context)
+{
+  if (SILC_PTR_TO_32(val1) > SILC_PTR_TO_32(val2))
+    return SILC_COMPARE_GREATER_THAN;
+  if (SILC_PTR_TO_32(val1) < SILC_PTR_TO_32(val2))
+    return SILC_COMPARE_LESS_THAN;
+  return SILC_COMPARE_EQUAL_TO;
+}
+
 void silc_st_abort(SilcStBlock stack, const char *file, int line,
                   char *fmt, ...)
 {
@@ -204,10 +218,13 @@ void silc_st_sigsegv(int sig, siginfo_t *si, void *context)
                "SILC_MALLOC: access violation (overflow)\n");
 }
 
-void silc_st_stacktrace_init(void)
+void silc_st_memtrace_init(void)
 {
   const char *var;
 
+  silc_tree_init(st_blocks, SILC_TREE_AVL, silc_st_compare, NULL,
+                silc_offsetof(struct SilcStBlockStruct, h), FALSE);
+
   atexit(silc_st_dump);
   dump = TRUE;
 
@@ -215,6 +232,10 @@ void silc_st_stacktrace_init(void)
   if (var && *var == '1')
     no_free = TRUE;
 
+  var = silc_getenv("SILC_MALLOC_NO_ALLOCATED");
+  if (var && *var == '1')
+    no_allocated = TRUE;
+
   var = silc_getenv("SILC_MALLOC_DUMP");
   if (var && *var == '1')
     dump_mem = TRUE;
@@ -251,7 +272,7 @@ void *silc_st_malloc(size_t size, const char *file, int line)
   SilcStBlock stack;
 
   if (silc_unlikely(!dump))
-    silc_st_stacktrace_init();
+    silc_st_memtrace_init();
 
   if (pg) {
     unsigned char *ptr;
@@ -268,10 +289,9 @@ void *silc_st_malloc(size_t size, const char *file, int line)
     /* Protect the page */
     if (mprotect(stack, pg, PROT_NONE))
       silc_st_abort(NULL, file, line, "SILC_MALLOC: mprotect() error: %s\n",
-                   errno == ENOMEM ? "Cannot allocate memory. \nYour program "
-                   "leaks memory, allocates too much or system \n"
-                   "is out of memory.  The SILC_MALLOC_PROTECT cannot "
-                   "be used." : strerror(errno));
+                   errno == ENOMEM ? "Cannot allocate memory. \nOn Linux, try"
+                   " giving 'echo 1000000 >/proc/sys/vm/max_map_count',\n"
+                   "to get rid of the problem" : strerror(errno));
 
     /* Get the accessible page */
     stack = SILC_ST_GET_STACK_ALIGN(ptr, size, pg);
@@ -281,6 +301,7 @@ void *silc_st_malloc(size_t size, const char *file, int line)
       return NULL;
   }
 
+  memset(&stack->h, 0, sizeof(stack->h));
   stack->dumpped = 0;
   stack->file = file;
   stack->free_file = NULL;
@@ -290,15 +311,8 @@ void *silc_st_malloc(size_t size, const char *file, int line)
   stack->depth = backtrace(stack->stack, SILC_ST_DEPTH);
 
   silc_mutex_lock(lock);
-
-  stack->next = st_blocks;
-  stack->prev = NULL;
-  if (st_blocks)
-    ((SilcStBlock)st_blocks)->prev = stack;
-  st_blocks = stack;
-  st_blocks_count++;
+  silc_tree_add(st_blocks, stack);
   st_num_malloc++;
-
   silc_mutex_unlock(lock);
 
   if (!pg)
@@ -342,7 +356,7 @@ void *silc_st_realloc(void *ptr, size_t size, const char *file, int line)
 
 void silc_st_free(void *ptr, const char *file, int line)
 {
-  SilcStBlock stack, s;
+  SilcStBlock stack;
 
   if (!ptr)
     return;
@@ -356,23 +370,13 @@ void silc_st_free(void *ptr, const char *file, int line)
 
   stack = SILC_ST_GET_STACK(ptr);
 
-  silc_mutex_lock(lock);
-
-  /* Check if we have ever made this allocation */
-  for (s = st_blocks; s; s = s->next)
-    if (s == stack)
-      break;
-  if (s == NULL)
-    silc_st_abort(NULL, file, line,
-                 "SILC_MALLOC: %p was never allocated\n", stack);
+  /* Check for underflow */
+  if (stack->bound != SILC_ST_TOP_BOUND)
+    silc_st_abort(stack, file, line,
+                 "SILC_MALLOC: %p was written out of bounds (underflow)\n",
+                 stack);
 
   if (!pg) {
-    /* Check for underflow */
-    if (stack->bound != SILC_ST_TOP_BOUND)
-      silc_st_abort(stack, file, line,
-                   "SILC_MALLOC: %p was written out of bounds (underflow)\n",
-                   stack);
-
     /* Check for overflow */
     if (*SILC_ST_GET_BOUND(stack, stack->size) != SILC_ST_BOTTOM_BOUND)
       silc_st_abort(stack, file, line,
@@ -380,14 +384,16 @@ void silc_st_free(void *ptr, const char *file, int line)
                    stack);
   }
 
-  if (stack->next)
-    stack->next->prev = stack->prev;
-  if (stack->prev)
-    stack->prev->next = stack->next;
-  else
-    st_blocks = stack->next;
+  silc_mutex_lock(lock);
 
-  st_blocks_count--;
+  /* Check if we have ever made this allocation */
+  if (!no_allocated && !silc_tree_find(st_blocks, stack))
+    silc_st_abort(NULL, file, line,
+                 "SILC_MALLOC: %p was never allocated\n", stack);
+
+  if (!silc_tree_del(st_blocks, stack))
+    silc_st_abort(NULL, file, line,
+                 "SILC_MALLOC: %p was never allocated\n", stack);
 
   silc_mutex_unlock(lock);
 
@@ -441,7 +447,8 @@ void silc_st_dump(void)
   lock = NULL;
   silc_mutex_free(l);
 
-  for (stack = st_blocks; stack; stack = stack->next) {
+  for (stack = silc_tree_enumerate(st_blocks, NULL); stack != NULL;
+       stack = silc_tree_enumerate(st_blocks, stack)) {
     bytes = blocks = 0;
 
     if (stack->dumpped)
@@ -450,7 +457,7 @@ void silc_st_dump(void)
     leaks++;
 
     if (!fp) {
-      fp = fopen("stacktrace.log", "wb");
+      fp = fopen("memtrace.log", "wb");
       if (!fp)
        fp = stderr;
     }
@@ -459,7 +466,8 @@ void silc_st_dump(void)
     syms = backtrace_symbols(stack->stack, stack->depth);
 
     /* Find number of leaks and bytes leaked for this leak */
-    for (s = stack; s; s = s->next) {
+    for (s = silc_tree_enumerate(st_blocks, NULL); s != NULL;
+         s = silc_tree_enumerate(st_blocks, s)) {
       if (s->file == stack->file && s->line == stack->line &&
          s->depth == stack->depth &&
          !memcmp(s->stack, stack->stack,
@@ -496,13 +504,13 @@ void silc_st_dump(void)
     fprintf(stderr, "\nNo memory leaks\n");
   } else {
     fprintf(stderr,
-           "-----------------------------------------\n"
-           "-----------------------------------------\n"
-           " Memory leaks dumped to 'stacktrace.log'\n"
+           "---------------------------------------\n"
+           "---------------------------------------\n"
+           " Memory leaks dumped to 'memtrace.log'\n"
            " Leaks: %lu leaks, %lu blocks\n"
-           "-----------------------------------------\n"
-           "-----------------------------------------\n",
-           leaks, st_blocks_count);
+           "---------------------------------------\n"
+           "---------------------------------------\n",
+           leaks, (unsigned long)silc_tree_count(st_blocks));
     fprintf(stderr, "Number of allocations: %lu\n", st_num_malloc);
   }
 
@@ -510,4 +518,4 @@ void silc_st_dump(void)
     fclose(fp);
 }
 
-#endif /* SILC_STACKTRACE */
+#endif /* SILC_MEMTRACE */
similarity index 92%
rename from lib/silcutil/stacktrace.h
rename to lib/silcutil/memtrace.h
index 9463e1205d6d1d9e58af29e7db34376b2e70b1c4..015929949ee767c07145692871fc83227a0ff979 100644 (file)
@@ -1,6 +1,6 @@
 /*
 
-  stacktrace.h 
+  memtrace.h 
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
 
 */
 
-#ifndef STACKTRACE_H
-#define STACKTRACE_H
+#ifndef MEMTRACE_H
+#define MEMTRACE_H
 
 #ifndef SILCMEMORY_H
 #error "Do not include internal header file directly"
 #endif
 
 #if (defined(__GNUC__) && defined(HAVE_EXECINFO_H) &&                  \
-     defined(HAVE_BACKTRACE)) || defined(__SILC_ENABLE_STACKTRACE)
+     defined(HAVE_BACKTRACE)) || defined(__SILC_ENABLE_MEMTRACE)
 
 #undef strdup
 #define silc_malloc(s)      silc_st_malloc((s), __FILE__, __LINE__)
@@ -48,4 +48,4 @@ void silc_st_dump(void);
 #error "memory allocation stack trace not supported on this platform"
 #endif /* __GNUC__ && HAVE_EXECINFO_H && HAVE_BACKTRACE */
 
-#endif /* STACKTRACE_H */
+#endif /* MEMTRACE_H */
index 44d313e9bd9243a14acb51d1386d0b1cb988d8ca..837803e42498191460113e32104ef0fce7a39324 100644 (file)
 
 #include <silcruntime.h>
 
+/* Define to 1 if you want hash table debug enabled */
+#ifndef SILC_AVL_TREE_DEBUG
+#define SILC_AVL_TREE_DEBUG 0
+#endif /* !SILC_AVL_TREE_DEBUG */
+
+#if SILC_ALV_TREE_DEBUG == 1
+#define SILC_TREE_DEBUG(fmt) SILC_LOG_DEBUG(fmt)
+#else
+#define SILC_TREE_DEBUG(fmt)
+#endif
+
 /************************ Static utility functions **************************/
 
 /* Rotate left
@@ -149,13 +160,13 @@ void *silc_avl_tree_find(SilcTree *tree, void *entry,
   void *cmp_context = compare ? context : tree->context;
   int ret;
 
-  SILC_LOG_DEBUG(("AVL tree %p, find %p", tree, entry));
+  SILC_TREE_DEBUG(("AVL tree %p, find %p", tree, entry));
 
   h = tree->root;
   while (h) {
     ret = cmp(entry, SILC_TREE_GET_ENTRY(tree, h), cmp_context);
     if (ret == SILC_COMPARE_EQUAL_TO) {
-      SILC_LOG_DEBUG(("Found %p", SILC_TREE_GET_ENTRY(tree, h)));
+      SILC_TREE_DEBUG(("Found %p", SILC_TREE_GET_ENTRY(tree, h)));
       return SILC_TREE_GET_ENTRY(tree, h);
     }
     if (ret == SILC_COMPARE_STOP)
@@ -163,8 +174,8 @@ void *silc_avl_tree_find(SilcTree *tree, void *entry,
     h = ret > 0 ? h->right : h->left;
   }
 
-  SILC_LOG_DEBUG(("Not found"));
-  silc_set_errno(SILC_ERR_NOT_FOUND);
+  SILC_TREE_DEBUG(("Not found"));
+  silc_set_errno_nofail(SILC_ERR_NOT_FOUND);
   return NULL;
 }
 
@@ -175,7 +186,7 @@ SilcBool silc_avl_tree_add(SilcTree *tree, void *entry)
   SilcTreeHeader *h, *parent = NULL, *q = NULL;
   int ret = 0;
 
-  SILC_LOG_DEBUG(("AVL tree %p, adding %p", tree, entry));
+  SILC_TREE_DEBUG(("AVL tree %p, adding %p", tree, entry));
 
   /* If tree is empty, add to root */
   if (!tree->root) {
@@ -184,7 +195,7 @@ SilcBool silc_avl_tree_add(SilcTree *tree, void *entry)
     h->t = 0;
     tree->root = h;
 
-    SILC_LOG_DEBUG(("Entry %p added as root", entry));
+    SILC_TREE_DEBUG(("Entry %p added as root", entry));
 
     SILC_ASSERT(!tree->count);
     tree->count = 1;
@@ -196,13 +207,13 @@ SilcBool silc_avl_tree_add(SilcTree *tree, void *entry)
   while (h) {
     /* Same entry context must not be in tree */
     if (entry == SILC_TREE_GET_ENTRY(tree, h)) {
-      silc_set_errno(SILC_ERR_ALREADY_EXISTS);
+      silc_set_errno_nofail(SILC_ERR_ALREADY_EXISTS);
       return FALSE;
     }
 
     ret = tree->compare(entry, SILC_TREE_GET_ENTRY(tree, h), tree->context);
     if (!tree->duplicates && ret == SILC_COMPARE_EQUAL_TO) {
-      silc_set_errno(SILC_ERR_ALREADY_EXISTS);
+      silc_set_errno_nofail(SILC_ERR_ALREADY_EXISTS);
       return FALSE;
     }
 
@@ -215,7 +226,7 @@ SilcBool silc_avl_tree_add(SilcTree *tree, void *entry)
        h->dup->parent = q;
       q->dup = h->dup;
       h->dup = q;
-      SILC_LOG_DEBUG(("Entry %p is duplicate to %p", entry,
+      SILC_TREE_DEBUG(("Entry %p is duplicate to %p", entry,
                      SILC_TREE_GET_ENTRY(tree, h)));
       tree->count++;
       return TRUE;
@@ -234,8 +245,8 @@ SilcBool silc_avl_tree_add(SilcTree *tree, void *entry)
   else
     parent->right = h;
 
-  SILC_LOG_DEBUG(("Entry %p added, parent %p", entry,
-                 SILC_TREE_GET_ENTRY(tree, parent)));
+  SILC_TREE_DEBUG(("Entry %p added, parent %p", entry,
+                  SILC_TREE_GET_ENTRY(tree, parent)));
 
   /* Update the new entry */
   h->parent = parent;
@@ -276,10 +287,10 @@ SilcBool silc_avl_tree_del(SilcTree *tree, void *entry)
   SilcTreeHeader *h, *q, *out, *parent = NULL, tmp;
   int left;
 
-  SILC_LOG_DEBUG(("AVL tree %p, delete %p", tree, entry));
+  SILC_TREE_DEBUG(("AVL tree %p, delete %p", tree, entry));
 
   if (!tree->root || !entry) {
-    silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+    silc_set_errno_nofail(SILC_ERR_INVALID_ARGUMENT);
     return FALSE;
   }
 
@@ -318,7 +329,7 @@ SilcBool silc_avl_tree_del(SilcTree *tree, void *entry)
       h->right->parent = h->dup;
 
     /* Cleanup the deleted entry */
-    SILC_LOG_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
+    SILC_TREE_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
     h->parent = h->left = h->right = h->dup = NULL;
     h->t = 0;
 
@@ -360,7 +371,7 @@ SilcBool silc_avl_tree_del(SilcTree *tree, void *entry)
     out->parent = parent;
 
   /* Cleanup the deleted entry */
-  SILC_LOG_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
+  SILC_TREE_DEBUG(("Deleted %p", SILC_TREE_GET_ENTRY(tree, h)));
   h->parent = h->left = h->right = h->dup = NULL;
   h->t = 0;
 
index f57ff458d51ad70d00053dc3ec1ffaa794c4fb78..082ac06d4953eba80b0cf2d49993e0e80a9faa34 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "silcruntime.h"
 
-#ifndef SILC_STACKTRACE
+#ifndef SILC_MEMTRACE
 
 #define SILC_MAX_ALLOC (1024 * 1024L * 1024L)
 
@@ -106,7 +106,7 @@ char *silc_strdup(const char *str)
   return silc_memdup(str, strlen(str));
 }
 
-#endif /* !SILC_STACKTRACE */
+#endif /* !SILC_MEMTRACE */
 
 /* SilcStack aware routines */
 
index 74974e96309472784dd3616f446cb129648980e4..64c13b5b5243a7658d3aa454ad81bea68a576fa6 100644 (file)
@@ -30,7 +30,7 @@
 
 /* Prototypes */
 
-#ifndef SILC_STACKTRACE
+#ifndef SILC_MEMTRACE
 
 /****f* silcutil/silc_malloc
  *
@@ -131,8 +131,8 @@ void *silc_memdup(const void *ptr, size_t size);
 char *silc_strdup(const char *str);
 
 #else
-#include "stacktrace.h"
-#endif /* SILC_STACKTRACE */
+#include "memtrace.h"
+#endif /* SILC_MEMTRACE */
 
 
 /* Following functions that use SilcStack as memory source. */
index e553ea15c186004804b3af438c41b84cb904855d..6d20103c6d962a7b971ae9ccfaed2150cf252a8d 100644 (file)
@@ -51,7 +51,7 @@
    configured/compiled. */
 @__SILC_HAVE_PTHREAD@
 @__SILC_ENABLE_DEBUG@
-@__SILC_ENABLE_STACKTRACE@
+@__SILC_ENABLE_MEMTRACE@
 @__SILC_VA_COPY@
 
 /* Types */
@@ -193,10 +193,10 @@ extern "C" {
 #define SILC_DEBUG 1
 #endif /* __SILC_ENABLE_DEBUG */
 
-#ifdef __SILC_ENABLE_STACKTRACE
-#undef SILC_STACKTRACE
-#define SILC_STACKTRACE 1
-#endif /* __SILC_ENABLE_STACKTRACE */
+#ifdef __SILC_ENABLE_MEMTRACE
+#undef SILC_MEMTRACE
+#define SILC_MEMTRACE 1
+#endif /* __SILC_ENABLE_MEMTRACE */
 
 /* SILC Runtime Toolkit includes */
 #include <silctypes.h>