[PATCH] perf report: [WIP] Support '-F none' option to hide hist lines

From: Namhyung Kim
Date: Mon Nov 09 2015 - 00:46:02 EST


For some reason, it sometimes wants to hide hist lines but only wants to
see callchains. To do that, add virtual 'none' field name to hide all
hist lines. It should be used solely and only meaningful on --stdio.

WIP on TUI

Cc: Brendan Gregg <brendan.d.gregg@xxxxxxxxx>
Signed-off-by: Namhyung Kim <namhyung@xxxxxxxxxx>
---
tools/perf/Documentation/perf-report.txt | 3 ++
tools/perf/ui/browsers/hists.c | 22 +++++++++--
tools/perf/ui/gtk/hists.c | 65 ++++++++++++++++++++++++--------
tools/perf/ui/stdio/hist.c | 5 +++
tools/perf/util/sort.c | 5 +++
5 files changed, 82 insertions(+), 18 deletions(-)

diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index dab99ed2b339..6cfc643c0806 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -127,6 +127,9 @@ OPTIONS
By default, every sort keys not specified in -F will be appended
automatically.

+ If "none" is specified, it hides all fields and --stdio output will show
+ callchains only.
+
If --mem-mode option is used, following sort keys are also available
(incompatible with --branch-stack):
symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline.
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 3efe7c74f47d..c2f586f0c729 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -78,6 +78,9 @@ static u32 hist_browser__nr_entries(struct hist_browser *hb)
nr_entries = hb->hists->nr_entries;

hb->nr_callchain_rows = hist_browser__get_folding(hb);
+
+ if (list_empty(&perf_hpp__list))
+ nr_entries = 1;
return nr_entries + hb->nr_callchain_rows;
}

@@ -255,7 +258,10 @@ static bool hist_entry__toggle_fold(struct hist_entry *he)
if (!he->has_children)
return false;

- he->unfolded = !he->unfolded;
+ if (list_empty(&perf_hpp__list))
+ he->unfolded = true;
+ else
+ he->unfolded = !he->unfolded;
return true;
}

@@ -329,6 +335,10 @@ static void hist_entry__init_have_children(struct hist_entry *he)
if (!he->init_have_children) {
he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
callchain__init_have_children(&he->sorted_chain);
+ if (list_empty(&perf_hpp__list)) {
+ he->unfolded = true;
+ he->nr_rows = callchain__count_rows(&he->sorted_chain);
+ }
he->init_have_children = true;
}
}
@@ -1038,6 +1048,9 @@ static int hist_browser__show_entry(struct hist_browser *browser,

hist_browser__gotorc(browser, row, 0);

+ if (list_empty(&perf_hpp__list))
+ goto print_callchain;
+
perf_hpp__for_each_format(fmt) {
if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
continue;
@@ -1080,6 +1093,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
} else
--row_offset;

+print_callchain:
if (folded_sign == '-' && row != browser->b.rows) {
u64 total = hists__total_period(entry->hists);
struct callchain_print_arg arg = {
@@ -1313,7 +1327,8 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
if (nd == NULL)
break;
- --offset;
+ if (!list_empty(&perf_hpp__list))
+ --offset;
browser->top = nd;
} while (offset != 0);
} else if (offset < 0) {
@@ -1347,7 +1362,8 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
hb->min_pcnt);
if (nd == NULL)
break;
- ++offset;
+ if (!list_empty(&perf_hpp__list))
+ ++offset;
browser->top = nd;
if (offset == 0) {
/*
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 6105b4921754..535f8c5e74dc 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -98,12 +98,12 @@ static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *sto
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
struct callchain_node *node;
struct callchain_list *chain;
- GtkTreeIter iter, new_parent;
+ GtkTreeIter iter, new_parent_iter, *new_parent;
bool need_new_parent;

node = rb_entry(nd, struct callchain_node, rb_node);

- new_parent = *parent;
+ new_parent = parent;
need_new_parent = !has_single_node;

callchain_node__make_parent_list(node);
@@ -111,7 +111,7 @@ static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *sto
list_for_each_entry(chain, &node->parent_val, list) {
char buf[128];

- gtk_tree_store_append(store, &iter, &new_parent);
+ gtk_tree_store_append(store, &iter, new_parent);

callchain_node__sprintf_value(node, buf, sizeof(buf), total);
gtk_tree_store_set(store, &iter, 0, buf, -1);
@@ -124,7 +124,8 @@ static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *sto
* Only show the top-most symbol in a callchain
* if it's not the only callchain.
*/
- new_parent = iter;
+ new_parent_iter = iter;
+ new_parent = &new_parent_iter;
need_new_parent = false;
}
}
@@ -132,7 +133,7 @@ static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *sto
list_for_each_entry(chain, &node->val, list) {
char buf[128];

- gtk_tree_store_append(store, &iter, &new_parent);
+ gtk_tree_store_append(store, &iter, new_parent);

callchain_node__sprintf_value(node, buf, sizeof(buf), total);
gtk_tree_store_set(store, &iter, 0, buf, -1);
@@ -145,7 +146,8 @@ static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *sto
* Only show the top-most symbol in a callchain
* if it's not the only callchain.
*/
- new_parent = iter;
+ new_parent_iter = iter;
+ new_parent = &new_parent_iter;
need_new_parent = false;
}
}
@@ -221,19 +223,19 @@ static void perf_gtk__add_callchain_graph(struct rb_root *root, GtkTreeStore *st
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
struct callchain_node *node;
struct callchain_list *chain;
- GtkTreeIter iter, new_parent;
+ GtkTreeIter iter, new_parent_iter, *new_parent;
bool need_new_parent;
u64 child_total;

node = rb_entry(nd, struct callchain_node, rb_node);

- new_parent = *parent;
+ new_parent = parent;
need_new_parent = !has_single_node && (node->val_nr > 1);

list_for_each_entry(chain, &node->val, list) {
char buf[128];

- gtk_tree_store_append(store, &iter, &new_parent);
+ gtk_tree_store_append(store, &iter, new_parent);

callchain_node__sprintf_value(node, buf, sizeof(buf), total);
gtk_tree_store_set(store, &iter, 0, buf, -1);
@@ -246,7 +248,8 @@ static void perf_gtk__add_callchain_graph(struct rb_root *root, GtkTreeStore *st
* Only show the top-most symbol in a callchain
* if it's not the only callchain.
*/
- new_parent = iter;
+ new_parent_iter = iter;
+ new_parent = &new_parent_iter;
need_new_parent = false;
}
}
@@ -292,12 +295,14 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
GType col_types[MAX_COLUMNS];
GtkCellRenderer *renderer;
GtkTreeStore *store;
+ GtkTreeIter *iter;
struct rb_node *nd;
GtkWidget *view;
int col_idx;
int sym_col = -1;
int nr_cols;
char s[512];
+ bool no_hists = false;

struct perf_hpp hpp = {
.buf = s,
@@ -309,6 +314,18 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
perf_hpp__for_each_format(fmt)
col_types[nr_cols++] = G_TYPE_STRING;

+ if (nr_cols == 0) {
+ /*
+ * user specified '-F none' to ignore hist entries.
+ * Add two columns to print callchain value and symbols.
+ */
+ no_hists = true;
+
+ nr_cols = 2;
+ col_types[0] = G_TYPE_STRING;
+ col_types[1] = G_TYPE_STRING;
+ }
+
store = gtk_tree_store_newv(nr_cols, col_types);

view = gtk_tree_view_new();
@@ -334,6 +351,18 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx++, NULL);
}

