From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Ingo Molnar <mingo@kernel.org>
Cc: linux-kernel@vger.kernel.org,
Milian Wolff <milian.wolff@kdab.com>,
Jiri Olsa <jolsa@kernel.org>, Yao Jin <yao.jin@linux.intel.com>,
Arnaldo Carvalho de Melo <acme@redhat.com>
Subject: [PATCH 12/20] perf report: Enable sorting by srcline as key
Date: Mon, 27 Mar 2017 22:39:07 -0300 [thread overview]
Message-ID: <20170328013915.15236-13-acme@kernel.org> (raw)
In-Reply-To: <20170328013915.15236-1-acme@kernel.org>
From: Milian Wolff <milian.wolff@kdab.com>
Often it is interesting to know how costly a given source line is in
total. Previously, one had to build these sums manually based on all
addresses that pointed to the same source line. This patch introduces
srcline as a sort key, which will do the aggregation for us.
Paired with the recent addition of showing inline frames, this makes
perf report much more useful for many C++ work loads.
The following shows the new feature in action. First, let's show the
status quo output when we sort by address. The result contains many hist
entries that generate the same output:
~~~~~~~~~~~~~~~~
$ perf report --stdio --inline -g address
# Children Self Command Shared Object Symbol
# ........ ........ ............ ................... .........................................
#
99.89% 35.34% cpp-inlining cpp-inlining [.] main
|
|--64.55%--main complex:655
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/complex:664 (inline)
| |
| |--60.31%--hypot +20
| | |
| | |--8.52%--__hypot_finite +273
| | |
| | |--7.32%--__hypot_finite +411
...
--35.34%--_start +4194346
__libc_start_main +241
|
|--6.65%--main random.tcc:3326
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1809 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1818 (inline)
| /usr/include/c++/6.3.1/bits/random.h:185 (inline)
|
|--2.70%--main random.tcc:3326
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1809 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1818 (inline)
| /usr/include/c++/6.3.1/bits/random.h:185 (inline)
|
|--1.69%--main random.tcc:3326
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1809 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1818 (inline)
| /usr/include/c++/6.3.1/bits/random.h:185 (inline)
...
~~~~~~~~~~~~~~~~
With this patch and `-g srcline` we instead get the following output:
~~~~~~~~~~~~~~~~
$ perf report --stdio --inline -g srcline
# Children Self Command Shared Object Symbol
# ........ ........ ............ ................... .........................................
#
99.89% 35.34% cpp-inlining cpp-inlining [.] main
|
|--64.55%--main complex:655
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/complex:664 (inline)
| |
| |--64.02%--hypot
| | |
| | --59.81%--__hypot_finite
| |
| --0.53%--cabs
|
--35.34%--_start
__libc_start_main
|
|--12.48%--main random.tcc:3326
| /home/milian/projects/kdab/rnd/hotspot/tests/test-clients/cpp-inlining/main.cpp:39 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1809 (inline)
| /usr/include/c++/6.3.1/bits/random.h:1818 (inline)
| /usr/include/c++/6.3.1/bits/random.h:185 (inline)
...
~~~~~~~~~~~~~~~~
Signed-off-by: Milian Wolff <milian.wolff@kdab.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Yao Jin <yao.jin@linux.intel.com>
Link: http://lkml.kernel.org/r/20170318214928.9047-1-milian.wolff@kdab.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/Documentation/perf-report.txt | 1 +
tools/perf/ui/browsers/hists.c | 3 +-
tools/perf/ui/stdio/hist.c | 3 +-
tools/perf/util/annotate.c | 3 +-
tools/perf/util/callchain.c | 52 +++++++++++++++++++++++++++++---
tools/perf/util/callchain.h | 3 +-
tools/perf/util/map.c | 3 +-
tools/perf/util/sort.c | 16 ++++++----
tools/perf/util/srcline.c | 11 +++++--
tools/perf/util/util.h | 4 +--
10 files changed, 78 insertions(+), 21 deletions(-)
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 248bba434b53..37a175914157 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -235,6 +235,7 @@ OPTIONS
sort_key can be:
- function: compare on functions (default)
- address: compare on individual code addresses
+ - srcline: compare on source filename and line number
branch can be:
- branch: include last branch information in callgraph when available.
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 62ecaebf2520..da24072bb76e 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -851,7 +851,8 @@ static int hist_browser__show_inline(struct hist_browser *browser,
if (ui_browser__is_current_entry(&browser->b, row))
color = HE_COLORSET_SELECTED;
- if (callchain_param.key == CCKEY_ADDRESS) {
+ if (callchain_param.key == CCKEY_ADDRESS ||
+ callchain_param.key == CCKEY_SRCLINE) {
if (ilist->filename != NULL)
scnprintf(buf, sizeof(buf),
"%s:%d (inline)",
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 6128f485a3c5..d52d5f64ea89 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -52,7 +52,8 @@ static size_t inline__fprintf(struct map *map, u64 ip, int left_margin,
ret += fprintf(fp, " ");
}
- if (callchain_param.key == CCKEY_ADDRESS) {
+ if (callchain_param.key == CCKEY_ADDRESS ||
+ callchain_param.key == CCKEY_SRCLINE) {
if (ilist->filename != NULL)
ret += fprintf(fp, "%s:%d (inline)",
ilist->filename,
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 22cd1dbe724b..3d0263e5d1db 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1674,7 +1674,8 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
goto next;
offset = start + i;
- src_line->path = get_srcline(map->dso, offset, NULL, false);
+ src_line->path = get_srcline(map->dso, offset, NULL,
+ false, true);
insert_source_line(&tmp_root, src_line);
next:
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index aba953421a03..d78776a20e80 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -80,6 +80,10 @@ static int parse_callchain_sort_key(const char *value)
callchain_param.key = CCKEY_ADDRESS;
return 0;
}
+ if (!strncmp(value, "srcline", strlen(value))) {
+ callchain_param.key = CCKEY_SRCLINE;
+ return 0;
+ }
if (!strncmp(value, "branch", strlen(value))) {
callchain_param.branch_callstack = 1;
return 0;
@@ -510,14 +514,51 @@ enum match_result {
MATCH_GT,
};
+static enum match_result match_chain_srcline(struct callchain_cursor_node *node,
+ struct callchain_list *cnode)
+{
+ char *left = get_srcline(cnode->ms.map->dso,
+ map__rip_2objdump(cnode->ms.map, cnode->ip),
+ cnode->ms.sym, true, false);
+ char *right = get_srcline(node->map->dso,
+ map__rip_2objdump(node->map, node->ip),
+ node->sym, true, false);
+ enum match_result ret = MATCH_EQ;
+ int cmp;
+
+ if (left && right)
+ cmp = strcmp(left, right);
+ else if (!left && right)
+ cmp = 1;
+ else if (left && !right)
+ cmp = -1;
+ else if (cnode->ip == node->ip)
+ cmp = 0;
+ else
+ cmp = (cnode->ip < node->ip) ? -1 : 1;
+
+ if (cmp != 0)
+ ret = cmp < 0 ? MATCH_LT : MATCH_GT;
+
+ free_srcline(left);
+ free_srcline(right);
+ return ret;
+}
+
static enum match_result match_chain(struct callchain_cursor_node *node,
struct callchain_list *cnode)
{
struct symbol *sym = node->sym;
u64 left, right;
- if (cnode->ms.sym && sym &&
- callchain_param.key == CCKEY_FUNCTION) {
+ if (callchain_param.key == CCKEY_SRCLINE) {
+ enum match_result match = match_chain_srcline(node, cnode);
+
+ if (match != MATCH_ERROR)
+ return match;
+ }
+
+ if (cnode->ms.sym && sym && callchain_param.key == CCKEY_FUNCTION) {
left = cnode->ms.sym->start;
right = sym->start;
} else {
@@ -911,15 +952,16 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
char *callchain_list__sym_name(struct callchain_list *cl,
char *bf, size_t bfsize, bool show_dso)
{
+ bool show_addr = callchain_param.key == CCKEY_ADDRESS;
+ bool show_srcline = show_addr || callchain_param.key == CCKEY_SRCLINE;
int printed;
if (cl->ms.sym) {
- if (callchain_param.key == CCKEY_ADDRESS &&
- cl->ms.map && !cl->srcline)
+ if (show_srcline && cl->ms.map && !cl->srcline)
cl->srcline = get_srcline(cl->ms.map->dso,
map__rip_2objdump(cl->ms.map,
cl->ip),
- cl->ms.sym, false);
+ cl->ms.sym, false, show_addr);
if (cl->srcline)
printed = scnprintf(bf, bfsize, "%s %s",
cl->ms.sym->name, cl->srcline);
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 4f4b60f1558a..c56c23dbbf72 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -77,7 +77,8 @@ typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
enum chain_key {
CCKEY_FUNCTION,
- CCKEY_ADDRESS
+ CCKEY_ADDRESS,
+ CCKEY_SRCLINE
};
enum chain_value {
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 1d9ebcf9e38e..c1870ac365a3 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -405,7 +405,8 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
if (map && map->dso) {
srcline = get_srcline(map->dso,
- map__rip_2objdump(map, addr), NULL, true);
+ map__rip_2objdump(map, addr), NULL,
+ true, true);
if (srcline != SRCLINE_UNKNOWN)
ret = fprintf(fp, "%s%s", prefix, srcline);
free_srcline(srcline);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 8b0d4e39f640..73f3ec1cf2a0 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -323,7 +323,7 @@ char *hist_entry__get_srcline(struct hist_entry *he)
return SRCLINE_UNKNOWN;
return get_srcline(map->dso, map__rip_2objdump(map, he->ip),
- he->ms.sym, true);
+ he->ms.sym, true, true);
}
static int64_t
@@ -366,7 +366,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
left->branch_info->srcline_from = get_srcline(map->dso,
map__rip_2objdump(map,
left->branch_info->from.al_addr),
- left->branch_info->from.sym, true);
+ left->branch_info->from.sym,
+ true, true);
}
if (!right->branch_info->srcline_from) {
struct map *map = right->branch_info->from.map;
@@ -376,7 +377,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
right->branch_info->srcline_from = get_srcline(map->dso,
map__rip_2objdump(map,
right->branch_info->from.al_addr),
- right->branch_info->from.sym, true);
+ right->branch_info->from.sym,
+ true, true);
}
return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from);
}
@@ -407,7 +409,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
left->branch_info->srcline_to = get_srcline(map->dso,
map__rip_2objdump(map,
left->branch_info->to.al_addr),
- left->branch_info->from.sym, true);
+ left->branch_info->from.sym,
+ true, true);
}
if (!right->branch_info->srcline_to) {
struct map *map = right->branch_info->to.map;
@@ -417,7 +420,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
right->branch_info->srcline_to = get_srcline(map->dso,
map__rip_2objdump(map,
right->branch_info->to.al_addr),
- right->branch_info->to.sym, true);
+ right->branch_info->to.sym,
+ true, true);
}
return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to);
}
@@ -448,7 +452,7 @@ static char *hist_entry__get_srcfile(struct hist_entry *e)
return no_srcfile;
sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
- e->ms.sym, false, true);
+ e->ms.sym, false, true, true);
if (!strcmp(sf, SRCLINE_UNKNOWN))
return no_srcfile;
p = strchr(sf, ':');
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 3ce28f702b36..778ccb5d99d1 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -429,7 +429,7 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
#define A2L_FAIL_LIMIT 123
char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
- bool show_sym, bool unwind_inlines)
+ bool show_sym, bool show_addr, bool unwind_inlines)
{
char *file = NULL;
unsigned line = 0;
@@ -463,6 +463,11 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
dso->has_srcline = 0;
dso__free_a2l(dso);
}
+
+ if (!show_addr)
+ return (show_sym && sym) ?
+ strndup(sym->name, sym->namelen) : NULL;
+
if (sym) {
if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
addr - sym->start) < 0)
@@ -479,9 +484,9 @@ void free_srcline(char *srcline)
}
char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
- bool show_sym)
+ bool show_sym, bool show_addr)
{
- return __get_srcline(dso, addr, sym, show_sym, false);
+ return __get_srcline(dso, addr, sym, show_sym, show_addr, false);
}
struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr)
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index cc0700d6fef0..7cf5752b38fd 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -287,9 +287,9 @@ struct symbol;
extern bool srcline_full_filename;
char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
- bool show_sym);
+ bool show_sym, bool show_addr);
char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
- bool show_sym, bool unwind_inlines);
+ bool show_sym, bool show_addr, bool unwind_inlines);
void free_srcline(char *srcline);
int perf_event_paranoid(void);
--
2.9.3
next prev parent reply other threads:[~2017-03-28 1:44 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-03-28 1:38 [GIT PULL 00/20] perf/core improvements and fixes Arnaldo Carvalho de Melo
2017-03-28 1:38 ` [PATCH 01/20] perf trace: Check for vfs_getname.pathname length Arnaldo Carvalho de Melo
2017-03-28 1:38 ` [PATCH 02/20] perf trace: Fix up error path indentation Arnaldo Carvalho de Melo
2017-03-28 1:38 ` [PATCH 03/20] perf trace: Fixup thread refcounting Arnaldo Carvalho de Melo
2017-03-28 1:38 ` [PATCH 04/20] perf auxtrace: Fix no_size logic in addr_filter__resolve_kernel_syms() Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 05/20] perf list sdt: Show option in man page Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 06/20] perf tools: Remove unused 'prefix' from builtin functions Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 07/20] perf report: Refactor common code in srcline.c Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 08/20] perf report: Find the inline stack for a given address Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 09/20] perf report: Introduce --inline option Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 10/20] perf report: Show inline stack for stdio mode Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 11/20] perf report: Show inline stack for browser mode Arnaldo Carvalho de Melo
2017-03-28 1:39 ` Arnaldo Carvalho de Melo [this message]
2017-03-28 1:39 ` [PATCH 13/20] perf annotate: Fix a bug following symbolic link of a build-id file Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 14/20] perf annotate: Fix a bug of division by zero when calculating percent Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 15/20] perf buildid: Do not update SDT cache with null filename Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 16/20] perf buildid: Do not assume that readlink() returns a null terminated string Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 17/20] perf tests: " Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 18/20] perf utils: use sizeof(buf) - 1 in readlink() call Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 19/20] perf utils: Null terminate buf in read_ftrace_printk() Arnaldo Carvalho de Melo
2017-03-28 1:39 ` [PATCH 20/20] perf utils: Readlink /proc/self/exe to find the perf binary Arnaldo Carvalho de Melo
2017-03-28 5:45 ` [GIT PULL 00/20] perf/core improvements and fixes Ingo Molnar
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=20170328013915.15236-13-acme@kernel.org \
--to=acme@kernel.org \
--cc=acme@redhat.com \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=milian.wolff@kdab.com \
--cc=mingo@kernel.org \
--cc=yao.jin@linux.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).