diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2018-10-31 05:10:42 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2018-10-31 11:54:27 -0400 |
commit | 242483068b4b9ad02f1653819b6e683577681e0e (patch) | |
tree | 97d9861d0d6134375a0d80ac7cccdbcbe6da4455 | |
parent | 4f8f382e635707ddaddf8269a116e4f8cc8835c0 (diff) |
perf intel-pt: Insert callchain context into synthesized callchains
In the absence of a fallback, callchains must encode also the callchain
context. Do that now there is no fallback.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: stable@vger.kernel.org # 4.19
Link: http://lkml.kernel.org/r/100ea2ec-ed14-b56d-d810-e0a6d2f4b069@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/util/intel-pt.c | 6 | ||||
-rw-r--r-- | tools/perf/util/thread-stack.c | 44 | ||||
-rw-r--r-- | tools/perf/util/thread-stack.h | 2 |
3 files changed, 40 insertions, 12 deletions
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index ffa385a029b3..60732213d16a 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c | |||
@@ -759,7 +759,8 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, | |||
759 | if (pt->synth_opts.callchain) { | 759 | if (pt->synth_opts.callchain) { |
760 | size_t sz = sizeof(struct ip_callchain); | 760 | size_t sz = sizeof(struct ip_callchain); |
761 | 761 | ||
762 | sz += pt->synth_opts.callchain_sz * sizeof(u64); | 762 | /* Add 1 to callchain_sz for callchain context */ |
763 | sz += (pt->synth_opts.callchain_sz + 1) * sizeof(u64); | ||
763 | ptq->chain = zalloc(sz); | 764 | ptq->chain = zalloc(sz); |
764 | if (!ptq->chain) | 765 | if (!ptq->chain) |
765 | goto out_free; | 766 | goto out_free; |
@@ -1160,7 +1161,8 @@ static void intel_pt_prep_sample(struct intel_pt *pt, | |||
1160 | 1161 | ||
1161 | if (pt->synth_opts.callchain) { | 1162 | if (pt->synth_opts.callchain) { |
1162 | thread_stack__sample(ptq->thread, ptq->chain, | 1163 | thread_stack__sample(ptq->thread, ptq->chain, |
1163 | pt->synth_opts.callchain_sz, sample->ip); | 1164 | pt->synth_opts.callchain_sz + 1, |
1165 | sample->ip, pt->kernel_start); | ||
1164 | sample->callchain = ptq->chain; | 1166 | sample->callchain = ptq->chain; |
1165 | } | 1167 | } |
1166 | 1168 | ||
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index c091635bf7dc..61a4286a74dc 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c | |||
@@ -310,20 +310,46 @@ void thread_stack__free(struct thread *thread) | |||
310 | } | 310 | } |
311 | } | 311 | } |
312 | 312 | ||
313 | static inline u64 callchain_context(u64 ip, u64 kernel_start) | ||
314 | { | ||
315 | return ip < kernel_start ? PERF_CONTEXT_USER : PERF_CONTEXT_KERNEL; | ||
316 | } | ||
317 | |||
313 | void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, | 318 | void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, |
314 | size_t sz, u64 ip) | 319 | size_t sz, u64 ip, u64 kernel_start) |
315 | { | 320 | { |
316 | size_t i; | 321 | u64 context = callchain_context(ip, kernel_start); |
322 | u64 last_context; | ||
323 | size_t i, j; | ||
317 | 324 | ||
318 | if (!thread || !thread->ts) | 325 | if (sz < 2) { |
319 | chain->nr = 1; | 326 | chain->nr = 0; |
320 | else | 327 | return; |
321 | chain->nr = min(sz, thread->ts->cnt + 1); | 328 | } |
322 | 329 | ||
323 | chain->ips[0] = ip; | 330 | chain->ips[0] = context; |
331 | chain->ips[1] = ip; | ||
332 | |||
333 | if (!thread || !thread->ts) { | ||
334 | chain->nr = 2; | ||
335 | return; | ||
336 | } | ||
337 | |||
338 | last_context = context; | ||
339 | |||
340 | for (i = 2, j = 1; i < sz && j <= thread->ts->cnt; i++, j++) { | ||
341 | ip = thread->ts->stack[thread->ts->cnt - j].ret_addr; | ||
342 | context = callchain_context(ip, kernel_start); | ||
343 | if (context != last_context) { | ||
344 | if (i >= sz - 1) | ||
345 | break; | ||
346 | chain->ips[i++] = context; | ||
347 | last_context = context; | ||
348 | } | ||
349 | chain->ips[i] = ip; | ||
350 | } | ||
324 | 351 | ||
325 | for (i = 1; i < chain->nr; i++) | 352 | chain->nr = i; |
326 | chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr; | ||
327 | } | 353 | } |
328 | 354 | ||
329 | struct call_return_processor * | 355 | struct call_return_processor * |
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h index b7e41c4ebfdd..f97c00a8c251 100644 --- a/tools/perf/util/thread-stack.h +++ b/tools/perf/util/thread-stack.h | |||
@@ -84,7 +84,7 @@ int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip, | |||
84 | u64 to_ip, u16 insn_len, u64 trace_nr); | 84 | u64 to_ip, u16 insn_len, u64 trace_nr); |
85 | void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr); | 85 | void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr); |
86 | void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, | 86 | void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, |
87 | size_t sz, u64 ip); | 87 | size_t sz, u64 ip, u64 kernel_start); |
88 | int thread_stack__flush(struct thread *thread); | 88 | int thread_stack__flush(struct thread *thread); |
89 | void thread_stack__free(struct thread *thread); | 89 | void thread_stack__free(struct thread *thread); |
90 | size_t thread_stack__depth(struct thread *thread); | 90 | size_t thread_stack__depth(struct thread *thread); |