Mesa (debug-refcnt): auxiliary: add reference count debugging code

Luca Barbieri lb at kemper.freedesktop.org
Tue Aug 17 23:10:41 UTC 2010


Module: Mesa
Branch: debug-refcnt
Commit: 9c2e8179b2048d277902adf62c0219851e25884d
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=9c2e8179b2048d277902adf62c0219851e25884d

Author: Luca Barbieri <luca at luca-barbieri.com>
Date:   Wed Aug 18 00:40:33 2010 +0200

auxiliary: add reference count debugging code

---

 src/gallium/auxiliary/Makefile              |    1 +
 src/gallium/auxiliary/SConscript            |    1 +
 src/gallium/auxiliary/util/u_debug_refcnt.c |  151 +++++++++++++++++++++++++++
 src/gallium/auxiliary/util/u_debug_refcnt.h |   29 +++++
 4 files changed, 182 insertions(+), 0 deletions(-)

diff --git a/src/gallium/auxiliary/Makefile b/src/gallium/auxiliary/Makefile
index 2dae479..e9b96aa 100644
--- a/src/gallium/auxiliary/Makefile
+++ b/src/gallium/auxiliary/Makefile
@@ -93,6 +93,7 @@ C_SOURCES = \
 	translate/translate_cache.c \
 	util/u_debug.c \
 	util/u_debug_describe.c \
+	util/u_debug_refcnt.c \
 	util/u_debug_symbol.c \
 	util/u_debug_stack.c \
 	util/u_dump_defines.c \
