perf callchain: Create an address space per thread
authorNamhyung Kim <namhyung@kernel.org>
Mon, 6 Oct 2014 00:46:00 +0000 (09:46 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 15 Oct 2014 20:38:23 +0000 (17:38 -0300)
The unw_addr_space_t in libunwind represents an address space to be used
for stack unwinding.  It doesn't need to be create/destory everytime to
unwind callchain (as in get_entries) and can have a same lifetime as
thread (unless exec called).

So move the address space construction/destruction logic to the thread
lifetime handling functions.  This is a preparation to enable caching in
the unwind library.

Note that it saves unw_addr_space_t object using thread__set_priv().  It
seems currently only used by perf trace and perf kvm stat commands which
don't use callchain.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Jean Pihet <jean.pihet@linaro.org>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Arun Sharma <asharma@fb.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jean Pihet <jean.pihet@linaro.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1412556363-26229-3-git-send-email-namhyung@kernel.org
[ Fixup unwind-libunwind.c missing CALLCHAIN_DWARF definition, added
  missing __maybe_unused on unused parameters in stubs at util/unwind.h ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/thread.c
tools/perf/util/unwind-libunwind.c
tools/perf/util/unwind.h

index a9df7f2c6dc934210e83755155e843b72af68011..2b7b2d91c016b211f48a9823f9837033615b1136 100644 (file)
@@ -7,6 +7,7 @@
 #include "util.h"
 #include "debug.h"
 #include "comm.h"
+#include "unwind.h"
 
 int thread__init_map_groups(struct thread *thread, struct machine *machine)
 {
@@ -37,6 +38,9 @@ struct thread *thread__new(pid_t pid, pid_t tid)
                thread->cpu = -1;
                INIT_LIST_HEAD(&thread->comm_list);
 
+               if (unwind__prepare_access(thread) < 0)
+                       goto err_thread;
+
                comm_str = malloc(32);
                if (!comm_str)
                        goto err_thread;
@@ -48,6 +52,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
                        goto err_thread;
 
                list_add(&comm->list, &thread->comm_list);
+
        }
 
        return thread;
@@ -69,6 +74,7 @@ void thread__delete(struct thread *thread)
                list_del(&comm->list);
                comm__free(comm);
        }
+       unwind__finish_access(thread);
 
        free(thread);
 }
index 92b56db5247193fb4c74f6d88cd5d49a542087ad..e060386165c5fad82372123e99252f577eb7eac4 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <libunwind.h>
 #include <libunwind-ptrace.h>
+#include "callchain.h"
 #include "thread.h"
 #include "session.h"
 #include "perf_regs.h"
@@ -525,12 +526,12 @@ static unw_accessors_t accessors = {
        .get_proc_name          = get_proc_name,
 };
 
-static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
-                      void *arg, int max_stack)
+int unwind__prepare_access(struct thread *thread)
 {
        unw_addr_space_t addr_space;
-       unw_cursor_t c;
-       int ret;
+
+       if (callchain_param.record_mode != CALLCHAIN_DWARF)
+               return 0;
 
        addr_space = unw_create_addr_space(&accessors, 0);
        if (!addr_space) {
@@ -538,6 +539,33 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
                return -ENOMEM;
        }
 
+       thread__set_priv(thread, addr_space);
+
+       return 0;
+}
+
+void unwind__finish_access(struct thread *thread)
+{
+       unw_addr_space_t addr_space;
+
+       if (callchain_param.record_mode != CALLCHAIN_DWARF)
+               return;
+
+       addr_space = thread__priv(thread);
+       unw_destroy_addr_space(addr_space);
+}
+
+static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
+                      void *arg, int max_stack)
+{
+       unw_addr_space_t addr_space;
+       unw_cursor_t c;
+       int ret;
+
+       addr_space = thread__priv(ui->thread);
+       if (addr_space == NULL)
+               return -1;
+
        ret = unw_init_remote(&c, addr_space, ui);
        if (ret)
                display_error(ret);
@@ -549,7 +577,6 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
                ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0;
        }
 
-       unw_destroy_addr_space(addr_space);
        return ret;
 }
 
index f03061260b4e5459970978cc051461c64180dfb0..c17c4855bdbc3e4bcf8423246c92b8f7bc750494 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/types.h>
 #include "event.h"
 #include "symbol.h"
+#include "thread.h"
 
 struct unwind_entry {
        struct map      *map;
@@ -21,6 +22,15 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
 /* libunwind specific */
 #ifdef HAVE_LIBUNWIND_SUPPORT
 int libunwind__arch_reg_id(int regnum);
+int unwind__prepare_access(struct thread *thread);
+void unwind__finish_access(struct thread *thread);
+#else
+static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
+{
+       return 0;
+}
+
+static inline void unwind__finish_access(struct thread *thread __maybe_unused) {}
 #endif
 #else
 static inline int
@@ -33,5 +43,12 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
 {
        return 0;
 }
+
+static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
+{
+       return 0;
+}
+
+static inline void unwind__finish_access(struct thread *thread __maybe_unused) {}
 #endif /* HAVE_DWARF_UNWIND_SUPPORT */
 #endif /* __UNWIND_H */