Mesa (master): gallium/util: cache symbol lookup with libunwind

Rob Clark robclark at kemper.freedesktop.org
Fri Apr 7 12:23:22 UTC 2017


Module: Mesa
Branch: master
Commit: 91dfa021254d5ea1c607f4f514414c2130fac208
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=91dfa021254d5ea1c607f4f514414c2130fac208

Author: Rob Clark <robdclark at gmail.com>
Date:   Tue Apr  4 09:52:57 2017 -0400

gallium/util: cache symbol lookup with libunwind

Signed-off-by: Rob Clark <robdclark at gmail.com>

---

 src/gallium/auxiliary/util/u_debug_stack.c | 117 ++++++++++++++++++++++-------
 src/gallium/auxiliary/util/u_debug_stack.h |   4 +-
 2 files changed, 94 insertions(+), 27 deletions(-)

diff --git a/src/gallium/auxiliary/util/u_debug_stack.c b/src/gallium/auxiliary/util/u_debug_stack.c
index 14d5b16c37..a5829316e4 100644
--- a/src/gallium/auxiliary/util/u_debug_stack.c
+++ b/src/gallium/auxiliary/util/u_debug_stack.c
@@ -43,6 +43,62 @@
 #endif
 #include <dlfcn.h>
 
+#include "os/os_thread.h"
+#include "u_hash_table.h"
+
+struct util_hash_table* symbols_hash;
+static mtx_t symbols_mutex = _MTX_INITIALIZER_NP;
+
+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;
+}
+
+/* TODO with some refactoring we might be able to re-use debug_symbol_name_cached()
+ * instead.. otoh if using libunwind I think u_debug_symbol could just be excluded
+ * from build?
+ */
+static const char *
+symbol_name_cached(unw_cursor_t *cursor, unw_proc_info_t *pip)
+{
+   void *addr = (void *)(uintptr_t)pip->start_ip;
+   char *name;
+
+   mtx_lock(&symbols_mutex);
+   if(!symbols_hash)
+      symbols_hash = util_hash_table_create(hash_ptr, compare_ptr);
+   name = util_hash_table_get(symbols_hash, addr);
+   if(!name)
+   {
+      char procname[256];
+      unw_word_t off;
+      int ret;
+
+      ret = unw_get_proc_name(cursor, procname, sizeof(procname), &off);
+      if (ret && ret != -UNW_ENOMEM) {
+         procname[0] = '?';
+         procname[1] = 0;
+      }
+
+      asprintf(&name, "%s%s", procname, ret == -UNW_ENOMEM ? "..." : "");
+
+      util_hash_table_set(symbols_hash, addr, (void*)name);
+   }
+   mtx_unlock(&symbols_mutex);
+
+   return name;
+}
+
 void
 debug_backtrace_capture(struct debug_stack_frame *backtrace,
                         unsigned start_frame,
@@ -52,7 +108,6 @@ debug_backtrace_capture(struct debug_stack_frame *backtrace,
    unw_context_t context;
    unw_proc_info_t pip;
    unsigned i = 0;
-   int ret;
 
    pip.unwind_info = NULL;
 
@@ -63,39 +118,43 @@ debug_backtrace_capture(struct debug_stack_frame *backtrace,
       start_frame--;
 
    while ((i < nr_frames) && (unw_step(&cursor) > 0)) {
-      char procname[256];
-      const char *filename;
-      unw_word_t off;
-      Dl_info dlinfo;
+      unw_word_t ip;
 
+      unw_get_reg(&cursor, UNW_REG_IP, &ip);
       unw_get_proc_info(&cursor, &pip);
 
-      ret = unw_get_proc_name(&cursor, procname, 256, &off);
-      if (ret && ret != -UNW_ENOMEM) {
-         procname[0] = '?';
-         procname[1] = 0;
-      }
-
-       if (dladdr((void *)(uintptr_t)(pip.start_ip + off), &dlinfo) && dlinfo.dli_fname &&
-               *dlinfo.dli_fname)
-           filename = dlinfo.dli_fname;
-       else
-           filename = "?";
-
-      snprintf(backtrace[i].buf, sizeof(backtrace[i].buf),
-            "%u: %s (%s%s+0x%x) [%p]", i, filename, procname,
-            ret == -UNW_ENOMEM ? "..." : "", (int)off,
-            (void *)(uintptr_t)(pip.start_ip + off));
+      backtrace[i].start_ip = pip.start_ip;
+      backtrace[i].off      = ip - pip.start_ip;
+      backtrace[i].procname = symbol_name_cached(&cursor, &pip);
 
       i++;
    }
 
    while (i < nr_frames) {
-      backtrace[i].buf[0] = '\0';
+      backtrace[i].start_ip = 0;
       i++;
    }
 }
 
+static const void *
+frame_ip(const struct debug_stack_frame *frame)
+{
+   return (void *)(uintptr_t)(frame->start_ip + frame->off);
+}
+
+static const char *
+frame_filename(const struct debug_stack_frame *frame)
+{
+   Dl_info dlinfo;
+
+
+   if (dladdr(frame_ip(frame), &dlinfo) && dlinfo.dli_fname &&
+           *dlinfo.dli_fname)
+       return dlinfo.dli_fname;
+
+   return "?";
+}
+
 void
 debug_backtrace_dump(const struct debug_stack_frame *backtrace,
                      unsigned nr_frames)
@@ -103,9 +162,12 @@ debug_backtrace_dump(const struct debug_stack_frame *backtrace,
    unsigned i;
 
    for (i = 0; i < nr_frames; ++i) {
-      if (backtrace[i].buf[0] == '\0')
+      if (!backtrace[i].start_ip)
          break;
-      debug_printf("\t%s\n", backtrace[i].buf);
+      debug_printf("\t%u: %s (%s+0x%x) [%p]\n", i,
+            frame_filename(&backtrace[i]),
+            backtrace[i].procname, backtrace[i].off,
+            frame_ip(&backtrace[i]));
    }
 }
 
@@ -117,9 +179,12 @@ debug_backtrace_print(FILE *f,
    unsigned i;
 
    for (i = 0; i < nr_frames; ++i) {
-      if (backtrace[i].buf[0] == '\0')
+      if (!backtrace[i].start_ip)
          break;
-      fprintf(f, "\t%s\n", backtrace[i].buf);
+      fprintf(f, "\t%u: %s (%s+0x%x) [%p]\n", i,
+            frame_filename(&backtrace[i]),
+            backtrace[i].procname, backtrace[i].off,
+            frame_ip(&backtrace[i]));
    }
 }
 
diff --git a/src/gallium/auxiliary/util/u_debug_stack.h b/src/gallium/auxiliary/util/u_debug_stack.h
index 0effcbe525..fff41a5a9e 100644
--- a/src/gallium/auxiliary/util/u_debug_stack.h
+++ b/src/gallium/auxiliary/util/u_debug_stack.h
@@ -60,7 +60,9 @@ extern "C" {
 struct debug_stack_frame 
 {
 #ifdef HAVE_LIBUNWIND
-   char buf[128];
+   unw_word_t start_ip;
+   unsigned int off;
+   const char *procname;
 #else
    const void *function;
 #endif




More information about the mesa-commit mailing list