diff --git a/src/gallium/auxiliary/SConscript b/src/gallium/auxiliary/SConscript
index 43774e3..992732f 100644
--- a/src/gallium/auxiliary/SConscript
+++ b/src/gallium/auxiliary/SConscript
@@ -148,6 +148,7 @@ source = [
     'util/u_debug.c',
     'util/u_debug_describe.c',
     'util/u_debug_memory.c',
+    'util/u_debug_refcnt.c',
     'util/u_debug_stack.c',
     'util/u_debug_symbol.c',
     'util/u_dump_defines.c',
diff --git a/src/gallium/auxiliary/util/u_debug_refcnt.c b/src/gallium/auxiliary/util/u_debug_refcnt.c
new file mode 100644
index 0000000..5b9c0f0
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_debug_refcnt.c
@@ -0,0 +1,151 @@
+#if defined(DEBUG) && (!defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_WINDOWS_USER))
+
+/* see http://www.mozilla.org/performance/refcnt-balancer.html for what do with the output
+ * on Linux, use tools/addr2line.sh to postprocess it before anything else
+ **/
+#include <util/u_debug.h>
+#include <util/u_debug_refcnt.h>
+#include <util/u_debug_stack.h>
+#include <util/u_debug_symbol.h>
+#include <stdio.h>
+#include <util/u_hash_table.h>
+#include <os/os_thread.h>
+
+int util_debug_refcnt_state;
+
+static FILE* fp;
+
+/* TODO: maybe move this serial machinery to a stand-alone module and expose it? */
+static pipe_mutex serials_mutex;
+static struct util_hash_table* serials_hash;
+static unsigned serials_last;
+
+static unsigned hash_ptr(void* p)
+{
+   return (unsigned)(uintptr_t)p;
+}
+
+static int compare_ptr(void* a, void* b)
+{
+   if(a == b)
+      return 0;
+   else if(a < b)
+      return -1;
+   else
+      return 1;
+}
+
+static boolean util_debug_serial(void* p, unsigned* pserial)
+{
+   unsigned serial;
+   boolean found = TRUE;
+   pipe_mutex_lock(serials_mutex);
+   if(!serials_hash)
+      serials_hash = util_hash_table_create(hash_ptr, compare_ptr);
+   serial = (unsigned)(uintptr_t)util_hash_table_get(serials_hash, p);
+   if(!serial)
+   {
+      /* time to stop logging... (you'll have a 100 GB logfile at least at this point)
+       * TODO: avoid this
+       */
+      serial = ++serials_last;
+      if(!serial)
+      {
+         fprintf(stderr, "More than 2^32 objects detected, aborting.\n");
+         abort();
+      }
+
+      util_hash_table_set(serials_hash, p, (void*)(uintptr_t)serial);
+      found = FALSE;
+   }
+   pipe_mutex_unlock(serials_mutex);
+   *pserial = serial;
+   return found;
+}
+
+static void util_debug_serial_delete(void* p)
+{
+   pipe_mutex_lock(serials_mutex);
+   util_hash_table_remove(serials_hash, p);
+   pipe_mutex_unlock(serials_mutex);
+}
+
+#define STACK_LEN 64
+
+static void dump_stack(char symbols[STACK_LEN][1024])
+{
+   unsigned i;
+   for(i = 0; i < STACK_LEN; ++i)
+   {
+      if(symbols[i][0])
+         fprintf(fp, "%s\n", symbols[i]);
+   }
+   fprintf(fp, "\n");
+}
+
+void util_debug_reference_slowpath(const struct pipe_reference* p, void* pget_desc, const char* op)
+{
+   if(util_debug_refcnt_state < 0)
+      return;
+
+   if(!util_debug_refcnt_state)
+   {
+      const char* filename = debug_get_option("GALLIUM_REFCNT_LOG", NULL);
+      if(filename && filename[0])
+         fp = fopen(filename, "w");
+
+      if(fp)
+         util_debug_refcnt_state = 1;
+      else
+         util_debug_refcnt_state = -1;
+   }
+
+   if(util_debug_refcnt_state > 0)
+   {
+      struct debug_stack_frame frames[STACK_LEN];
+      char symbols[STACK_LEN][1024];
+      char buf[1024];
+
+      void (*get_desc)(char*, const struct pipe_reference*) = pget_desc;
+      unsigned i;
+      unsigned refcnt = p->count;
+      unsigned serial;
+      boolean existing = util_debug_serial((void*)p, &serial);
+
+      debug_backtrace_capture(frames, 1, STACK_LEN);
+      for(i = 0; i < STACK_LEN; ++i)
+      {
+         if(frames[i].function)
+            debug_symbol_name(frames[i].function, symbols[i], sizeof(symbols[i]));
+         else
+            symbols[i][0] = 0;
+      }
+
+      get_desc(buf, p);
+
+      if(!existing)
+      {
+         fprintf(fp, "<%s> %p %u Create\n", buf, p, serial);
+         dump_stack(symbols);
+
+         for(i = 1; i < refcnt; ++i)
+         {
+            fprintf(fp, "<%s> %p %u AddRef %u\n", buf, p, serial, i);
+            dump_stack(symbols);
+         }
+      }
+
+      fprintf(fp, "<%s> %p %u %s %u\n", buf, p, serial, op, refcnt);
+      dump_stack(symbols);
+
+      if(!refcnt)
+      {
+         util_debug_serial_delete((void*)p);
+         fprintf(fp, "<%s> %p %u Destroy\n", buf, p, serial);
+         dump_stack(symbols);
+      }
+
+      fflush(fp);
+   }
+}
+#endif
diff --git a/src/gallium/auxiliary/util/u_debug_refcnt.h b/src/gallium/auxiliary/util/u_debug_refcnt.h
new file mode 100644
index 0000000..9728fe6
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_debug_refcnt.h
@@ -0,0 +1,29 @@
+/*
+ * u_debug_refcnt.h
+ *
+ *  Created on: Aug 17, 2010
+ *      Author: lb
+ */
+
+#ifndef U_DEBUG_REFCNT_H_
+#define U_DEBUG_REFCNT_H_
+
+#include <pipe/p_config.h>
+#include <pipe/p_state.h>
+
+#if defined(DEBUG) && (!defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_WINDOWS_USER))
+extern int util_debug_refcnt_state;
+
+void util_debug_reference_slowpath(const struct pipe_reference* p, void* get_desc, const char* op);
+
+static INLINE void util_debug_reference(const struct pipe_reference* p, void* get_desc, const char* op)
+{
+	if(util_debug_refcnt_state >= 0)
+		util_debug_reference_slowpath(p, get_desc, op);
+}
+#else
+static INLINE void util_debug_reference(const struct pipe_reference* p, void* get_desc, const char* op)
+{}
+#endif
+
+#endif /* U_DEBUG_REFCNT_H_ */




More information about the mesa-commit mailing list