[RESEND PATCH v2 5/5] perf report: Show inline stack in browser mode

From: Jin Yao
Date: Wed Dec 07 2016 - 01:46:15 EST


For example:

- 0.05% test2 test2 [.] main
/home/jinyao/perf-dev/test/test2.c:27 (inline)
/home/jinyao/perf-dev/test/test2.c:35 (inline)
/home/jinyao/perf-dev/test/test2.c:45 (inline)
/home/jinyao/perf-dev/test/test2.c:61 (inline)

Signed-off-by: Jin Yao <yao.jin@xxxxxxxxxxxxxxx>
---
tools/perf/ui/browsers/hists.c | 98 ++++++++++++++++++++++++++++++++++++++++--
tools/perf/util/hist.c | 5 +++
tools/perf/util/sort.h | 1 +
3 files changed, 100 insertions(+), 4 deletions(-)

diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 641b402..489ba09 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -362,6 +362,46 @@ static void hist_entry__init_have_children(struct hist_entry *he)
he->init_have_children = true;
}

+static void hist_entry_init_inline_node(struct hist_entry *he)
+{
+ struct dso *dso;
+
+ if (he->inline_node)
+ return;
+
+ if (he->ms.map == NULL)
+ return;
+
+ dso = he->ms.map->dso;
+ if (dso == NULL)
+ return;
+
+ if (dso->kernel != DSO_TYPE_USER)
+ return;
+
+ he->inline_node = dso__parse_addr_inlines(dso,
+ map__rip_2objdump(he->ms.map, he->ip));
+
+ if (he->inline_node == NULL)
+ return;
+
+ he->has_children = true;
+}
+
+static int inline__count_rows(struct hist_entry *he)
+{
+ struct inline_node *node = he->inline_node;
+ struct inline_list *ilist;
+ int i = 0;
+
+ list_for_each_entry(ilist, &node->val, list) {
+ if (ilist->filename != NULL)
+ i++;
+ }
+
+ return i;
+}
+
static bool hist_browser__toggle_fold(struct hist_browser *browser)
{
struct hist_entry *he = browser->he_selection;
@@ -393,7 +433,11 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)

if (he->unfolded) {
if (he->leaf)
- he->nr_rows = callchain__count_rows(&he->sorted_chain);
+ if (he->inline_node)
+ he->nr_rows = inline__count_rows(he);
+ else
+ he->nr_rows = callchain__count_rows(
+ &he->sorted_chain);
else
he->nr_rows = hierarchy_count_rows(browser, he, false);

@@ -1091,6 +1135,40 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
return printed;
}

+static int hist_browser__show_inline(struct hist_browser *browser,
+ struct hist_entry *entry,
+ unsigned short row)
+{
+ struct inline_node *node;
+ struct inline_list *ilist;
+ char buf[1024];
+ int color, width, first_row;
+
+ first_row = row;
+ node = entry->inline_node;
+ width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
+
+ list_for_each_entry(ilist, &node->val, list) {
+ if (ilist->filename != NULL) {
+ color = HE_COLORSET_NORMAL;
+ if (ui_browser__is_current_entry(&browser->b, row))
+ color = HE_COLORSET_SELECTED;
+
+ scnprintf(buf, sizeof(buf), "%s:%d (inline)",
+ ilist->filename, ilist->line_nr);
+
+ ui_browser__set_color(&browser->b, color);
+ hist_browser__gotorc(browser, row, 0);
+ ui_browser__write_nstring(&browser->b, " ",
+ LEVEL_OFFSET_STEP + 2);
+ ui_browser__write_nstring(&browser->b, buf, width);
+ row++;
+ }
+ }
+
+ return row - first_row;
+}
+
struct hpp_arg {
struct ui_browser *b;
char folded_sign;
@@ -1204,6 +1282,11 @@ static int hist_browser__show_entry(struct hist_browser *browser,
folded_sign = hist_entry__folded(entry);
}

+ if (symbol_conf.show_inline && (!entry->has_children)) {
+ hist_entry_init_inline_node(entry);
+ folded_sign = hist_entry__folded(entry);
+ }
+
if (row_offset == 0) {
struct hpp_arg arg = {
.b = &browser->b,
@@ -1235,7 +1318,8 @@ static int hist_browser__show_entry(struct hist_browser *browser,
}

if (first) {
- if (symbol_conf.use_callchain) {
+ if (symbol_conf.use_callchain ||
+ symbol_conf.show_inline) {
ui_browser__printf(&browser->b, "%c ", folded_sign);
width -= 2;
}
@@ -1277,8 +1361,14 @@ static int hist_browser__show_entry(struct hist_browser *browser,
.is_current_entry = current_entry,
};

- printed += hist_browser__show_callchain(browser, entry, 1, row,
- hist_browser__show_callchain_entry, &arg,
+ if (entry->inline_node)
+ printed += hist_browser__show_inline(browser,
+ entry, row);
+ else
+ printed += hist_browser__show_callchain(browser,
+ entry, 1, row,
+ hist_browser__show_callchain_entry,
+ &arg,
hist_browser__check_output_full);
}

diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 6770a96..6b35187 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1122,6 +1122,11 @@ void hist_entry__delete(struct hist_entry *he)
zfree(&he->mem_info);
}

+ if (he->inline_node) {
+ inline_node__delete(he->inline_node);
+ he->inline_node = NULL;
+ }
+
zfree(&he->stat_acc);
free_srcline(he->srcline);
if (he->srcfile && he->srcfile[0])
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 7aff317..5dbfdc7 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -122,6 +122,7 @@ struct hist_entry {
};
char *srcline;
char *srcfile;
+ struct inline_node *inline_node;
struct symbol *parent;
struct branch_info *branch_info;
struct hists *hists;
--
2.7.4