From 66f066d8994bd146304bab72fa09c1e644c4b3ff Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 6 Oct 2014 09:46:00 +0900 Subject: [PATCH] perf callchain: Create an address space per thread 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 Acked-by: Jean Pihet Acked-by: Jiri Olsa Cc: Arun Sharma Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra 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 --- tools/perf/util/thread.c | 6 +++++ tools/perf/util/unwind-libunwind.c | 39 +++++++++++++++++++++++++----- tools/perf/util/unwind.h | 17 +++++++++++++ 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index a9df7f2c6dc9..2b7b2d91c016 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -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); } diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 92b56db52471..e060386165c5 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -24,6 +24,7 @@ #include #include #include +#include "callchain.h" #include "thread.h" #include "session.h" #include "perf_regs.h" @@ -525,6 +526,35 @@ static unw_accessors_t accessors = { .get_proc_name = get_proc_name, }; +int unwind__prepare_access(struct thread *thread) +{ + unw_addr_space_t addr_space; + + if (callchain_param.record_mode != CALLCHAIN_DWARF) + return 0; + + addr_space = unw_create_addr_space(&accessors, 0); + if (!addr_space) { + pr_err("unwind: Can't create unwind address space.\n"); + 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) { @@ -532,11 +562,9 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, unw_cursor_t c; int ret; - addr_space = unw_create_addr_space(&accessors, 0); - if (!addr_space) { - pr_err("unwind: Can't create unwind address space.\n"); - return -ENOMEM; - } + addr_space = thread__priv(ui->thread); + if (addr_space == NULL) + return -1; ret = unw_init_remote(&c, addr_space, ui); if (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; } diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index f03061260b4e..c17c4855bdbc 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -4,6 +4,7 @@ #include #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 */