diff options
| author | He Kuang <hekuang@huawei.com> | 2016-06-02 23:33:12 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-06-07 11:08:52 -0400 |
| commit | f83c04156c1483f16ac548516f41212cf244e441 (patch) | |
| tree | 4880d7dac992ee50993b68758e13ff373b81495e | |
| parent | c1d1d0d9b302cb5f0365f4de78dd7fcbf7983c05 (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.h | 4 | ||||
| -rw-r--r-- | tools/perf/util/unwind-libunwind.c | 53 | ||||
| -rw-r--r-- | tools/perf/util/unwind.h | 9 |
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 | ||
| 13 | struct thread_stack; | 13 | struct thread_stack; |
| 14 | struct unwind_libunwind_ops; | ||
| 14 | 15 | ||
| 15 | struct thread { | 16 | struct 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 | ||
| 582 | int unwind__prepare_access(struct thread *thread) | 582 | static 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 | ||
| 597 | void unwind__flush_access(struct thread *thread) | 597 | static 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 | ||
| 605 | void unwind__finish_access(struct thread *thread) | 605 | static 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 | ||
| 665 | int unwind__get_entries(unwind_entry_cb_t cb, void *arg, | 665 | static 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 | |||
| 684 | static 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 | |||
| 692 | struct unwind_libunwind_ops * | ||
| 693 | local_unwind_libunwind_ops = &_unwind_libunwind_ops; | ||
| 694 | |||
| 695 | static void unwind__register_ops(struct thread *thread, | ||
| 696 | struct unwind_libunwind_ops *ops) | ||
| 697 | { | ||
| 698 | thread->unwind_libunwind_ops = ops; | ||
| 699 | } | ||
| 700 | |||
| 701 | int 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 | |||
| 708 | void unwind__flush_access(struct thread *thread) | ||
| 709 | { | ||
| 710 | if (thread->unwind_libunwind_ops) | ||
| 711 | thread->unwind_libunwind_ops->flush_access(thread); | ||
| 712 | } | ||
| 713 | |||
| 714 | void unwind__finish_access(struct thread *thread) | ||
| 715 | { | ||
| 716 | if (thread->unwind_libunwind_ops) | ||
| 717 | thread->unwind_libunwind_ops->finish_access(thread); | ||
| 718 | } | ||
| 719 | |||
| 720 | int 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 | ||
| 15 | typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); | 15 | typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); |
| 16 | 16 | ||
| 17 | struct 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 |
| 18 | int unwind__get_entries(unwind_entry_cb_t cb, void *arg, | 27 | int unwind__get_entries(unwind_entry_cb_t cb, void *arg, |
| 19 | struct thread *thread, | 28 | struct thread *thread, |
