diff options
| author | Adrian Hunter <adrian.hunter@intel.com> | 2018-09-20 09:00:45 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2018-09-20 14:16:17 -0400 |
| commit | 4d60e5e36aa6f11b4d9eadc5d2b94128f24870c7 (patch) | |
| tree | cdd74e3a541925cdfb47f0e440d84c1fe2d45760 | |
| parent | ff645daf30cafb6fa74bee9a73733700bac2aff7 (diff) | |
perf tools: Improve thread_stack__event() for trace begin / end
thread_stack__event() is used to create call stacks, by keeping track of
calls and returns. Improve the handling of trace begin / end to allow
for a trace that ends in a call.
Previously, the Intel PT decoder would indicate begin / end by a branch
from / to zero. That hides useful information, in particular when a
trace ends with a call. Before remedying that, enhance the thread stack
so that it does not expect to see the 'return' for a 'call' that ends
the trace.
Committer notes:
Added this:
return thread_stack__push(thread->ts, ret_addr,
- flags && PERF_IP_FLAG_TRACE_END);
+ flags & PERF_IP_FLAG_TRACE_END);
To fix problem spotted by:
debian:9: clang version 3.8.1-24 (tags/RELEASE_381/final)
debian:experimental: clang version 6.0.1-6 (tags/RELEASE_601/final)
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/20180920130048.31432-4-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
| -rw-r--r-- | tools/perf/util/thread-stack.c | 35 |
1 files changed, 30 insertions, 5 deletions
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index dd17d6a38d3a..e3f7dfecafa9 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | * @branch_count: the branch count when the entry was created | 36 | * @branch_count: the branch count when the entry was created |
| 37 | * @cp: call path | 37 | * @cp: call path |
| 38 | * @no_call: a 'call' was not seen | 38 | * @no_call: a 'call' was not seen |
| 39 | * @trace_end: a 'call' but trace ended | ||
| 39 | */ | 40 | */ |
| 40 | struct thread_stack_entry { | 41 | struct thread_stack_entry { |
| 41 | u64 ret_addr; | 42 | u64 ret_addr; |
| @@ -44,6 +45,7 @@ struct thread_stack_entry { | |||
| 44 | u64 branch_count; | 45 | u64 branch_count; |
| 45 | struct call_path *cp; | 46 | struct call_path *cp; |
| 46 | bool no_call; | 47 | bool no_call; |
| 48 | bool trace_end; | ||
| 47 | }; | 49 | }; |
| 48 | 50 | ||
| 49 | /** | 51 | /** |
| @@ -112,7 +114,8 @@ static struct thread_stack *thread_stack__new(struct thread *thread, | |||
| 112 | return ts; | 114 | return ts; |
| 113 | } | 115 | } |
| 114 | 116 | ||
| 115 | static int thread_stack__push(struct thread_stack *ts, u64 ret_addr) | 117 | static int thread_stack__push(struct thread_stack *ts, u64 ret_addr, |
| 118 | bool trace_end) | ||
| 116 | { | 119 | { |
| 117 | int err = 0; | 120 | int err = 0; |
| 118 | 121 | ||
| @@ -124,6 +127,7 @@ static int thread_stack__push(struct thread_stack *ts, u64 ret_addr) | |||
| 124 | } | 127 | } |
| 125 | } | 128 | } |
| 126 | 129 | ||
| 130 | ts->stack[ts->cnt].trace_end = trace_end; | ||
| 127 | ts->stack[ts->cnt++].ret_addr = ret_addr; | 131 | ts->stack[ts->cnt++].ret_addr = ret_addr; |
| 128 | 132 | ||
| 129 | return err; | 133 | return err; |
| @@ -150,6 +154,18 @@ static void thread_stack__pop(struct thread_stack *ts, u64 ret_addr) | |||
| 150 | } | 154 | } |
| 151 | } | 155 | } |
| 152 | 156 | ||
| 157 | static void thread_stack__pop_trace_end(struct thread_stack *ts) | ||
| 158 | { | ||
| 159 | size_t i; | ||
| 160 | |||
| 161 | for (i = ts->cnt; i; ) { | ||
| 162 | if (ts->stack[--i].trace_end) | ||
| 163 | ts->cnt = i; | ||
| 164 | else | ||
| 165 | return; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 153 | static bool thread_stack__in_kernel(struct thread_stack *ts) | 169 | static bool thread_stack__in_kernel(struct thread_stack *ts) |
| 154 | { | 170 | { |
| 155 | if (!ts->cnt) | 171 | if (!ts->cnt) |
| @@ -254,10 +270,19 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip, | |||
| 254 | ret_addr = from_ip + insn_len; | 270 | ret_addr = from_ip + insn_len; |
| 255 | if (ret_addr == to_ip) | 271 | if (ret_addr == to_ip) |
| 256 | return 0; /* Zero-length calls are excluded */ | 272 | return 0; /* Zero-length calls are excluded */ |
| 257 | return thread_stack__push(thread->ts, ret_addr); | 273 | return thread_stack__push(thread->ts, ret_addr, |
| 258 | } else if (flags & PERF_IP_FLAG_RETURN) { | 274 | flags & PERF_IP_FLAG_TRACE_END); |
| 259 | if (!from_ip) | 275 | } else if (flags & PERF_IP_FLAG_TRACE_BEGIN) { |
| 260 | return 0; | 276 | /* |
| 277 | * If the caller did not change the trace number (which would | ||
| 278 | * have flushed the stack) then try to make sense of the stack. | ||
| 279 | * Possibly, tracing began after returning to the current | ||
| 280 | * address, so try to pop that. Also, do not expect a call made | ||
| 281 | * when the trace ended, to return, so pop that. | ||
| 282 | */ | ||
| 283 | thread_stack__pop(thread->ts, to_ip); | ||
| 284 | thread_stack__pop_trace_end(thread->ts); | ||
| 285 | } else if ((flags & PERF_IP_FLAG_RETURN) && from_ip) { | ||
| 261 | thread_stack__pop(thread->ts, to_ip); | 286 | thread_stack__pop(thread->ts, to_ip); |
| 262 | } | 287 | } |
| 263 | 288 | ||
