aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2018-09-20 09:00:45 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2018-09-20 14:16:17 -0400
commit4d60e5e36aa6f11b4d9eadc5d2b94128f24870c7 (patch)
treecdd74e3a541925cdfb47f0e440d84c1fe2d45760
parentff645daf30cafb6fa74bee9a73733700bac2aff7 (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.c35
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 */
40struct thread_stack_entry { 41struct 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
115static int thread_stack__push(struct thread_stack *ts, u64 ret_addr) 117static 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
157static 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
153static bool thread_stack__in_kernel(struct thread_stack *ts) 169static 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