Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <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>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
66f066d8 0cdccac6

+56 -6
+6
tools/perf/util/thread.c
··· 7 7 #include "util.h" 8 8 #include "debug.h" 9 9 #include "comm.h" 10 + #include "unwind.h" 10 11 11 12 int thread__init_map_groups(struct thread *thread, struct machine *machine) 12 13 { ··· 38 37 thread->cpu = -1; 39 38 INIT_LIST_HEAD(&thread->comm_list); 40 39 40 + if (unwind__prepare_access(thread) < 0) 41 + goto err_thread; 42 + 41 43 comm_str = malloc(32); 42 44 if (!comm_str) 43 45 goto err_thread; ··· 52 48 goto err_thread; 53 49 54 50 list_add(&comm->list, &thread->comm_list); 51 + 55 52 } 56 53 57 54 return thread; ··· 74 69 list_del(&comm->list); 75 70 comm__free(comm); 76 71 } 72 + unwind__finish_access(thread); 77 73 78 74 free(thread); 79 75 }
+33 -6
tools/perf/util/unwind-libunwind.c
··· 24 24 #include <linux/list.h> 25 25 #include <libunwind.h> 26 26 #include <libunwind-ptrace.h> 27 + #include "callchain.h" 27 28 #include "thread.h" 28 29 #include "session.h" 29 30 #include "perf_regs.h" ··· 526 525 .get_proc_name = get_proc_name, 527 526 }; 528 527 528 + int unwind__prepare_access(struct thread *thread) 529 + { 530 + unw_addr_space_t addr_space; 531 + 532 + if (callchain_param.record_mode != CALLCHAIN_DWARF) 533 + return 0; 534 + 535 + addr_space = unw_create_addr_space(&accessors, 0); 536 + if (!addr_space) { 537 + pr_err("unwind: Can't create unwind address space.\n"); 538 + return -ENOMEM; 539 + } 540 + 541 + thread__set_priv(thread, addr_space); 542 + 543 + return 0; 544 + } 545 + 546 + void unwind__finish_access(struct thread *thread) 547 + { 548 + unw_addr_space_t addr_space; 549 + 550 + if (callchain_param.record_mode != CALLCHAIN_DWARF) 551 + return; 552 + 553 + addr_space = thread__priv(thread); 554 + unw_destroy_addr_space(addr_space); 555 + } 556 + 529 557 static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, 530 558 void *arg, int max_stack) 531 559 { ··· 562 532 unw_cursor_t c; 563 533 int ret; 564 534 565 - addr_space = unw_create_addr_space(&accessors, 0); 566 - if (!addr_space) { 567 - pr_err("unwind: Can't create unwind address space.\n"); 568 - return -ENOMEM; 569 - } 535 + addr_space = thread__priv(ui->thread); 536 + if (addr_space == NULL) 537 + return -1; 570 538 571 539 ret = unw_init_remote(&c, addr_space, ui); 572 540 if (ret) ··· 577 549 ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0; 578 550 } 579 551 580 - unw_destroy_addr_space(addr_space); 581 552 return ret; 582 553 } 583 554
+17
tools/perf/util/unwind.h
··· 4 4 #include <linux/types.h> 5 5 #include "event.h" 6 6 #include "symbol.h" 7 + #include "thread.h" 7 8 8 9 struct unwind_entry { 9 10 struct map *map; ··· 22 21 /* libunwind specific */ 23 22 #ifdef HAVE_LIBUNWIND_SUPPORT 24 23 int libunwind__arch_reg_id(int regnum); 24 + int unwind__prepare_access(struct thread *thread); 25 + void unwind__finish_access(struct thread *thread); 26 + #else 27 + static inline int unwind__prepare_access(struct thread *thread __maybe_unused) 28 + { 29 + return 0; 30 + } 31 + 32 + static inline void unwind__finish_access(struct thread *thread __maybe_unused) {} 25 33 #endif 26 34 #else 27 35 static inline int ··· 43 33 { 44 34 return 0; 45 35 } 36 + 37 + static inline int unwind__prepare_access(struct thread *thread __maybe_unused) 38 + { 39 + return 0; 40 + } 41 + 42 + static inline void unwind__finish_access(struct thread *thread __maybe_unused) {} 46 43 #endif /* HAVE_DWARF_UNWIND_SUPPORT */ 47 44 #endif /* __UNWIND_H */