From: kan.liang@linux.intel.com
To: peterz@infradead.org, acme@kernel.org, mingo@kernel.org,
linux-kernel@vger.kernel.org
Cc: jolsa@kernel.org, namhyung@kernel.org, ak@linux.intel.com,
vitaly.slobodskoy@intel.com, pavel.gerasimov@intel.com,
Kan Liang <kan.liang@linux.intel.com>
Subject: [PATCH 05/10] perf machine: Refine the function for LBR call stack reconstruction
Date: Mon, 7 Oct 2019 10:59:05 -0700 [thread overview]
Message-ID: <20191007175910.2805-6-kan.liang@linux.intel.com> (raw)
In-Reply-To: <20191007175910.2805-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 TOS, 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, 119 insertions(+), 67 deletions(-)
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 70a9f8716a4b..e3e516e30093 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -2183,6 +2183,96 @@ 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;
+ 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 = lbr_stack->entries[0].to;
+ flags = &lbr_stack->entries[0].flags;
+ branch_from = lbr_stack->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 = lbr_stack->entries[i].from;
+ flags = &lbr_stack->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 = lbr_stack->entries[i].from;
+ flags = &lbr_stack->entries[i].flags;
+ err = add_callchain_ip(thread, cursor, parent,
+ root_al, &cpumode, ip,
+ true, flags, NULL, branch_from);
+ if (err)
+ return err;
+ }
+
+ ip = lbr_stack->entries[0].to;
+ flags = &lbr_stack->entries[0].flags;
+ branch_from = lbr_stack->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:
@@ -2198,82 +2288,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;
- 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 = lbr_stack->entries[k].from;
- branch = true;
- flags = &lbr_stack->entries[k].flags;
- } else {
- ip = lbr_stack->entries[0].to;
- branch = true;
- flags = &lbr_stack->entries[0].flags;
- branch_from =
- lbr_stack->entries[0].from;
- }
- } else {
- if (j < lbr_nr) {
- k = lbr_nr - j - 1;
- ip = lbr_stack->entries[k].from;
- branch = true;
- flags = &lbr_stack->entries[k].flags;
- }
- else if (j > lbr_nr)
- ip = chain->ips[i + 1 - (j - lbr_nr)];
- else {
- ip = lbr_stack->entries[0].to;
- branch = true;
- flags = &lbr_stack->entries[0].flags;
- branch_from =
- lbr_stack->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:[~2019-10-07 18:00 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-07 17:59 [PATCH 00/10] Stitch LBR call stack kan.liang
2019-10-07 17:59 ` [PATCH 01/10] perf/core, x86: Add PERF_SAMPLE_LBR_TOS kan.liang
2019-10-08 8:31 ` Peter Zijlstra
2019-10-08 13:53 ` Liang, Kan
2019-10-08 14:38 ` Peter Zijlstra
2019-10-08 15:25 ` Liang, Kan
2019-10-08 16:32 ` Peter Zijlstra
2019-10-07 17:59 ` [PATCH 02/10] perf tools: Support PERF_SAMPLE_LBR_TOS kan.liang
2019-10-07 17:59 ` [PATCH 03/10] perf pmu: Add support for PMU capabilities kan.liang
2019-10-07 17:59 ` [PATCH 04/10] perf header: Support CPU " kan.liang
2019-10-07 17:59 ` kan.liang [this message]
2019-10-07 17:59 ` [PATCH 06/10] perf tools: Stitch LBR call stack kan.liang
2019-10-07 17:59 ` [PATCH 07/10] perf report: Add option to enable the LBR stitching approach kan.liang
2019-10-07 17:59 ` [PATCH 08/10] perf script: " kan.liang
2019-10-07 17:59 ` [PATCH 09/10] perf top: " kan.liang
2019-10-07 17:59 ` [PATCH 10/10] perf c2c: " kan.liang
2019-10-07 18:24 ` [PATCH 00/10] Stitch LBR call stack Ingo Molnar
2019-10-07 20:06 ` Liang, Kan
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=20191007175910.2805-6-kan.liang@linux.intel.com \
--to=kan.liang@linux.intel.com \
--cc=acme@kernel.org \
--cc=ak@linux.intel.com \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=namhyung@kernel.org \
--cc=pavel.gerasimov@intel.com \
--cc=peterz@infradead.org \
--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;
as well as URLs for NNTP newsgroup(s).