From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754772AbcEWMJV (ORCPT ); Mon, 23 May 2016 08:09:21 -0400 Received: from mga03.intel.com ([134.134.136.65]:4828 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753039AbcEWMJU (ORCPT ); Mon, 23 May 2016 08:09:20 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.26,355,1459839600"; d="scan'208";a="986816718" Subject: Re: [PATCH 1/2] perf pt: Mark PT return events as "return" To: Andi Kleen References: <1463773938-26194-1-git-send-email-andi@firstfloor.org> Cc: acme@kernel.org, jolsa@kernel.org, linux-kernel@vger.kernel.org, Andi Kleen From: Adrian Hunter Organization: Intel Finland Oy, Registered Address: PL 281, 00181 Helsinki, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Message-ID: <5742F1F4.9040709@intel.com> Date: Mon, 23 May 2016 15:05:08 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.7.2 MIME-Version: 1.0 In-Reply-To: <1463773938-26194-1-git-send-email-andi@firstfloor.org> Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 20/05/16 22:52, Andi Kleen wrote: > From: Andi Kleen > > With perf script --itrace=cr we can synthesize calls and returns out of > a PT log. However both calls and returns are marked with the same event, > called branches. This makes it difficult to read and post process, > because calls and returns are somewhat diffferent. Did you consider the sample flags? e.g. perf script --itrace=cre -F pid,tid,comm,dso,event,ip,sym,symoff,addr,flags ... uname 1807/1807 branches:u: bB 0 [unknown] ([unknown]) => 7fc78a81e18c brk+0xc (/lib/x86_64-linux-gnu/ld-2.19.so) uname 1807/1807 branches:u: br 7fc78a81e1a5 brk+0x25 (/lib/x86_64-linux-gnu/ld-2.19.so) => 7fc78a81d508 _dl_sysdep_start+0x148 (/lib/x86_64-linux-gnu/ld-2.19.so) uname 1807/1807 branches:u: bc 7fc78a81d630 _dl_sysdep_start+0x270 (/lib/x86_64-linux-gnu/ld-2.19.so) => 7fc78a81fca0 strlen+0x0 (/lib/x86_64-linux-gnu/ld-2.19.so) uname 1807/1807 branches:u: br 7fc78a81fd88 strlen+0xe8 (/lib/x86_64-linux-gnu/ld-2.19.so) => 7fc78a81d635 _dl_sysdep_start+0x275 (/lib/x86_64-linux-gnu/ld-2.19.so) uname 1807/1807 branches:u: bc 7fc78a81d52a _dl_sysdep_start+0x16a (/lib/x86_64-linux-gnu/ld-2.19.so) => 7fc78a81e1e0 sbrk+0x0 (/lib/x86_64-linux-gnu/ld-2.19.so) uname 1807/1807 branches:u: br 7fc78a81e222 sbrk+0x42 (/lib/x86_64-linux-gnu/ld-2.19.so) => 7fc78a81d52f _dl_sysdep_start+0x16f (/lib/x86_64-linux-gnu/ld-2.19.so) uname 1807/1807 branches:u: bc 7fc78a81d563 _dl_sysdep_start+0x1a3 (/lib/x86_64-linux-gnu/ld-2.19.so) => 7fc78a807910 dl_main+0x0 (/lib/x86_64-linux-gnu/ld-2.19.so) uname 1807/1807 branches:u: bE 7fc78a807929 dl_main+0x19 (/lib/x86_64-linux-gnu/ld-2.19.so) => 0 [unknown] ([unknown]) ... You can see 'c' and 'r' flags for calls and returns. > > Create a separate return event and mark the returns as return. > > Cc: adrian.hunter@intel.com > Signed-off-by: Andi Kleen > --- > tools/perf/util/intel-pt.c | 53 +++++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 48 insertions(+), 5 deletions(-) > > diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c > index ddec87f6e616..25f839e765ef 100644 > --- a/tools/perf/util/intel-pt.c > +++ b/tools/perf/util/intel-pt.c > @@ -82,9 +82,12 @@ struct intel_pt { > u64 instructions_id; > > bool sample_branches; > + bool sample_returns; > u32 branches_filter; > u64 branches_sample_type; > + u64 returns_sample_type; > u64 branches_id; > + u64 returns_id; > > bool sample_transactions; > u64 transactions_sample_type; > @@ -960,7 +963,8 @@ static int intel_pt_inject_event(union perf_event *event, > return perf_event__synthesize_sample(event, type, 0, sample, swapped); > } > > -static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) > +static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq, > + bool is_return) > { > int ret; > struct intel_pt *pt = ptq->pt; > @@ -990,8 +994,13 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) > sample.pid = ptq->pid; > sample.tid = ptq->tid; > sample.addr = ptq->state->to_ip; > - sample.id = ptq->pt->branches_id; > - sample.stream_id = ptq->pt->branches_id; > + if (is_return) { > + sample.id = ptq->pt->returns_id; > + sample.stream_id = ptq->pt->returns_id; > + } else { > + sample.id = ptq->pt->branches_id; > + sample.stream_id = ptq->pt->branches_id; > + } > sample.period = 1; > sample.cpu = ptq->cpu; > sample.flags = ptq->flags; > @@ -1014,6 +1023,8 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) > > if (pt->synth_opts.inject) { > ret = intel_pt_inject_event(event, &sample, > + is_return ? > + pt->returns_sample_type : > pt->branches_sample_type, > pt->synth_needs_swap); > if (ret) > @@ -1241,7 +1252,13 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) > thread_stack__set_trace_nr(ptq->thread, state->trace_nr); > > if (pt->sample_branches) { > - err = intel_pt_synth_branch_sample(ptq); > + err = intel_pt_synth_branch_sample(ptq, false); > + if (err) > + return err; > + } > + > + if (pt->sample_returns) { > + err = intel_pt_synth_branch_sample(ptq, true); > if (err) > return err; > } > @@ -1956,7 +1973,33 @@ static int intel_pt_synth_events(struct intel_pt *pt, > } > pt->sample_branches = true; > pt->branches_sample_type = attr.sample_type; > - pt->branches_id = id; > + pt->branches_id = id++; > + } > + if (pt->synth_opts.returns) { > + attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; > + attr.sample_period = 1; > + attr.sample_type |= PERF_SAMPLE_ADDR; > + attr.sample_type &= ~(u64)PERF_SAMPLE_CALLCHAIN; > + attr.sample_type &= ~(u64)PERF_SAMPLE_BRANCH_STACK; > + pr_debug("Synthesizing 'return' event with id %" PRIu64 " sample type %#" PRIx64 "\n", > + id, (u64)attr.sample_type); > + err = intel_pt_synth_event(session, &attr, id); > + if (err) { > + pr_err("%s: failed to synthesize 'return' event type\n", > + __func__); > + return err; > + } > + pt->sample_returns = true; > + pt->returns_sample_type = attr.sample_type; > + pt->returns_id = id; > + evlist__for_each(evlist, evsel) { > + if (evsel->id && evsel->id[0] == pt->returns_id) { > + if (evsel->name) > + zfree(&evsel->name); > + evsel->name = strdup("return"); > + break; > + } > + } > } > > pt->synth_needs_swap = evsel->needs_swap; >