+ if (no_hists) {
+ sym_col = 1;
+ gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+ -1, "Overhead",
+ renderer, "markup",
+ 0, NULL);
+ gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+ -1, "Callchains",
+ renderer, "markup",
+ 1, NULL);
+ }
+
for (col_idx = 0; col_idx < nr_cols; col_idx++) {
GtkTreeViewColumn *column;

@@ -352,7 +381,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,

for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
- GtkTreeIter iter;
+ GtkTreeIter this_iter;
u64 total = hists__total_period(h->hists);
float percent;

@@ -363,7 +392,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
if (percent < min_pcnt)
continue;

- gtk_tree_store_append(store, &iter, NULL);
+ if (no_hists) {
+ /* NULL means that callchains are in top-level */
+ iter = NULL;
+ } else {
+ iter = &this_iter;
+ gtk_tree_store_append(store, iter, NULL);
+ }

col_idx = 0;

@@ -376,15 +411,15 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
else
fmt->entry(fmt, &hpp, h);

- gtk_tree_store_set(store, &iter, col_idx++, s, -1);
+ gtk_tree_store_set(store, iter, col_idx++, s, -1);
}

- if (symbol_conf.use_callchain && sort__has_sym) {
+ if (symbol_conf.use_callchain) {
if (callchain_param.mode == CHAIN_GRAPH_REL)
total = symbol_conf.cumulate_callchain ?
h->stat_acc->period : h->stat.period;

- perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
+ perf_gtk__add_callchain(&h->sorted_chain, store, iter,
sym_col, total);
}
}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 7ebc661be267..48ae34abf9c8 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -422,6 +422,11 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
if (size == 0 || size > bfsz)
size = hpp.size = bfsz;

+ /*
+ * In case of '-F none', the bf is not set at all.
+ */
+ bf[0] = '\0';
+
hist_entry__snprintf(he, &hpp);

ret = fprintf(fp, "%s\n", bf);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 2d8ccd4d9e1b..8c731906d432 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1923,6 +1923,11 @@ static int __setup_output_field(void)
if (field_order == NULL)
return 0;

+ if (!strcmp(field_order, "none")) {
+ symbol_conf.show_hist_headers = false;
+ return 0;
+ }
+
strp = str = strdup(field_order);
if (str == NULL) {
error("Not enough memory to setup output fields");
--
2.6.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/