aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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