aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHe Kuang <hekuang@huawei.com>2016-06-02 23:33:12 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-06-07 11:08:52 -0400
commitf83c04156c1483f16ac548516f41212cf244e441 (patch)
tree4880d7dac992ee50993b68758e13ff373b81495e
parentc1d1d0d9b302cb5f0365f4de78dd7fcbf7983c05 (diff)
perf unwind: Introduce 'struct unwind_libunwind_ops' for local unwind
Currently, libunwind operations are fixed, and they are chosen according to the host architecture. This will lead to a problem that if a thread is run as x86_32 on a x86_64 machine, perf will use libunwind methods for x86_64 to parse the callchain and get wrong results. This patch changes the fixed methods of libunwind operations to be thread/map related, and each thread can have individual libunwind operations. Local libunwind methods are registered as default value. Signed-off-by: He Kuang <hekuang@huawei.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Ekaterina Tumanova <tumanova@linux.vnet.ibm.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Kan Liang <kan.liang@intel.com> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Pekka Enberg <penberg@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> Cc: Wang Nan <wangnan0@huawei.com> Link: http://lkml.kernel.org/r/1464924803-22214-4-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/util/thread.h4
-rw-r--r--tools/perf/util/unwind-libunwind.c53
-rw-r--r--tools/perf/util/unwind.h9
3 files changed, 61 insertions, 5 deletions
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 4c9f0aa11f1f..07ffb18221ab 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -11,6 +11,7 @@
11#include <intlist.h> 11#include <intlist.h>
12 12
13struct thread_stack; 13struct thread_stack;
14struct unwind_libunwind_ops;
14 15
15struct thread { 16struct thread {
16 union { 17 union {
@@ -33,7 +34,8 @@ struct thread {
33 void *priv; 34 void *priv;
34 struct thread_stack *ts; 35 struct thread_stack *ts;
35#ifdef HAVE_LIBUNWIND_SUPPORT 36#ifdef HAVE_LIBUNWIND_SUPPORT
36 void *addr_space; 37 void *addr_space;
38 struct unwind_libunwind_ops *unwind_libunwind_ops;
37#endif 39#endif
38}; 40};
39 41
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 63687d3a344e..b0c5db1333f9 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -579,7 +579,7 @@ static unw_accessors_t accessors = {
579 .get_proc_name = get_proc_name, 579 .get_proc_name = get_proc_name,
580}; 580};
581 581
582int unwind__prepare_access(struct thread *thread) 582static int _unwind__prepare_access(struct thread *thread)
583{ 583{
584 if (callchain_param.record_mode != CALLCHAIN_DWARF) 584 if (callchain_param.record_mode != CALLCHAIN_DWARF)
585 return 0; 585 return 0;
@@ -594,7 +594,7 @@ int unwind__prepare_access(struct thread *thread)
594 return 0; 594 return 0;
595} 595}
596 596
597void unwind__flush_access(struct thread *thread) 597static void _unwind__flush_access(struct thread *thread)
598{ 598{
599 if (callchain_param.record_mode != CALLCHAIN_DWARF) 599 if (callchain_param.record_mode != CALLCHAIN_DWARF)
600 return; 600 return;
@@ -602,7 +602,7 @@ void unwind__flush_access(struct thread *thread)
602 unw_flush_cache(thread->addr_space, 0, 0); 602 unw_flush_cache(thread->addr_space, 0, 0);
603} 603}
604 604
605void unwind__finish_access(struct thread *thread) 605static void _unwind__finish_access(struct thread *thread)
606{ 606{
607 if (callchain_param.record_mode != CALLCHAIN_DWARF) 607 if (callchain_param.record_mode != CALLCHAIN_DWARF)
608 return; 608 return;
@@ -662,7 +662,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
662 return ret; 662 return ret;
663} 663}
664 664
665int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 665static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg,
666 struct thread *thread, 666 struct thread *thread,
667 struct perf_sample *data, int max_stack) 667 struct perf_sample *data, int max_stack)
668{ 668{
@@ -680,3 +680,48 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
680 680
681 return get_entries(&ui, cb, arg, max_stack); 681 return get_entries(&ui, cb, arg, max_stack);
682} 682}
683
684static struct unwind_libunwind_ops
685_unwind_libunwind_ops = {
686 .prepare_access = _unwind__prepare_access,
687 .flush_access = _unwind__flush_access,
688 .finish_access = _unwind__finish_access,
689 .get_entries = _unwind__get_entries,
690};
691
692struct unwind_libunwind_ops *
693local_unwind_libunwind_ops = &_unwind_libunwind_ops;
694
695static void unwind__register_ops(struct thread *thread,
696 struct unwind_libunwind_ops *ops)
697{
698 thread->unwind_libunwind_ops = ops;
699}
700
701int unwind__prepare_access(struct thread *thread)
702{
703 unwind__register_ops(thread, local_unwind_libunwind_ops);
704
705 return thread->unwind_libunwind_ops->prepare_access(thread);
706}
707
708void unwind__flush_access(struct thread *thread)
709{
710 if (thread->unwind_libunwind_ops)
711 thread->unwind_libunwind_ops->flush_access(thread);
712}
713
714void unwind__finish_access(struct thread *thread)
715{
716 if (thread->unwind_libunwind_ops)
717 thread->unwind_libunwind_ops->finish_access(thread);
718}
719
720int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
721 struct thread *thread,
722 struct perf_sample *data, int max_stack)
723{
724 if (thread->unwind_libunwind_ops)
725 return thread->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack);
726 return 0;
727}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 12790cf94618..bbd73d9bea45 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -14,6 +14,15 @@ struct unwind_entry {
14 14
15typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); 15typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
16 16
17struct unwind_libunwind_ops {
18 int (*prepare_access)(struct thread *thread);
19 void (*flush_access)(struct thread *thread);
20 void (*finish_access)(struct thread *thread);
21 int (*get_entries)(unwind_entry_cb_t cb, void *arg,
22 struct thread *thread,
23 struct perf_sample *data, int max_stack);
24};
25
17#ifdef HAVE_DWARF_UNWIND_SUPPORT 26#ifdef HAVE_DWARF_UNWIND_SUPPORT
18int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 27int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
19 struct thread *thread, 28 struct thread *thread,