Mesa (nvfx-next-7f): reference debugging code
Luca Barbieri
lb at kemper.freedesktop.org
Tue Aug 17 21:22:34 UTC 2010
Module: Mesa
Branch: nvfx-next-7f
Commit: 2c62ce2789ff3a133b74ff2d96574dfcfe2ed8c1
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=2c62ce2789ff3a133b74ff2d96574dfcfe2ed8c1
Author: Luca Barbieri <luca at luca-barbieri.com>
Date: Mon Aug 9 05:05:41 2010 +0200
reference debugging code
---
src/gallium/auxiliary/Makefile | 2 +
src/gallium/auxiliary/SConscript | 2 +
src/gallium/auxiliary/util/u_debug_describe.c | 43 +++++++
src/gallium/auxiliary/util/u_debug_describe.h | 17 +++
src/gallium/auxiliary/util/u_debug_refcnt.c | 149 +++++++++++++++++++++++++
src/gallium/auxiliary/util/u_debug_refcnt.h | 21 ++++
src/gallium/auxiliary/util/u_debug_symbol.c | 55 +++++++--
src/gallium/auxiliary/util/u_debug_symbol.h | 3 +
src/gallium/auxiliary/util/u_inlines.h | 22 +++-
src/gallium/tools/addr2line.sh | 27 +++++
10 files changed, 323 insertions(+), 18 deletions(-)
diff --git a/src/gallium/auxiliary/Makefile b/src/gallium/auxiliary/Makefile
index 3533526..215ffb3 100644
--- a/src/gallium/auxiliary/Makefile
+++ b/src/gallium/auxiliary/Makefile
@@ -92,6 +92,8 @@ C_SOURCES = \
translate/translate.c \
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 30e5d02..992732f 100644
--- a/src/gallium/auxiliary/SConscript
+++ b/src/gallium/auxiliary/SConscript
@@ -146,7 +146,9 @@ source = [
'util/u_caps.c',
'util/u_cpu_detect.c',
'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_describe.c b/src/gallium/auxiliary/util/u_debug_describe.c
new file mode 100644
index 0000000..ba87e1c
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_debug_describe.c
@@ -0,0 +1,43 @@
+#include <pipe/p_state.h>
+#include <util/u_format.h>
+#include <util/u_debug_describe.h>
+#include <stdio.h>
+
+void
+util_debug_describe_reference(char* buf, const struct pipe_reference*ptr)
+{
+ strcpy(buf, "pipe_object");
+}
+
+void
+util_debug_describe_resource(char* buf, const struct pipe_resource *ptr)
+{
+ if(ptr->target == PIPE_BUFFER)
+ sprintf(buf, "pipe_buffer<%u>", util_format_get_stride(ptr->format, ptr->width0));
+ else if(ptr->target == PIPE_TEXTURE_1D)
+ sprintf(buf, "pipe_texture1d<%u,%s,%u>", ptr->width0, util_format_short_name(ptr->format), ptr->last_level);
+ else if(ptr->target == PIPE_TEXTURE_2D)
+ sprintf(buf, "pipe_texture2d<%u,%u,%s,%u>", ptr->width0, ptr->height0, util_format_short_name(ptr->format), ptr->last_level);
+ else if(ptr->target == PIPE_TEXTURE_CUBE)
+ sprintf(buf, "pipe_texture_cube<%u,%u,%s,%u>", ptr->width0, ptr->height0, util_format_short_name(ptr->format), ptr->last_level);
+ else if(ptr->target == PIPE_TEXTURE_3D)
+ sprintf(buf, "pipe_texture3d<%u,%u,%u,%s,%u>", ptr->width0, ptr->height0, ptr->depth0, util_format_short_name(ptr->format), ptr->last_level);
+ else
+ sprintf(buf, "pipe_martian_resource<%u>", ptr->target);
+}
+
+void
+util_debug_describe_surface(char* buf, const struct pipe_surface *ptr)
+{
+ char res[128];
+ util_debug_describe_resource(res, ptr->texture);
+ sprintf(buf, "pipe_surface<%s,%u,%u,%u>", res, ptr->face, ptr->level, ptr->zslice);
+}
+
+void
+util_debug_describe_sampler_view(char* buf, const struct pipe_sampler_view *ptr)
+{
+ char res[128];
+ util_debug_describe_resource(res, ptr->texture);
+ sprintf(buf, "pipe_sampler_view<%s,%s>", res, util_format_short_name(ptr->format));
+}
diff --git a/src/gallium/auxiliary/util/u_debug_describe.h b/src/gallium/auxiliary/util/u_debug_describe.h
new file mode 100644
index 0000000..4271195
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_debug_describe.h
@@ -0,0 +1,17 @@
+/*
+ * u_debug_describe.h
+ *
+ * Created on: Aug 17, 2010
+ * Author: lb
+ */
+
+#ifndef U_DEBUG_DESCRIBE_H_
+#define U_DEBUG_DESCRIBE_H_
+
+/* a 256-byte buffer must be enough */
+void util_debug_describe_reference(char* buf, const struct pipe_reference*ptr);
+void util_debug_describe_resource(char* buf, const struct pipe_resource *ptr);
+void util_debug_describe_surface(char* buf, const struct pipe_surface *ptr);
+void util_debug_describe_sampler_view(char* buf, const struct pipe_sampler_view *ptr);
+
+#endif /* U_DEBUG_DESCRIBE_H_ */
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..b758002
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_debug_refcnt.c
@@ -0,0 +1,149 @@
+#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 u_debug_symbol_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>
+
+static int state;
+static FILE* fp;
+
+/* TODO: maybe move this serial machinery to a stand-alone module and expose it? */
+pipe_mutex serials_mutex;
+struct util_hash_table* serials_hash;
+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 16
+
+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(const struct pipe_reference* p, void* pget_desc, const char* op)
+{
+ if(state < 0)
+ return;
+
+ if(!state)
+ {
+ const char* filename = debug_get_option("GALLIUM_REFCNT_LOG", NULL);
+ state = -1;
+ if(filename && filename[0])
+ fp = fopen(filename, "w");
+
+ if(fp)
+ state = 1;
+ }
+
+ if(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..878bacf
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_debug_refcnt.h
@@ -0,0 +1,21 @@
+/*
+ * 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))
+void util_debug_reference(const struct pipe_reference* p, void* get_desc, const char* 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_ */
diff --git a/src/gallium/auxiliary/util/u_debug_symbol.c b/src/gallium/auxiliary/util/u_debug_symbol.c
index 6e25057..174d7c5 100644
--- a/src/gallium/auxiliary/util/u_debug_symbol.c
+++ b/src/gallium/auxiliary/util/u_debug_symbol.c
@@ -33,6 +33,7 @@
*/
#include "pipe/p_compiler.h"
+#include <stdio.h>
#include "u_debug.h"
#include "u_debug_symbol.h"
@@ -113,8 +114,8 @@ BOOL WINAPI j_SymGetSymFromAddr(HANDLE hProcess, DWORD Address, PDWORD Displacem
}
-static INLINE boolean
-debug_symbol_print_imagehlp(const void *addr)
+static INLINE void
+debug_symbol_name_imagehlp(const void *addr, char* buf, unsigned size)
{
HANDLE hProcess;
BYTE symbolBuffer[1024];
@@ -133,23 +134,55 @@ debug_symbol_print_imagehlp(const void *addr)
}
if(!j_SymGetSymFromAddr(hProcess, (DWORD)addr, &dwDisplacement, pSymbol))
- return FALSE;
+ buf[0] = 0;
+ else
+ {
+ strncpy(buf, pSymbol->Name, size);
+ buf[size - 1] = 0;
+ }
+}
+#endif
- debug_printf("\t%s\n", pSymbol->Name);
+#ifdef __GLIBC__
+#include <execinfo.h>
- return TRUE;
-
+/* This can only provide dynamic symbols, or binary offsets into a file.
+ *
+ * To fix this, post-process the output with tools/addr2line.sh
+ */
+static INLINE void
+debug_symbol_name_glibc(const void *addr, char* buf, unsigned size)
+{
+ char** syms = backtrace_symbols((void**)&addr, 1);
+ strncpy(buf, syms[0], size);
+ buf[size - 1] = 0;
+ free(syms);
}
#endif
-
void
-debug_symbol_print(const void *addr)
+debug_symbol_name(const void *addr, char* buf, unsigned size)
{
#if defined(PIPE_SUBSYSTEM_WINDOWS_USER) && defined(PIPE_ARCH_X86)
- if(debug_symbol_print_imagehlp(addr))
+ debug_symbol_name_imagehlp(addr, buf, size);
+ if(buf[0])
return;
#endif
-
- debug_printf("\t%p\n", addr);
+
+#ifdef __GLIBC__
+ debug_symbol_name_glibc(addr, buf, size);
+ if(buf[0])
+ return;
+#endif
+
+ snprintf(buf, size, "%p", addr);
+ buf[size - 1] = 0;
+}
+
+void
+debug_symbol_print(const void *addr)
+{
+ char buf[1024];
+ debug_symbol_name(addr, buf, sizeof(buf));
+ debug_printf("\t%s\n", buf);
}
diff --git a/src/gallium/auxiliary/util/u_debug_symbol.h b/src/gallium/auxiliary/util/u_debug_symbol.h
index 0215869..5e283e5 100644
--- a/src/gallium/auxiliary/util/u_debug_symbol.h
+++ b/src/gallium/auxiliary/util/u_debug_symbol.h
@@ -43,6 +43,9 @@ extern "C" {
void
+debug_symbol_name(const void *addr, char* buf, unsigned size);
+
+void
debug_symbol_print(const void *addr);
diff --git a/src/gallium/auxiliary/util/u_inlines.h b/src/gallium/auxiliary/util/u_inlines.h
index 540305c..e216791 100644
--- a/src/gallium/auxiliary/util/u_inlines.h
+++ b/src/gallium/auxiliary/util/u_inlines.h
@@ -33,6 +33,8 @@
#include "pipe/p_state.h"
#include "pipe/p_screen.h"
#include "util/u_debug.h"
+#include "util/u_debug_describe.h"
+#include "util/u_debug_refcnt.h"
#include "util/u_atomic.h"
#include "util/u_box.h"
#include "util/u_math.h"
@@ -67,15 +69,17 @@ pipe_is_referenced(struct pipe_reference *reference)
* \return TRUE if the object's refcount hits zero and should be destroyed.
*/
static INLINE boolean
-pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference)
+pipe_reference_described(struct pipe_reference *ptr, struct pipe_reference *reference, void* get_desc)
{
boolean destroy = FALSE;
if(ptr != reference) {
- /* bump the reference.count first */
+
+ /* bump the reference.count first */
if (reference) {
assert(pipe_is_referenced(reference));
p_atomic_inc(&reference->count);
+ util_debug_reference(reference, get_desc, "AddRef");
}
if (ptr) {
@@ -83,41 +87,45 @@ pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference)
if (p_atomic_dec_zero(&ptr->count)) {
destroy = TRUE;
}
+ util_debug_reference(ptr, get_desc, "Release");
}
}
return destroy;
}
+static INLINE boolean
+pipe_reference(struct pipe_reference *ptr, struct pipe_reference *reference)
+{
+ return pipe_reference_described(ptr, reference, util_debug_describe_reference);
+}
static INLINE void
pipe_surface_reference(struct pipe_surface **ptr, struct pipe_surface *surf)
{
struct pipe_surface *old_surf = *ptr;
- if (pipe_reference(&(*ptr)->reference, &surf->reference))
+ if (pipe_reference_described(&(*ptr)->reference, &surf->reference, util_debug_describe_surface))
old_surf->texture->screen->tex_surface_destroy(old_surf);
*ptr = surf;
}
-
static INLINE void
pipe_resource_reference(struct pipe_resource **ptr, struct pipe_resource *tex)
{
struct pipe_resource *old_tex = *ptr;
- if (pipe_reference(&(*ptr)->reference, &tex->reference))
+ if (pipe_reference_described(&(*ptr)->reference, &tex->reference, util_debug_describe_resource))
old_tex->screen->resource_destroy(old_tex->screen, old_tex);
*ptr = tex;
}
-
static INLINE void
pipe_sampler_view_reference(struct pipe_sampler_view **ptr, struct pipe_sampler_view *view)
{
struct pipe_sampler_view *old_view = *ptr;
- if (pipe_reference(&(*ptr)->reference, &view->reference))
+ if (pipe_reference_described(&(*ptr)->reference, &view->reference, util_debug_describe_sampler_view))
old_view->context->sampler_view_destroy(old_view->context, old_view);
*ptr = view;
}
diff --git a/src/gallium/tools/addr2line.sh b/src/gallium/tools/addr2line.sh
new file mode 100755
index 0000000..5573803
--- /dev/null
+++ b/src/gallium/tools/addr2line.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# This script processes symbols output by Gallium using glibc to human-readable function names
+
+lastbin=
+i=-1
+dir="$(mktemp -d)"
+input="$1"
+
+# Gather all unique addresses for each binary
+sed -nre 's|([^ ]*/[^ ]*)\(\+0x([^)]*).*|\1 \2|p' "$input"|sort|uniq|while read bin addr; do
+ if test "$lastbin" != "$bin"; then
+ ((++i))
+ lastbin="$bin"
+ echo "$bin" > "$dir/$i.addrs.bin"
+ fi
+ echo "$addr" >> "$dir/$i.addrs"
+done
+
+# Construct a sed script to convert hex address to human readable form, and apply it
+for i in "$dir"/*.addrs; do
+ bin="$(<"$i.bin")"
+ addr2line -p -e "$bin" -a -f < "$i"|sed -nre 's@^0x0*([^:]*): ([^?]*)$@s|'"$bin"'(+0x\1)|\2|g at gp'
+ rm -f "$i" "$i.bin"
+done|sed -f - "$input"
+
+rmdir "$dir"
+
More information about the mesa-commit
mailing list