From: kan.liang@linux.intel.com
To: acme@kernel.org, jolsa@redhat.com, peterz@infradead.org,
mingo@redhat.com, linux-kernel@vger.kernel.org
Cc: namhyung@kernel.org, adrian.hunter@intel.com,
mathieu.poirier@linaro.org, ravi.bangoria@linux.ibm.com,
alexey.budankov@linux.intel.com, vitaly.slobodskoy@intel.com,
pavel.gerasimov@intel.com, mpe@ellerman.id.au,
eranian@google.com, ak@linux.intel.com,
Kan Liang <kan.liang@linux.intel.com>
Subject: [PATCH V2 3/9] perf machine: Refine the function for LBR call stack reconstruction
Date: Mon, 9 Mar 2020 10:46:33 -0700 [thread overview]
Message-ID: <20200309174639.4594-4-kan.liang@linux.intel.com> (raw)
In-Reply-To: <20200309174639.4594-1-kan.liang@linux.intel.com>
From: Kan Liang <kan.liang@linux.intel.com>
LBR only collect the user call stack. To reconstruct a call stack, both
kernel call stack and user call stack are required. The function
resolve_lbr_callchain_sample() mix the kernel call stack and user
call stack. Now, with the help of HW idx, perf tool can reconstruct a
more complete call stack by adding some user call stack from previous
sample. However, current implementation is hard to be extended to
support it.
Abstract two new functions to resolve user call stack and kernel
call stack respectively.
No functional changes.
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
---
tools/perf/util/machine.c | 186 ++++++++++++++++++++++++--------------
1 file changed, 120 insertions(+), 66 deletions(-)
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index fd14f1489802..4687067d609b 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -2159,6 +2159,97 @@ static int remove_loops(struct branch_entry *l, int nr,
return nr;
}
+
+static int lbr_callchain_add_kernel_ip(struct thread *thread,
+ struct callchain_cursor *cursor,
+ struct perf_sample *sample,
+ struct symbol **parent,
+ struct addr_location *root_al,
+ bool callee, int end)
+{
+ struct ip_callchain *chain = sample->callchain;
+ u8 cpumode = PERF_RECORD_MISC_USER;
+ int err, i;
+
+ if (callee) {
+ for (i = 0; i < end + 1; i++) {
+ err = add_callchain_ip(thread, cursor, parent,
+ root_al, &cpumode, chain->ips[i],
+ false, NULL, NULL, 0);
+ if (err)
+ return err;
+ }
+ } else {
+ for (i = end; i >= 0; i--) {
+ err = add_callchain_ip(thread, cursor, parent,
+ root_al, &cpumode, chain->ips[i],
+ false, NULL, NULL, 0);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int lbr_callchain_add_lbr_ip(struct thread *thread,
+ struct callchain_cursor *cursor,
+ struct perf_sample *sample,
+ struct symbol **parent,
+ struct addr_location *root_al,
+ bool callee)
+{
+ struct branch_stack *lbr_stack = sample->branch_stack;
+ struct branch_entry *entries = perf_sample__branch_entries(sample);
+ u8 cpumode = PERF_RECORD_MISC_USER;
+ int lbr_nr = lbr_stack->nr;
+ struct branch_flags *flags;
+ u64 ip, branch_from = 0;
+ int err, i;
+
+ if (callee) {
+ ip = entries[0].to;
+ flags = &entries[0].flags;
+ branch_from = entries[0].from;
+ err = add_callchain_ip(thread, cursor, parent,
+ root_al, &cpumode, ip,
+ true, flags, NULL, branch_from);
+ if (err)
+ return err;
+
+ for (i = 0; i < lbr_nr; i++) {
+ ip = entries[i].from;
+ flags = &entries[i].flags;
+ err = add_callchain_ip(thread, cursor, parent,
+ root_al, &cpumode, ip,
+ true, flags, NULL, branch_from);
+ if (err)
+ return err;
+ }
+ } else {
+ for (i = lbr_nr - 1; i >= 0; i--) {
+ ip = entries[i].from;
+ flags = &entries[i].flags;
+ err = add_callchain_ip(thread, cursor, parent,
+ root_al, &cpumode, ip,
+ true, flags, NULL, branch_from);
+ if (err)
+ return err;
+ }
+
+ ip = entries[0].to;
+ flags = &entries[0].flags;
+ branch_from = entries[0].from;
+ err = add_callchain_ip(thread, cursor, parent,
+ root_al, &cpumode, ip,
+ true, flags, NULL, branch_from);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
/*
* Recolve LBR callstack chain sample
* Return:
@@ -2174,81 +2265,44 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
int max_stack)
{
struct ip_callchain *chain = sample->callchain;
- int chain_nr = min(max_stack, (int)chain->nr), i;
- u8 cpumode = PERF_RECORD_MISC_USER;
- u64 ip, branch_from = 0;
+ int chain_nr = min(max_stack, (int)chain->nr);
+ int i, err;
for (i = 0; i < chain_nr; i++) {
if (chain->ips[i] == PERF_CONTEXT_USER)
break;
}
- /* LBR only affects the user callchain */
- if (i != chain_nr) {
- struct branch_stack *lbr_stack = sample->branch_stack;
- struct branch_entry *entries = perf_sample__branch_entries(sample);
- int lbr_nr = lbr_stack->nr, j, k;
- bool branch;
- struct branch_flags *flags;
- /*
- * LBR callstack can only get user call chain.
- * The mix_chain_nr is kernel call chain
- * number plus LBR user call chain number.
- * i is kernel call chain number,
- * 1 is PERF_CONTEXT_USER,
- * lbr_nr + 1 is the user call chain number.
- * For details, please refer to the comments
- * in callchain__printf
- */
- int mix_chain_nr = i + 1 + lbr_nr + 1;
-
- for (j = 0; j < mix_chain_nr; j++) {
- int err;
- branch = false;
- flags = NULL;
-
- if (callchain_param.order == ORDER_CALLEE) {
- if (j < i + 1)
- ip = chain->ips[j];
- else if (j > i + 1) {
- k = j - i - 2;
- ip = entries[k].from;
- branch = true;
- flags = &entries[k].flags;
- } else {
- ip = entries[0].to;
- branch = true;
- flags = &entries[0].flags;
- branch_from = entries[0].from;
- }
- } else {
- if (j < lbr_nr) {
- k = lbr_nr - j - 1;
- ip = entries[k].from;
- branch = true;
- flags = &entries[k].flags;
- }
- else if (j > lbr_nr)
- ip = chain->ips[i + 1 - (j - lbr_nr)];
- else {
- ip = entries[0].to;
- branch = true;
- flags = &entries[0].flags;
- branch_from = entries[0].from;
- }
- }
+ /*
+ * LBR only affects the user callchain.
+ * Fall back if there is no user callchain.
+ */
+ if (i == chain_nr)
+ return 0;
- err = add_callchain_ip(thread, cursor, parent,
- root_al, &cpumode, ip,
- branch, flags, NULL,
- branch_from);
- if (err)
- return (err < 0) ? err : 0;
- }
- return 1;
+ if (callchain_param.order == ORDER_CALLEE) {
+ err = lbr_callchain_add_kernel_ip(thread, cursor, sample,
+ parent, root_al, true, i);
+ if (err)
+ goto error;
+ err = lbr_callchain_add_lbr_ip(thread, cursor, sample,
+ parent, root_al, true);
+ if (err)
+ goto error;
+ } else {
+ err = lbr_callchain_add_lbr_ip(thread, cursor, sample,
+ parent, root_al, false);
+ if (err)
+ goto error;
+ err = lbr_callchain_add_kernel_ip(thread, cursor, sample,
+ parent, root_al, false, i);
+ if (err)
+ goto error;
}
- return 0;
+ return 1;
+error:
+ return (err < 0) ? err : 0;
}
static int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread,
--
2.17.1
next prev parent reply other threads:[~2020-03-09 17:47 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-09 17:46 [PATCH V2 0/9] Stitch LBR call stack (Perf Tools) kan.liang
2020-03-09 17:46 ` [PATCH V2 1/9] perf pmu: Add support for PMU capabilities kan.liang
2020-03-10 13:06 ` Arnaldo Carvalho de Melo
2020-03-10 13:53 ` Liang, Kan
2020-03-10 14:04 ` Arnaldo Carvalho de Melo
2020-03-10 16:54 ` Liang, Kan
2020-03-10 17:30 ` Arnaldo Carvalho de Melo
2020-03-09 17:46 ` [PATCH V2 2/9] perf header: Support CPU " kan.liang
2020-03-09 17:46 ` kan.liang [this message]
2020-03-09 17:46 ` [PATCH V2 4/9] perf tools: Stitch LBR call stack kan.liang
2020-03-09 17:46 ` [PATCH V2 5/9] perf report: Add option to enable the LBR stitching approach kan.liang
2020-03-09 17:46 ` [PATCH V2 6/9] perf script: " kan.liang
2020-03-09 17:46 ` [PATCH V2 7/9] perf top: " kan.liang
2020-03-09 17:46 ` [PATCH V2 8/9] perf c2c: " kan.liang
2020-03-09 17:46 ` [PATCH V2 9/9] perf hist: Add fast path for duplicate entries check approach kan.liang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200309174639.4594-4-kan.liang@linux.intel.com \
--to=kan.liang@linux.intel.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=ak@linux.intel.com \
--cc=alexey.budankov@linux.intel.com \
--cc=eranian@google.com \
--cc=jolsa@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mathieu.poirier@linaro.org \
--cc=mingo@redhat.com \
--cc=mpe@ellerman.id.au \
--cc=namhyung@kernel.org \
--cc=pavel.gerasimov@intel.com \
--cc=peterz@infradead.org \
--cc=ravi.bangoria@linux.ibm.com \
--cc=vitaly.slobodskoy@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox