linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Implement lbr-as-callgraph v3
@ 2014-01-14  1:04 Andi Kleen
  2014-01-14  1:04 ` [PATCH 1/6] perf, tools: fix BFD detection on opensuse Andi Kleen
                   ` (6 more replies)
  0 siblings, 7 replies; 16+ messages in thread
From: Andi Kleen @ 2014-01-14  1:04 UTC (permalink / raw)
  To: acme
  Cc: jolsa, namhyung, mingo, dsahern, fweisbec, adrian.hunter, linux-kernel

This patchkit implements lbr-as-callgraphs in per freport,
as an alternative way to present LBR information.

Current perf report does a histogram over the branch edges,
which is useful to look at basic blocks, but doesn't tell
you anything about the larger control flow behaviour.

This patchkit adds a new option --branch-history that
adds the branch paths to the callgraph history instead.

This allows to reason about individual branch paths leading
to specific samples.

Updates to v1:
- rebased on perf/core
- fix various issues
- rename the option to --branch-history
- various fixes to display the information more concise

Updates to v3:
- White space changes
- Consolidate some patches
- Update some descriptions

Example output:

    % perf record -b -g ./tsrc/tcall
    [ perf record: Woken up 1 times to write data ]
    [ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
    % perf report --branch-history
    ...
        54.91%  tcall.c:6  [.] f2                      tcall
                |
                |--65.53%-- f2 tcall.c:5
                |          |
                |          |--70.83%-- f1 tcall.c:11
                |          |          f1 tcall.c:10
                |          |          main tcall.c:18
                |          |          main tcall.c:18
                |          |          main tcall.c:17
                |          |          main tcall.c:17
                |          |          f1 tcall.c:13
                |          |          f1 tcall.c:13
                |          |          f2 tcall.c:7
                |          |          f2 tcall.c:5
                |          |          f1 tcall.c:12
                |          |          f1 tcall.c:12
                |          |          f2 tcall.c:7
                |          |          f2 tcall.c:5
                |          |          f1 tcall.c:11



^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/6] perf, tools: fix BFD detection on opensuse
  2014-01-14  1:04 Implement lbr-as-callgraph v3 Andi Kleen
@ 2014-01-14  1:04 ` Andi Kleen
  2014-01-14  1:04 ` [PATCH 2/6] perf, tools: Support handling complete branch stacks as histograms v3 Andi Kleen
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2014-01-14  1:04 UTC (permalink / raw)
  To: acme
  Cc: jolsa, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

opensuse libbfd requires -lz -liberty to build. Add those
to the BFD feature detection.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 tools/perf/config/Makefile                | 2 +-
 tools/perf/config/feature-checks/Makefile | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 01dd43d..d86d33c 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -478,7 +478,7 @@ else
 endif
 
 ifeq ($(feature-libbfd), 1)
-  EXTLIBS += -lbfd
+  EXTLIBS += -lbfd -lz -liberty
 endif
 
 ifdef NO_DEMANGLE
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 7cf6fcd..a430e4f 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -120,7 +120,7 @@ test-libpython-version.bin:
 	$(BUILD) $(FLAGS_PYTHON_EMBED)
 
 test-libbfd.bin:
-	$(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
+	$(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
 
 test-liberty.bin:
 	$(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/6] perf, tools: Support handling complete branch stacks as histograms v3
  2014-01-14  1:04 Implement lbr-as-callgraph v3 Andi Kleen
  2014-01-14  1:04 ` [PATCH 1/6] perf, tools: fix BFD detection on opensuse Andi Kleen
@ 2014-01-14  1:04 ` Andi Kleen
  2014-01-15 14:48   ` Jiri Olsa
  2014-01-15 15:00   ` Jiri Olsa
  2014-01-14  1:04 ` [PATCH 3/6] perf, tools: Add --branch-history option to report v2 Andi Kleen
                   ` (4 subsequent siblings)
  6 siblings, 2 replies; 16+ messages in thread
From: Andi Kleen @ 2014-01-14  1:04 UTC (permalink / raw)
  To: acme
  Cc: jolsa, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

Currently branch stacks can be only shown as edge histograms for
individual branches. I never found this display particularly useful.

This implements an alternative mode that creates histograms over complete
branch traces, instead of individual branches, similar to how normal
callgraphs are handled. This is done by putting it in
front of the normal callgraph and then using the normal callgraph
histogram infrastructure to unify them.

This way in complex functions we can understand the control flow
that lead to a particular sample, and may even see some control
flow in the caller for short functions.

Example (simplified, of course for such simple code this
is usually not needed):

tcall.c:

volatile a = 10000, b = 100000, c;

__attribute__((noinline)) f2()
{
	c = a / b;
}

__attribute__((noinline)) f1()
{
	f2();
	f2();
}
main()
{
	int i;
	for (i = 0; i < 1000000; i++)
		f1();
}

% perf record -b -g ./tsrc/tcall
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
% perf report --branch-history
...
    54.91%  tcall.c:6  [.] f2                      tcall
            |
            |--65.53%-- f2 tcall.c:5
            |          |
            |          |--70.83%-- f1 tcall.c:11
            |          |          f1 tcall.c:10
            |          |          main tcall.c:18
            |          |          main tcall.c:18
            |          |          main tcall.c:17
            |          |          main tcall.c:17
            |          |          f1 tcall.c:13
            |          |          f1 tcall.c:13
            |          |          f2 tcall.c:7
            |          |          f2 tcall.c:5
            |          |          f1 tcall.c:12
            |          |          f1 tcall.c:12
            |          |          f2 tcall.c:7
            |          |          f2 tcall.c:5
            |          |          f1 tcall.c:11
            |          |
            |           --29.17%-- f1 tcall.c:12
            |                     f1 tcall.c:12
            |                     f2 tcall.c:7
            |                     f2 tcall.c:5
            |                     f1 tcall.c:11
            |                     f1 tcall.c:10
            |                     main tcall.c:18
            |                     main tcall.c:18
            |                     main tcall.c:17
            |                     main tcall.c:17
            |                     f1 tcall.c:13
            |                     f1 tcall.c:13
            |                     f2 tcall.c:7
            |                     f2 tcall.c:5
            |                     f1 tcall.c:12

The default output is unchanged.

This is only implemented in perf report, no change to record
or anywhere else.

This adds the basic code to report:
- add a new "branch" option to the -g option parser to enable this mode
- when the flag is set include the LBR into the callstack in machine.c.
The rest of the history code is unchanged and doesn't know the difference
between LBR entry and normal call entry.
- detect overlaps with the callchain
- remove small loop duplicates in the LBR

Current limitations:
- The LBR flags (mispredict etc.) are not shown in the history
and LBR entries have no special marker.
- It would be nice if annotate marked the LBR entries somehow
(e.g. with arrows)

v2: Various fixes.
v3: Merge further patches into this one. Fix white space.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 tools/perf/builtin-report.c |  15 +++-
 tools/perf/util/callchain.h |   1 +
 tools/perf/util/machine.c   | 176 ++++++++++++++++++++++++++++++++++++++------
 tools/perf/util/symbol.h    |   3 +-
 4 files changed, 168 insertions(+), 27 deletions(-)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 46864dd..19a74e1 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -658,7 +658,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
 		callchain_param.order = ORDER_CALLER;
 	else if (!strncmp(tok2, "callee", strlen("callee")))
 		callchain_param.order = ORDER_CALLEE;
-	else
+	else if (tok2[0] != 0)
 		return -1;
 
 	/* Get the sort key */
@@ -669,8 +669,15 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
 		callchain_param.key = CCKEY_FUNCTION;
 	else if (!strncmp(tok2, "address", strlen("address")))
 		callchain_param.key = CCKEY_ADDRESS;
-	else
+	else if (tok2[0] != 0)
 		return -1;
+
+	tok2 = strtok(NULL, ",");
+	if (!tok2)
+		goto setup;
+	if (!strncmp(tok2, "branch", 6))
+		callchain_param.branch_callstack = 1;
+
 setup:
 	if (callchain_register_param(&callchain_param) < 0) {
 		pr_err("Can't register callchain params\n");
@@ -786,8 +793,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 		   "regex filter to identify parent, see: '--sort parent'"),
 	OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
 		    "Only display entries with parent-match"),
-	OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
-		     "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
+	OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order[,branch]",
+		     "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address), add branches. "
 		     "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
 	OPT_INTEGER(0, "max-stack", &report.max_stack,
 		    "Set the maximum stack depth when parsing the callchain, "
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 08b25af..a1a298a 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -53,6 +53,7 @@ struct callchain_param {
 	sort_chain_func_t	sort;
 	enum chain_order	order;
 	enum chain_key		key;
+	bool			branch_callstack;
 };
 
 struct callchain_list {
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 0130279..084c80c 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -11,6 +11,7 @@
 #include <stdbool.h>
 #include <symbol/kallsyms.h>
 #include "unwind.h"
+#include "linux/hash.h"
 
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 {
@@ -1248,9 +1249,98 @@ struct branch_info *machine__resolve_bstack(struct machine *machine,
 	return bi;
 }
 
+static int add_callchain_ip(struct machine *machine,
+			    struct thread *thread,
+			    struct symbol **parent,
+			    struct addr_location *root_al,
+			    int cpumode,
+			    u64 ip)
+{
+	struct addr_location al;
+
+	al.filtered = false;
+	al.sym = NULL;
+	if (cpumode == -1) {
+		int i;
+
+		for (i = 0; i < (int)NCPUMODES && !al.sym; i++) {
+			/*
+			 * We cannot use the header.misc hint to determine whether a
+			 * branch stack address is user, kernel, guest, hypervisor.
+			 * Branches may straddle the kernel/user/hypervisor boundaries.
+			 * Thus, we have to try consecutively until we find a match
+			 * or else, the symbol is unknown
+			 */
+			thread__find_addr_location(thread, machine, cpumodes[i],
+					MAP__FUNCTION,
+					ip, &al);
+		}
+	} else {
+		thread__find_addr_location(thread, machine, cpumode,
+					   MAP__FUNCTION, ip, &al);
+	}
+	if (al.sym != NULL) {
+		if (sort__has_parent && !*parent &&
+		    symbol__match_regex(al.sym, &parent_regex))
+			*parent = al.sym;
+		else if (have_ignore_callees && root_al &&
+		  symbol__match_regex(al.sym, &ignore_callees_regex)) {
+			/* Treat this symbol as the root,
+			   forgetting its callees. */
+			*root_al = al;
+			callchain_cursor_reset(&callchain_cursor);
+		}
+		if (!symbol_conf.use_callchain)
+			return -EINVAL;
+	}
+
+	return callchain_cursor_append(&callchain_cursor, ip, al.map, al.sym);
+}
+
+#define CHASHSZ 127
+#define CHASHBITS 7
+#define NO_ENTRY 0xff
+
+#define PERF_MAX_BRANCH_DEPTH 127
+
+/* Remove loops. */
+static int remove_loops(struct branch_entry *l, int nr)
+{
+	int i, j, off;
+	unsigned char chash[CHASHSZ];
+	memset(chash, -1, sizeof(chash));
+
+	BUG_ON(nr >= 256);
+	for (i = 0; i < nr; i++) {
+		int h = hash_64(l[i].from, CHASHBITS) % CHASHSZ;
+
+		/* no collision handling for now */
+		if (chash[h] == NO_ENTRY) {
+			chash[h] = i;
+		} else if (l[chash[h]].from == l[i].from) {
+			bool is_loop = true;
+			/* check if it is a real loop */
+			off = 0;
+			for (j = chash[h]; j < i && i + off < nr; j++, off++)
+				if (l[j].from != l[i + off].from) {
+					is_loop = false;
+					break;
+				}
+			if (is_loop) {
+				memmove(l + i, l + i + off,
+					(nr - (i + off))
+					* sizeof(struct branch_entry));
+				nr -= off;
+			}
+		}
+	}
+	return nr;
+}
+
 static int machine__resolve_callchain_sample(struct machine *machine,
 					     struct thread *thread,
 					     struct ip_callchain *chain,
+					     struct branch_stack *branch,
 					     struct symbol **parent,
 					     struct addr_location *root_al,
 					     int max_stack)
@@ -1259,17 +1349,73 @@ static int machine__resolve_callchain_sample(struct machine *machine,
 	int chain_nr = min(max_stack, (int)chain->nr);
 	int i;
 	int err;
+	int first_call = 0;
 
 	callchain_cursor_reset(&callchain_cursor);
 
+	/*
+	 * Add branches to call stack for easier browsing. This gives
+	 * more context for a sample than just the callers.
+	 *
+	 * This uses individual histograms of paths compared to the
+	 * aggregated histograms the normal LBR mode uses.
+	 *
+	 * Limitations for now:
+	 * - No extra filters
+	 * - No annotations (should annotate somehow)
+	 */
+
+	if (branch->nr > PERF_MAX_BRANCH_DEPTH) {
+		pr_warning("corrupted branch chain. skipping...\n");
+		return 0;
+	}
+
+	if (callchain_param.branch_callstack) {
+		int nr = min(max_stack, (int)branch->nr);
+		struct branch_entry be[nr];
+
+		for (i = 0; i < nr; i++) {
+			if (callchain_param.order == ORDER_CALLEE) {
+				be[i] = branch->entries[i];
+				/*
+				 * Check for overlap into the callchain.
+				 * The return address is one off compared to
+				 * the branch entry. To adjust for this
+				 * assume the calling instruction is not longer
+				 * than 8 bytes.
+				 */
+				if (be[i].from < chain->ips[first_call] &&
+				    be[i].from >= chain->ips[first_call] - 8)
+					first_call++;
+			} else
+				be[i] = branch->entries[branch->nr - i - 1];
+		}
+
+		nr = remove_loops(be, nr);
+
+		for (i = 0; i < nr; i++) {
+			err = add_callchain_ip(machine, thread, parent,
+					       root_al,
+					       -1, be[i].to);
+			if (!err)
+				err = add_callchain_ip(machine, thread,
+						       parent, root_al,
+						       -1, be[i].from);
+			if (err == -EINVAL)
+				break;
+			if (err)
+				return err;
+		}
+		chain_nr -= nr;
+	}
+
 	if (chain->nr > PERF_MAX_STACK_DEPTH) {
 		pr_warning("corrupted callchain. skipping...\n");
 		return 0;
 	}
 
-	for (i = 0; i < chain_nr; i++) {
+	for (i = first_call; i < chain_nr; i++) {
 		u64 ip;
-		struct addr_location al;
 
 		if (callchain_param.order == ORDER_CALLEE)
 			ip = chain->ips[i];
@@ -1300,26 +1446,10 @@ static int machine__resolve_callchain_sample(struct machine *machine,
 			continue;
 		}
 
-		al.filtered = false;
-		thread__find_addr_location(thread, machine, cpumode,
-					   MAP__FUNCTION, ip, &al);
-		if (al.sym != NULL) {
-			if (sort__has_parent && !*parent &&
-			    symbol__match_regex(al.sym, &parent_regex))
-				*parent = al.sym;
-			else if (have_ignore_callees && root_al &&
-			  symbol__match_regex(al.sym, &ignore_callees_regex)) {
-				/* Treat this symbol as the root,
-				   forgetting its callees. */
-				*root_al = al;
-				callchain_cursor_reset(&callchain_cursor);
-			}
-			if (!symbol_conf.use_callchain)
-				break;
-		}
 
-		err = callchain_cursor_append(&callchain_cursor,
-					      ip, al.map, al.sym);
+		err = add_callchain_ip(machine, thread, parent, root_al, cpumode, ip);
+		if (err == -EINVAL)
+			break;
 		if (err)
 			return err;
 	}
@@ -1345,7 +1475,9 @@ int machine__resolve_callchain(struct machine *machine,
 	int ret;
 
 	ret = machine__resolve_callchain_sample(machine, thread,
-						sample->callchain, parent,
+						sample->callchain,
+						sample->branch_stack,
+						parent,
 						root_al, max_stack);
 	if (ret)
 		return ret;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index cbd6803..0da4b24 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -99,7 +99,8 @@ struct symbol_conf {
 			annotate_asm_raw,
 			annotate_src,
 			event_group,
-			demangle;
+			demangle,
+			branch_callstack;
 	const char	*vmlinux_name,
 			*kallsyms_name,
 			*source_prefix,
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/6] perf, tools: Add --branch-history option to report v2
  2014-01-14  1:04 Implement lbr-as-callgraph v3 Andi Kleen
  2014-01-14  1:04 ` [PATCH 1/6] perf, tools: fix BFD detection on opensuse Andi Kleen
  2014-01-14  1:04 ` [PATCH 2/6] perf, tools: Support handling complete branch stacks as histograms v3 Andi Kleen
@ 2014-01-14  1:04 ` Andi Kleen
  2014-01-15 14:44   ` Jiri Olsa
  2014-01-14  1:04 ` [PATCH 4/6] perf, tools: Enable printing the srcline in the history Andi Kleen
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 16+ messages in thread
From: Andi Kleen @ 2014-01-14  1:04 UTC (permalink / raw)
  To: acme
  Cc: jolsa, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

Add a --branch-history option to perf report that changes all
the settings necessary for using the branches in callstacks.

This is just a short cut to make this nicer to use, it does
not enable any functionality by itself.

v2: Change sort order. Rename option to --branch-history to
be less confusing.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 tools/perf/Documentation/perf-report.txt |  5 +++++
 tools/perf/builtin-report.c              | 27 ++++++++++++++++++++++++---
 2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 8eab8a4..5410f35 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -223,6 +223,11 @@ OPTIONS
 	branch stacks and it will automatically switch to the branch view mode,
 	unless --no-branch-stack is used.
 
+--branch-history::
+	Add the addresses of sampled taken branches to the callstack.
+	This allows to examine the path the program took to each sample.
+	The data collection must have used -b (or -j) and -g.
+
 --objdump=<path>::
         Path to objdump binary.
 
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 19a74e1..24b48ec 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -715,6 +715,16 @@ parse_branch_mode(const struct option *opt __maybe_unused,
 }
 
 static int
+parse_branch_call_mode(const struct option *opt __maybe_unused,
+		  const char *str __maybe_unused, int unset)
+{
+	int *branch_mode = opt->value;
+
+	*branch_mode = !unset;
+	return 0;
+}
+
+static int
 parse_percent_limit(const struct option *opt, const char *str,
 		    int unset __maybe_unused)
 {
@@ -729,7 +739,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 	struct perf_session *session;
 	struct stat st;
 	bool has_br_stack = false;
-	int branch_mode = -1;
+	int branch_mode = -1, branch_call_mode = -1;
 	int ret = -1;
 	char callchain_default_opt[] = "fractal,0.5,callee";
 	const char * const report_usage[] = {
@@ -838,7 +848,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 	OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
 		    "Show event group information together"),
 	OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
-		    "use branch records for histogram filling", parse_branch_mode),
+		    "use branch records for per branch histogram filling", parse_branch_mode),
+	OPT_CALLBACK_NOOPT(0, "branch-history", &branch_call_mode, "",
+		    "add last branch records to call history",
+		    parse_branch_call_mode),
 	OPT_STRING(0, "objdump", &objdump_path, "path",
 		   "objdump binary to use for disassembly and annotations"),
 	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
@@ -886,8 +899,16 @@ repeat:
 	has_br_stack = perf_header__has_feat(&session->header,
 					     HEADER_BRANCH_STACK);
 
-	if (branch_mode == -1 && has_br_stack)
+	if (branch_mode == -1 && has_br_stack && branch_call_mode == -1)
 		sort__mode = SORT_MODE__BRANCH;
+	if (branch_call_mode != -1) {
+		callchain_param.branch_callstack = 1;
+		callchain_param.key = CCKEY_ADDRESS;
+		symbol_conf.use_callchain = true;
+		callchain_register_param(&callchain_param);
+		if (sort_order == default_sort_order)
+			sort_order = "srcline,symbol,dso";
+	}
 
 	/* sort__mode could be NORMAL if --no-branch-stack */
 	if (sort__mode == SORT_MODE__BRANCH) {
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 4/6] perf, tools: Enable printing the srcline in the history
  2014-01-14  1:04 Implement lbr-as-callgraph v3 Andi Kleen
                   ` (2 preceding siblings ...)
  2014-01-14  1:04 ` [PATCH 3/6] perf, tools: Add --branch-history option to report v2 Andi Kleen
@ 2014-01-14  1:04 ` Andi Kleen
  2014-01-15 15:12   ` Jiri Olsa
  2014-01-14  1:04 ` [PATCH 5/6] perf, tools: Only print base source file for srcline Andi Kleen
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 16+ messages in thread
From: Andi Kleen @ 2014-01-14  1:04 UTC (permalink / raw)
  To: acme
  Cc: jolsa, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

For lbr-as-callgraph we need to see the line number in the history,
because many LBR entries can be in a single function, and just
showing the same function name many times is not useful.

When the history code is configured to sort by address, also try to
resolve the address to a file:srcline and display this in the browser.
If that doesn't work still display the address.

This can be also useful without LBRs for understanding which call in a large
function (or in which inlined function) called something else.

Contains fixes from Namhyung Kim

Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 tools/perf/ui/browsers/hists.c | 15 ++++++++++++---
 tools/perf/ui/stdio/hist.c     | 16 +++++++++++++---
 tools/perf/util/callchain.h    |  1 +
 tools/perf/util/machine.c      |  2 +-
 tools/perf/util/srcline.c      |  6 ++++--
 5 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index b720b92..060fffc 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -399,9 +399,18 @@ static char *callchain_list__sym_name(struct callchain_list *cl,
 {
 	int printed;
 
-	if (cl->ms.sym)
-		printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
-	else
+	if (cl->ms.sym) {
+		if (callchain_param.key == CCKEY_ADDRESS &&
+		    cl->ms.map && !cl->srcline)
+			cl->srcline = get_srcline(cl->ms.map->dso,
+						  map__rip_2objdump(cl->ms.map,
+								    cl->ip));
+		if (cl->srcline)
+			printed = scnprintf(bf, bfsize, "%s %s",
+					cl->ms.sym->name, cl->srcline);
+		else
+			printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
+	} else
 		printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
 
 	if (show_dso)
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 831fbb7..a494eed 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -56,9 +56,19 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
 		} else
 			ret += fprintf(fp, "%s", "          ");
 	}
-	if (chain->ms.sym)
-		ret += fprintf(fp, "%s\n", chain->ms.sym->name);
-	else
+	if (chain->ms.sym) {
+		if (callchain_param.key == CCKEY_ADDRESS &&
+		    chain->ms.map)
+			chain->srcline = get_srcline(chain->ms.map->dso,
+						  map__rip_2objdump(
+							  chain->ms.map,
+							  chain->ip));
+		if (chain->srcline)
+			ret += fprintf(fp, "%s %s\n",
+				       chain->ms.sym->name, chain->srcline);
+		else
+			ret += fprintf(fp, "%s\n", chain->ms.sym->name);
+	} else
 		ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);
 
 	return ret;
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index a1a298a..7e74c1d 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -59,6 +59,7 @@ struct callchain_param {
 struct callchain_list {
 	u64			ip;
 	struct map_symbol	ms;
+	char		       *srcline;
 	struct list_head	list;
 };
 
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 084c80c..f839e6f 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1294,7 +1294,7 @@ static int add_callchain_ip(struct machine *machine,
 			return -EINVAL;
 	}
 
-	return callchain_cursor_append(&callchain_cursor, ip, al.map, al.sym);
+	return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym);
 }
 
 #define CHASHSZ 127
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 7e67879..680c02b 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -258,7 +258,7 @@ char *get_srcline(struct dso *dso, unsigned long addr)
 	const char *dso_name;
 
 	if (!dso->has_srcline)
-		return SRCLINE_UNKNOWN;
+		goto out;
 
 	if (dso->symsrc_filename)
 		dso_name = dso->symsrc_filename;
@@ -289,7 +289,9 @@ out:
 		dso->has_srcline = 0;
 		dso__free_a2l(dso);
 	}
-	return SRCLINE_UNKNOWN;
+	if (asprintf(&srcline, "%s[%lx]", dso->short_name, addr) < 0)
+		return SRCLINE_UNKNOWN;
+	return srcline;
 }
 
 void free_srcline(char *srcline)
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 5/6] perf, tools: Only print base source file for srcline
  2014-01-14  1:04 Implement lbr-as-callgraph v3 Andi Kleen
                   ` (3 preceding siblings ...)
  2014-01-14  1:04 ` [PATCH 4/6] perf, tools: Enable printing the srcline in the history Andi Kleen
@ 2014-01-14  1:04 ` Andi Kleen
  2014-01-14  1:04 ` [PATCH 6/6] perf, tools: Support source line numbers in annotate Andi Kleen
  2014-01-15 13:59 ` Implement lbr-as-callgraph v3 Jiri Olsa
  6 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2014-01-14  1:04 UTC (permalink / raw)
  To: acme
  Cc: jolsa, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

For perf report with --sort srcline only print the base source file
name. This makes the results generally fit much better to the
screen. The path is usually not that useful anyways because it is
often from different systems.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 tools/perf/util/srcline.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 680c02b..88bf0e8 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -274,7 +274,7 @@ char *get_srcline(struct dso *dso, unsigned long addr)
 	if (!addr2line(dso_name, addr, &file, &line, dso))
 		goto out;
 
-	if (asprintf(&srcline, "%s:%u", file, line) < 0) {
+	if (asprintf(&srcline, "%s:%u", basename(file), line) < 0) {
 		free(file);
 		goto out;
 	}
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 6/6] perf, tools: Support source line numbers in annotate
  2014-01-14  1:04 Implement lbr-as-callgraph v3 Andi Kleen
                   ` (4 preceding siblings ...)
  2014-01-14  1:04 ` [PATCH 5/6] perf, tools: Only print base source file for srcline Andi Kleen
@ 2014-01-14  1:04 ` Andi Kleen
  2014-01-15 13:59 ` Implement lbr-as-callgraph v3 Jiri Olsa
  6 siblings, 0 replies; 16+ messages in thread
From: Andi Kleen @ 2014-01-14  1:04 UTC (permalink / raw)
  To: acme
  Cc: jolsa, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

From: Andi Kleen <ak@linux.intel.com>

With srcline key/sort'ing it's useful to have line numbers
in the annotate window. This patch implements this.

Use objdump -l to request the line numbers and
save them in the line structure. Then the browser
displays them for source lines.

The line numbers are not displayed by default, but can be
toggled on with 'k'

There is one unfortunate problem with this setup. For
lines not containing source and which are outside functions
objdump -l reports line numbers off by a few: it always reports
the first line number in the next function even for lines
that are outside the function.
I haven't find a nice way to detect/correct this. Probably objdump
has to be fixed.
See https://sourceware.org/bugzilla/show_bug.cgi?id=16433

The line numbers are still useful even with these problems,
as most are correct and the ones which are not are nearby.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
---
 tools/perf/ui/browsers/annotate.c | 13 ++++++++++++-
 tools/perf/util/annotate.c        | 30 +++++++++++++++++++++++++-----
 tools/perf/util/annotate.h        |  1 +
 3 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index f0697a3..8df6787 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -27,6 +27,7 @@ static struct annotate_browser_opt {
 	bool hide_src_code,
 	     use_offset,
 	     jump_arrows,
+	     show_linenr,
 	     show_nr_jumps;
 } annotate_browser__opts = {
 	.use_offset	= true,
@@ -128,7 +129,11 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
 	if (!*dl->line)
 		slsmg_write_nstring(" ", width - pcnt_width);
 	else if (dl->offset == -1) {
-		printed = scnprintf(bf, sizeof(bf), "%*s  ",
+		if (dl->line_nr && annotate_browser__opts.show_linenr)
+			printed = scnprintf(bf, sizeof(bf), "%*s %-5d ",
+					ab->addr_width, " ", dl->line_nr);
+		else
+			printed = scnprintf(bf, sizeof(bf), "%*s  ",
 				    ab->addr_width, " ");
 		slsmg_write_nstring(bf, printed);
 		slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
@@ -733,6 +738,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
 		"o             Toggle disassembler output/simplified view\n"
 		"s             Toggle source code view\n"
 		"/             Search string\n"
+		"k	       Toggle line numbers\n"
 		"r             Run available scripts\n"
 		"?             Search string backwards\n");
 			continue;
@@ -741,6 +747,10 @@ static int annotate_browser__run(struct annotate_browser *browser,
 				script_browse(NULL);
 				continue;
 			}
+		case 'k':
+			annotate_browser__opts.show_linenr =
+				!annotate_browser__opts.show_linenr;
+			break;
 		case 'H':
 			nd = browser->curr_hot;
 			break;
@@ -984,6 +994,7 @@ static struct annotate_config {
 } annotate__configs[] = {
 	ANNOTATE_CFG(hide_src_code),
 	ANNOTATE_CFG(jump_arrows),
+	ANNOTATE_CFG(show_linenr),
 	ANNOTATE_CFG(show_nr_jumps),
 	ANNOTATE_CFG(use_offset),
 };
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 469eb67..f020110 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -15,11 +15,13 @@
 #include "debug.h"
 #include "annotate.h"
 #include "evsel.h"
+#include <regex.h>
 #include <pthread.h>
 #include <linux/bitops.h>
 
 const char 	*disassembler_style;
 const char	*objdump_path;
+static regex_t	 file_lineno;
 
 static struct ins *ins__find(const char *name);
 static int disasm_line__parse(char *line, char **namep, char **rawp);
@@ -562,13 +564,15 @@ out_free_name:
 	return -1;
 }
 
-static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
+static struct disasm_line *disasm_line__new(s64 offset, char *line,
+					size_t privsize, int line_nr)
 {
 	struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
 
 	if (dl != NULL) {
 		dl->offset = offset;
 		dl->line = strdup(line);
+		dl->line_nr = line_nr;
 		if (dl->line == NULL)
 			goto out_delete;
 
@@ -780,13 +784,15 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
  * The ops.raw part will be parsed further according to type of the instruction.
  */
 static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
-				      FILE *file, size_t privsize)
+				      FILE *file, size_t privsize,
+				      int *line_nr)
 {
 	struct annotation *notes = symbol__annotation(sym);
 	struct disasm_line *dl;
 	char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
 	size_t line_len;
 	s64 line_ip, offset = -1;
+	regmatch_t match[2];
 
 	if (getline(&line, &line_len, file) < 0)
 		return -1;
@@ -804,6 +810,12 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
 	line_ip = -1;
 	parsed_line = line;
 
+	/* /filename:linenr ? Save line number and ignore. */
+	if (regexec(&file_lineno, line, 2, match, 0) == 0) {
+		*line_nr = atoi(line + match[1].rm_so);
+		return 0;
+	}
+
 	/*
 	 * Strip leading spaces:
 	 */
@@ -834,8 +846,9 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
 			parsed_line = tmp2 + 1;
 	}
 
-	dl = disasm_line__new(offset, parsed_line, privsize);
+	dl = disasm_line__new(offset, parsed_line, privsize, *line_nr);
 	free(line);
+	(*line_nr)++;
 
 	if (dl == NULL)
 		return -1;
@@ -861,6 +874,11 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
 	return 0;
 }
 
+static __attribute__((constructor)) void symbol__init_regexpr(void)
+{
+	regcomp(&file_lineno, "^/[^:]+:([0-9]+)$", REG_EXTENDED);
+}
+
 static void delete_last_nop(struct symbol *sym)
 {
 	struct annotation *notes = symbol__annotation(sym);
@@ -896,6 +914,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
 	char symfs_filename[PATH_MAX];
 	struct kcore_extract kce;
 	bool delete_extract = false;
+	int lineno = 0;
 
 	if (filename) {
 		snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
@@ -977,7 +996,7 @@ fallback:
 	snprintf(command, sizeof(command),
 		 "%s %s%s --start-address=0x%016" PRIx64
 		 " --stop-address=0x%016" PRIx64
-		 " -d %s %s -C %s 2>/dev/null|grep -v %s|expand",
+		 " -l -d %s %s -C %s 2>/dev/null|grep -v %s|expand",
 		 objdump_path ? objdump_path : "objdump",
 		 disassembler_style ? "-M " : "",
 		 disassembler_style ? disassembler_style : "",
@@ -994,7 +1013,8 @@ fallback:
 		goto out_free_filename;
 
 	while (!feof(file))
-		if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
+		if (symbol__parse_objdump_line(sym, map, file, privsize,
+			    &lineno) < 0)
 			break;
 
 	/*
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index b2aef59..a124e7e 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -58,6 +58,7 @@ struct disasm_line {
 	char		    *line;
 	char		    *name;
 	struct ins	    *ins;
+	int		    line_nr;
 	struct ins_operands ops;
 };
 
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: Implement lbr-as-callgraph v3
  2014-01-14  1:04 Implement lbr-as-callgraph v3 Andi Kleen
                   ` (5 preceding siblings ...)
  2014-01-14  1:04 ` [PATCH 6/6] perf, tools: Support source line numbers in annotate Andi Kleen
@ 2014-01-15 13:59 ` Jiri Olsa
  6 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2014-01-15 13:59 UTC (permalink / raw)
  To: Andi Kleen
  Cc: acme, namhyung, mingo, dsahern, fweisbec, adrian.hunter, linux-kernel

On Mon, Jan 13, 2014 at 05:04:15PM -0800, Andi Kleen wrote:
> This patchkit implements lbr-as-callgraphs in per freport,
> as an alternative way to present LBR information.
> 
> Current perf report does a histogram over the branch edges,
> which is useful to look at basic blocks, but doesn't tell
> you anything about the larger control flow behaviour.
> 
> This patchkit adds a new option --branch-history that
> adds the branch paths to the callgraph history instead.
> 
> This allows to reason about individual branch paths leading
> to specific samples.
> 
> Updates to v1:
> - rebased on perf/core
> - fix various issues
> - rename the option to --branch-history
> - various fixes to display the information more concise
> 
> Updates to v3:
> - White space changes
> - Consolidate some patches
> - Update some descriptions
> 
> Example output:
> 
>     % perf record -b -g ./tsrc/tcall
>     [ perf record: Woken up 1 times to write data ]
>     [ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
>     % perf report --branch-history
>     ...
>         54.91%  tcall.c:6  [.] f2                      tcall
>                 |
>                 |--65.53%-- f2 tcall.c:5
>                 |          |
>                 |          |--70.83%-- f1 tcall.c:11
>                 |          |          f1 tcall.c:10
>                 |          |          main tcall.c:18
>                 |          |          main tcall.c:18
>                 |          |          main tcall.c:17
>                 |          |          main tcall.c:17
>                 |          |          f1 tcall.c:13
>                 |          |          f1 tcall.c:13
>                 |          |          f2 tcall.c:7
>                 |          |          f2 tcall.c:5
>                 |          |          f1 tcall.c:12
>                 |          |          f1 tcall.c:12
>                 |          |          f2 tcall.c:7
>                 |          |          f2 tcall.c:5
>                 |          |          f1 tcall.c:11
> 
> 

the tui output needs some cleanup:

+  26.38%  :0  [.] _IO_file_xsputn@@GLIBC_2.2.5    libc-2.17.so                                                                           ◆
+  20.43%  :0  [.] __strlen_sse2                   libc-2.17.so                                                                           ▒
+  15.94%  yes.c:83  [.] main                            yes                                                                              ▒
+  12.16%  :0  [.] fputs_unlocked                  libc-2.17.so                                                                           ▒
+  10.27%  stdio.h:107  [.] main                            yes                                                                           ▒
+  10.09%  :0  [.] __GI___mempcpy                  libc-2.17.so                                                                           ▒
+   2.63%  yes.c:84  [.] main                            yes                                                                              ▒
+   1.71%  yes[4012f0]  [.] fputs_unlocked@plt              yes                                                                           ▒
+   0.25%  yes.c:85  [.] main                            yes                                                                              ▒
+   0.03%  [kernel.kallsyms][ffffffff81757eb0]  [k] system_call                     [kernel.kallsyms]                                     ▒
+   0.02%  :0  [.] _IO_file_write@@GLIBC_2.2.5     libc-2.17.so                                                                           ▒
+   0.02%  :0  [.] _IO_do_write@@GLIBC_2.2.5       libc-2.17.so                                                                           ▒
+   0.02%  [kernel.kallsyms][ffffffff81758b40]  [k] apic_timer_interrupt            [kernel.kallsyms]                                     ▒
+   0.02%  :0  [.] _IO_default_xsputn              libc-2.17.so                                                                           ▒
+   0.01%  :0  [.] _IO_file_overflow@@GLIBC_2.2.5  libc-2.17.so                                                                           ▒
+   0.01%  :0  [.] __GI___libc_write               libc-2.17.so                                                                           ▒
+   0.00%  [kernel.kallsyms][ffffffff8174f020]  [k] page_fault                      [kernel.kallsyms]                                     ▒
+   0.00%  :0  [.] getenv                          libc-2.17.so                                                                           ▒
+   0.00%  :0  [.] _nl_load_locale_from_archive    libc-2.17.so                                                                           ▒
+   0.00%  ld-2.17.so[3407c0af52]  [.] _dl_setup_hash                  ld-2.17.so                                                         ▒
+   0.00%  ld-2.17.so[3407c01420]  [.] _start                          ld-2.17.so                      


when we cannot get source and line number we could output address not ':0':

-   2.63%  yes.c:84  [.] main                            yes                                                                              ▒
   - main stdio.h:107                                                                                                                     ▒
   - main yes.c:84                                                                                                                        ▒
   - main yes.c:84                                                                                                                        ▒
   - fputs_unlocked :0                                                                                                                    ▒
   - fputs_unlocked :0                                                                                                                    ▒
   - _IO_file_xsputn@@GLIBC_2.2.5 :0                                                                                                      ▒
      - 99.78% _IO_file_xsputn@@GLIBC_2.2.5 :0                                                                                            ▒
           __GI___mempcpy :0                                                                                                              ▒
           __GI___mempcpy :0                                                                                                              ▒
           __GI___mempcpy :0                                                                                                              ▒
           __GI___mempcpy :0                                         


at some samples I could not get see  source/address info, just:

     0.03%  [kernel.kallsyms][ffffffff810a7b4f]  [k] __srcu_read_lock                [kernel.kallsyms]
            |
            --- __srcu_read_lock
                fsnotify
                fsnotify
                fsnotify
                fsnotify
                fsnotify
                fsnotify
                fsnotify
                fsnotify

going to check the patches now ;-)

jirka

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] perf, tools: Add --branch-history option to report v2
  2014-01-14  1:04 ` [PATCH 3/6] perf, tools: Add --branch-history option to report v2 Andi Kleen
@ 2014-01-15 14:44   ` Jiri Olsa
  2014-01-15 15:23     ` Andi Kleen
  0 siblings, 1 reply; 16+ messages in thread
From: Jiri Olsa @ 2014-01-15 14:44 UTC (permalink / raw)
  To: Andi Kleen
  Cc: acme, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

On Mon, Jan 13, 2014 at 05:04:18PM -0800, Andi Kleen wrote:
> From: Andi Kleen <ak@linux.intel.com>
> 
> Add a --branch-history option to perf report that changes all
> the settings necessary for using the branches in callstacks.
> 
> This is just a short cut to make this nicer to use, it does
> not enable any functionality by itself.
> 
> v2: Change sort order. Rename option to --branch-history to
> be less confusing.
> Signed-off-by: Andi Kleen <ak@linux.intel.com>
> ---

SNIP

> @@ -729,7 +739,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
>  	struct perf_session *session;
>  	struct stat st;
>  	bool has_br_stack = false;
> -	int branch_mode = -1;
> +	int branch_mode = -1, branch_call_mode = -1;
>  	int ret = -1;
>  	char callchain_default_opt[] = "fractal,0.5,callee";
>  	const char * const report_usage[] = {
> @@ -838,7 +848,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
>  	OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
>  		    "Show event group information together"),
>  	OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
> -		    "use branch records for histogram filling", parse_branch_mode),
> +		    "use branch records for per branch histogram filling", parse_branch_mode),
> +	OPT_CALLBACK_NOOPT(0, "branch-history", &branch_call_mode, "",
> +		    "add last branch records to call history",
> +		    parse_branch_call_mode),
>  	OPT_STRING(0, "objdump", &objdump_path, "path",
>  		   "objdump binary to use for disassembly and annotations"),
>  	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
> @@ -886,8 +899,16 @@ repeat:
>  	has_br_stack = perf_header__has_feat(&session->header,
>  					     HEADER_BRANCH_STACK);
>  
> -	if (branch_mode == -1 && has_br_stack)
> +	if (branch_mode == -1 && has_br_stack && branch_call_mode == -1)
>  		sort__mode = SORT_MODE__BRANCH;
> +	if (branch_call_mode != -1) {
> +		callchain_param.branch_callstack = 1;
> +		callchain_param.key = CCKEY_ADDRESS;
> +		symbol_conf.use_callchain = true;
> +		callchain_register_param(&callchain_param);
> +		if (sort_order == default_sort_order)
> +			sort_order = "srcline,symbol,dso";
> +	}

this sort of settings needs to be in for the previous patch,
to make the following command work:

  $ perf report --call-graph=fractal,0.5,callee,function,branch

will just set symbol_conf.use_callchain, but the sorting stays
as SORT_MODE__BRANCH.. and callchains are invisible

as you said in the changelog, this should be 'short cut to make this nicer to use',
but it's actually currently the only way..

jirka

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/6] perf, tools: Support handling complete branch stacks as histograms v3
  2014-01-14  1:04 ` [PATCH 2/6] perf, tools: Support handling complete branch stacks as histograms v3 Andi Kleen
@ 2014-01-15 14:48   ` Jiri Olsa
  2014-01-15 15:27     ` Andi Kleen
  2014-01-15 15:00   ` Jiri Olsa
  1 sibling, 1 reply; 16+ messages in thread
From: Jiri Olsa @ 2014-01-15 14:48 UTC (permalink / raw)
  To: Andi Kleen
  Cc: acme, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

On Mon, Jan 13, 2014 at 05:04:17PM -0800, Andi Kleen wrote:
> From: Andi Kleen <ak@linux.intel.com>
> 
> Currently branch stacks can be only shown as edge histograms for
> individual branches. I never found this display particularly useful.
> 
> This implements an alternative mode that creates histograms over complete
> branch traces, instead of individual branches, similar to how normal
> callgraphs are handled. This is done by putting it in
> front of the normal callgraph and then using the normal callgraph
> histogram infrastructure to unify them.
> 
> This way in complex functions we can understand the control flow
> that lead to a particular sample, and may even see some control
> flow in the caller for short functions.
> 
> Example (simplified, of course for such simple code this
> is usually not needed):
> 
> tcall.c:
> 
> volatile a = 10000, b = 100000, c;
> 
> __attribute__((noinline)) f2()
> {
> 	c = a / b;
> }
> 
> __attribute__((noinline)) f1()
> {
> 	f2();
> 	f2();
> }
> main()
> {
> 	int i;
> 	for (i = 0; i < 1000000; i++)
> 		f1();
> }
> 
> % perf record -b -g ./tsrc/tcall
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.044 MB perf.data (~1923 samples) ]
> % perf report --branch-history

this option is not added in this patch, I tried:
  $ perf report --call-graph=fractal,0.5,callee,function,branch

but as I already said in reply for patch 3, it's not working
please update the doc in Documentation/perf-report.txt with an example

jirka

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/6] perf, tools: Support handling complete branch stacks as histograms v3
  2014-01-14  1:04 ` [PATCH 2/6] perf, tools: Support handling complete branch stacks as histograms v3 Andi Kleen
  2014-01-15 14:48   ` Jiri Olsa
@ 2014-01-15 15:00   ` Jiri Olsa
  1 sibling, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2014-01-15 15:00 UTC (permalink / raw)
  To: Andi Kleen
  Cc: acme, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

On Mon, Jan 13, 2014 at 05:04:17PM -0800, Andi Kleen wrote:
> From: Andi Kleen <ak@linux.intel.com>

SNIP

>  
>  int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
>  {
> @@ -1248,9 +1249,98 @@ struct branch_info *machine__resolve_bstack(struct machine *machine,
>  	return bi;
>  }
>  
> +static int add_callchain_ip(struct machine *machine,
> +			    struct thread *thread,
> +			    struct symbol **parent,
> +			    struct addr_location *root_al,
> +			    int cpumode,
> +			    u64 ip)
> +{
> +	struct addr_location al;
> +
> +	al.filtered = false;
> +	al.sym = NULL;
> +	if (cpumode == -1) {
> +		int i;
> +
> +		for (i = 0; i < (int)NCPUMODES && !al.sym; i++) {
> +			/*
> +			 * We cannot use the header.misc hint to determine whether a
> +			 * branch stack address is user, kernel, guest, hypervisor.
> +			 * Branches may straddle the kernel/user/hypervisor boundaries.
> +			 * Thus, we have to try consecutively until we find a match
> +			 * or else, the symbol is unknown
> +			 */
> +			thread__find_addr_location(thread, machine, cpumodes[i],
> +					MAP__FUNCTION,
> +					ip, &al);
> +		}

above code is already in ip__resolve_ams, maybe we could add put this
into separate function like 'thread__find_addr_location_cpumodes'

jirka

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 4/6] perf, tools: Enable printing the srcline in the history
  2014-01-14  1:04 ` [PATCH 4/6] perf, tools: Enable printing the srcline in the history Andi Kleen
@ 2014-01-15 15:12   ` Jiri Olsa
  0 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2014-01-15 15:12 UTC (permalink / raw)
  To: Andi Kleen
  Cc: acme, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

On Mon, Jan 13, 2014 at 05:04:19PM -0800, Andi Kleen wrote:
> From: Andi Kleen <ak@linux.intel.com>
> 
> For lbr-as-callgraph we need to see the line number in the history,
> because many LBR entries can be in a single function, and just
> showing the same function name many times is not useful.
> 
> When the history code is configured to sort by address, also try to
> resolve the address to a file:srcline and display this in the browser.
> If that doesn't work still display the address.
> 
> This can be also useful without LBRs for understanding which call in a large
> function (or in which inlined function) called something else.
> 
> Contains fixes from Namhyung Kim
> 
> Signed-off-by: Andi Kleen <ak@linux.intel.com>
> ---
>  tools/perf/ui/browsers/hists.c | 15 ++++++++++++---
>  tools/perf/ui/stdio/hist.c     | 16 +++++++++++++---
>  tools/perf/util/callchain.h    |  1 +
>  tools/perf/util/machine.c      |  2 +-
>  tools/perf/util/srcline.c      |  6 ++++--
>  5 files changed, 31 insertions(+), 9 deletions(-)
> 
> diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
> index b720b92..060fffc 100644
> --- a/tools/perf/ui/browsers/hists.c
> +++ b/tools/perf/ui/browsers/hists.c
> @@ -399,9 +399,18 @@ static char *callchain_list__sym_name(struct callchain_list *cl,
>  {
>  	int printed;
>  
> -	if (cl->ms.sym)
> -		printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
> -	else
> +	if (cl->ms.sym) {
> +		if (callchain_param.key == CCKEY_ADDRESS &&
> +		    cl->ms.map && !cl->srcline)
> +			cl->srcline = get_srcline(cl->ms.map->dso,
> +						  map__rip_2objdump(cl->ms.map,
> +								    cl->ip));
> +		if (cl->srcline)
> +			printed = scnprintf(bf, bfsize, "%s %s",
> +					cl->ms.sym->name, cl->srcline);
> +		else
> +			printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
> +	} else
>  		printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);

above function 'callchain_list__sym_name' could be exported

>  
>  	if (show_dso)
> diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
> index 831fbb7..a494eed 100644
> --- a/tools/perf/ui/stdio/hist.c
> +++ b/tools/perf/ui/stdio/hist.c
> @@ -56,9 +56,19 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
>  		} else
>  			ret += fprintf(fp, "%s", "          ");
>  	}
> -	if (chain->ms.sym)
> -		ret += fprintf(fp, "%s\n", chain->ms.sym->name);
> -	else
> +	if (chain->ms.sym) {
> +		if (callchain_param.key == CCKEY_ADDRESS &&
> +		    chain->ms.map)
> +			chain->srcline = get_srcline(chain->ms.map->dso,
> +						  map__rip_2objdump(
> +							  chain->ms.map,
> +							  chain->ip));
> +		if (chain->srcline)
> +			ret += fprintf(fp, "%s %s\n",
> +				       chain->ms.sym->name, chain->srcline);
> +		else
> +			ret += fprintf(fp, "%s\n", chain->ms.sym->name);
> +	} else
>  		ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);

and this place could call it

jirka

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] perf, tools: Add --branch-history option to report v2
  2014-01-15 14:44   ` Jiri Olsa
@ 2014-01-15 15:23     ` Andi Kleen
  2014-01-15 15:42       ` Jiri Olsa
  0 siblings, 1 reply; 16+ messages in thread
From: Andi Kleen @ 2014-01-15 15:23 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Andi Kleen, acme, namhyung, mingo, dsahern, fweisbec,
	adrian.hunter, linux-kernel, Andi Kleen

> this sort of settings needs to be in for the previous patch,
> to make the following command work:
> 
>   $ perf report --call-graph=fractal,0.5,callee,function,branch
> 
> will just set symbol_conf.use_callchain, but the sorting stays
> as SORT_MODE__BRANCH.. and callchains are invisible

You can use --no-branch-stack

> as you said in the changelog, this should be 'short cut to make this nicer to use',
> but it's actually currently the only way..

It works, it's just very long and cumbersome.

-Andi

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/6] perf, tools: Support handling complete branch stacks as histograms v3
  2014-01-15 14:48   ` Jiri Olsa
@ 2014-01-15 15:27     ` Andi Kleen
  2014-01-15 15:45       ` Jiri Olsa
  0 siblings, 1 reply; 16+ messages in thread
From: Andi Kleen @ 2014-01-15 15:27 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Andi Kleen, acme, namhyung, mingo, dsahern, fweisbec,
	adrian.hunter, linux-kernel, Andi Kleen

> this option is not added in this patch, I tried:
>   $ perf report --call-graph=fractal,0.5,callee,function,branch

Of course not, it's in the next patch.

But I was not putting the cumbersome long command line into this
example.

If you really feel strongly about it I guess the two patches could be merged,
but seems cleaner separated.

> 
> but as I already said in reply for patch 3, it's not working
> please update the doc in Documentation/perf-report.txt with an example

What kind of example? Full output for a command?

I don't think any other option has that in the man page. It would be
unique.

Having a illustrated `perf tutorial' with examples would probably be a 
good idea, but I'm not sure the man page is the right place for that.

-Andi


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/6] perf, tools: Add --branch-history option to report v2
  2014-01-15 15:23     ` Andi Kleen
@ 2014-01-15 15:42       ` Jiri Olsa
  0 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2014-01-15 15:42 UTC (permalink / raw)
  To: Andi Kleen
  Cc: acme, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

On Wed, Jan 15, 2014 at 04:23:44PM +0100, Andi Kleen wrote:
> > this sort of settings needs to be in for the previous patch,
> > to make the following command work:
> > 
> >   $ perf report --call-graph=fractal,0.5,callee,function,branch
> > 
> > will just set symbol_conf.use_callchain, but the sorting stays
> > as SORT_MODE__BRANCH.. and callchains are invisible
> 
> You can use --no-branch-stack

that works.. w/o srcline

> 
> > as you said in the changelog, this should be 'short cut to make this nicer to use',
> > but it's actually currently the only way..
> 
> It works, it's just very long and cumbersome.

well I'd like to see it anyway.. wouldn't need to figure out
it by looking to the code

and the example could be in the next patch then,
it's misleading to reference non existing option

jirka

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/6] perf, tools: Support handling complete branch stacks as histograms v3
  2014-01-15 15:27     ` Andi Kleen
@ 2014-01-15 15:45       ` Jiri Olsa
  0 siblings, 0 replies; 16+ messages in thread
From: Jiri Olsa @ 2014-01-15 15:45 UTC (permalink / raw)
  To: Andi Kleen
  Cc: acme, namhyung, mingo, dsahern, fweisbec, adrian.hunter,
	linux-kernel, Andi Kleen

On Wed, Jan 15, 2014 at 04:27:29PM +0100, Andi Kleen wrote:
> > this option is not added in this patch, I tried:
> >   $ perf report --call-graph=fractal,0.5,callee,function,branch
> 
> Of course not, it's in the next patch.
> 
> But I was not putting the cumbersome long command line into this
> example.
> 
> If you really feel strongly about it I guess the two patches could be merged,
> but seems cleaner separated.
> 
> > 
> > but as I already said in reply for patch 3, it's not working
> > please update the doc in Documentation/perf-report.txt with an example
> 
> What kind of example? Full output for a command?
> 
> I don't think any other option has that in the man page. It would be
> unique.
> 
> Having a illustrated `perf tutorial' with examples would probably be a 
> good idea, but I'm not sure the man page is the right place for that.
> 

yea.. example would be too much ;-) but at least all available options
are mentioned in '--call-graph::' section in Documentation/perf-report.txt
and 'branch' is missing

jirka

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2014-01-15 15:45 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-14  1:04 Implement lbr-as-callgraph v3 Andi Kleen
2014-01-14  1:04 ` [PATCH 1/6] perf, tools: fix BFD detection on opensuse Andi Kleen
2014-01-14  1:04 ` [PATCH 2/6] perf, tools: Support handling complete branch stacks as histograms v3 Andi Kleen
2014-01-15 14:48   ` Jiri Olsa
2014-01-15 15:27     ` Andi Kleen
2014-01-15 15:45       ` Jiri Olsa
2014-01-15 15:00   ` Jiri Olsa
2014-01-14  1:04 ` [PATCH 3/6] perf, tools: Add --branch-history option to report v2 Andi Kleen
2014-01-15 14:44   ` Jiri Olsa
2014-01-15 15:23     ` Andi Kleen
2014-01-15 15:42       ` Jiri Olsa
2014-01-14  1:04 ` [PATCH 4/6] perf, tools: Enable printing the srcline in the history Andi Kleen
2014-01-15 15:12   ` Jiri Olsa
2014-01-14  1:04 ` [PATCH 5/6] perf, tools: Only print base source file for srcline Andi Kleen
2014-01-14  1:04 ` [PATCH 6/6] perf, tools: Support source line numbers in annotate Andi Kleen
2014-01-15 13:59 ` Implement lbr-as-callgraph v3 Jiri Olsa

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).