perf ui/gtk: Implement hierarchy output mode
The hierarchy output mode is to group entries for each level so that user can see higher level picture more easily. Signed-off-by: Namhyung Kim <namhyung@kernel.org> Acked-by: Pekka Enberg <penberg@kernel.org> Cc: Andi Kleen <andi@firstfloor.org> Cc: David Ahern <dsahern@gmail.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Wang Nan <wangnan0@huawei.com> Link: http://lkml.kernel.org/r/1456326830-30456-16-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
d8b92400d3
commit
e311ec1e5d
|
@ -396,6 +396,164 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
|
||||||
gtk_container_add(GTK_CONTAINER(window), view);
|
gtk_container_add(GTK_CONTAINER(window), view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void perf_gtk__add_hierarchy_entries(struct hists *hists,
|
||||||
|
struct rb_root *root,
|
||||||
|
GtkTreeStore *store,
|
||||||
|
GtkTreeIter *parent,
|
||||||
|
struct perf_hpp *hpp,
|
||||||
|
float min_pcnt)
|
||||||
|
{
|
||||||
|
int col_idx = 0;
|
||||||
|
struct rb_node *node;
|
||||||
|
struct hist_entry *he;
|
||||||
|
struct perf_hpp_fmt *fmt;
|
||||||
|
u64 total = hists__total_period(hists);
|
||||||
|
|
||||||
|
for (node = rb_first(root); node; node = rb_next(node)) {
|
||||||
|
GtkTreeIter iter;
|
||||||
|
float percent;
|
||||||
|
|
||||||
|
he = rb_entry(node, struct hist_entry, rb_node);
|
||||||
|
if (he->filtered)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
percent = hist_entry__get_percent_limit(he);
|
||||||
|
if (percent < min_pcnt)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
gtk_tree_store_append(store, &iter, parent);
|
||||||
|
|
||||||
|
col_idx = 0;
|
||||||
|
hists__for_each_format(hists, fmt) {
|
||||||
|
if (perf_hpp__is_sort_entry(fmt) ||
|
||||||
|
perf_hpp__is_dynamic_entry(fmt))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (fmt->color)
|
||||||
|
fmt->color(fmt, hpp, he);
|
||||||
|
else
|
||||||
|
fmt->entry(fmt, hpp, he);
|
||||||
|
|
||||||
|
gtk_tree_store_set(store, &iter, col_idx++, hpp->buf, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt = he->fmt;
|
||||||
|
if (fmt->color)
|
||||||
|
fmt->color(fmt, hpp, he);
|
||||||
|
else
|
||||||
|
fmt->entry(fmt, hpp, he);
|
||||||
|
|
||||||
|
gtk_tree_store_set(store, &iter, col_idx, rtrim(hpp->buf), -1);
|
||||||
|
|
||||||
|
if (!he->leaf) {
|
||||||
|
perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
|
||||||
|
store, &iter, hpp,
|
||||||
|
min_pcnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbol_conf.use_callchain && he->leaf) {
|
||||||
|
if (callchain_param.mode == CHAIN_GRAPH_REL)
|
||||||
|
total = symbol_conf.cumulate_callchain ?
|
||||||
|
he->stat_acc->period : he->stat.period;
|
||||||
|
|
||||||
|
perf_gtk__add_callchain(&he->sorted_chain, store, &iter,
|
||||||
|
col_idx, total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
|
||||||
|
float min_pcnt)
|
||||||
|
{
|
||||||
|
struct perf_hpp_fmt *fmt;
|
||||||
|
GType col_types[MAX_COLUMNS];
|
||||||
|
GtkCellRenderer *renderer;
|
||||||
|
GtkTreeStore *store;
|
||||||
|
GtkWidget *view;
|
||||||
|
int col_idx;
|
||||||
|
int nr_cols = 0;
|
||||||
|
char s[512];
|
||||||
|
char buf[512];
|
||||||
|
bool first = true;
|
||||||
|
struct perf_hpp hpp = {
|
||||||
|
.buf = s,
|
||||||
|
.size = sizeof(s),
|
||||||
|
};
|
||||||
|
|
||||||
|
hists__for_each_format(hists, fmt) {
|
||||||
|
if (perf_hpp__is_sort_entry(fmt) ||
|
||||||
|
perf_hpp__is_dynamic_entry(fmt))
|
||||||
|
break;
|
||||||
|
|
||||||
|
col_types[nr_cols++] = G_TYPE_STRING;
|
||||||
|
}
|
||||||
|
col_types[nr_cols++] = G_TYPE_STRING;
|
||||||
|
|
||||||
|
store = gtk_tree_store_newv(nr_cols, col_types);
|
||||||
|
view = gtk_tree_view_new();
|
||||||
|
renderer = gtk_cell_renderer_text_new();
|
||||||
|
|
||||||
|
col_idx = 0;
|
||||||
|
hists__for_each_format(hists, fmt) {
|
||||||
|
if (perf_hpp__is_sort_entry(fmt) ||
|
||||||
|
perf_hpp__is_dynamic_entry(fmt))
|
||||||
|
break;
|
||||||
|
|
||||||
|
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
|
||||||
|
-1, fmt->name,
|
||||||
|
renderer, "markup",
|
||||||
|
col_idx++, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* construct merged column header since sort keys share single column */
|
||||||
|
buf[0] = '\0';
|
||||||
|
hists__for_each_format(hists ,fmt) {
|
||||||
|
if (!perf_hpp__is_sort_entry(fmt) &&
|
||||||
|
!perf_hpp__is_dynamic_entry(fmt))
|
||||||
|
continue;
|
||||||
|
if (perf_hpp__should_skip(fmt, hists))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
strcat(buf, " / ");
|
||||||
|
|
||||||
|
fmt->header(fmt, &hpp, hists_to_evsel(hists));
|
||||||
|
strcat(buf, rtrim(hpp.buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
|
||||||
|
-1, buf,
|
||||||
|
renderer, "markup",
|
||||||
|
col_idx++, NULL);
|
||||||
|
|
||||||
|
for (col_idx = 0; col_idx < nr_cols; col_idx++) {
|
||||||
|
GtkTreeViewColumn *column;
|
||||||
|
|
||||||
|
column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
|
||||||
|
gtk_tree_view_column_set_resizable(column, TRUE);
|
||||||
|
|
||||||
|
if (col_idx == 0) {
|
||||||
|
gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
|
||||||
|
column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
|
||||||
|
g_object_unref(GTK_TREE_MODEL(store));
|
||||||
|
|
||||||
|
perf_gtk__add_hierarchy_entries(hists, &hists->entries, store,
|
||||||
|
NULL, &hpp, min_pcnt);
|
||||||
|
|
||||||
|
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
|
||||||
|
|
||||||
|
g_signal_connect(view, "row-activated",
|
||||||
|
G_CALLBACK(on_row_activated), NULL);
|
||||||
|
gtk_container_add(GTK_CONTAINER(window), view);
|
||||||
|
}
|
||||||
|
|
||||||
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
|
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
|
||||||
const char *help,
|
const char *help,
|
||||||
struct hist_browser_timer *hbt __maybe_unused,
|
struct hist_browser_timer *hbt __maybe_unused,
|
||||||
|
@ -463,7 +621,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
|
||||||
GTK_POLICY_AUTOMATIC,
|
GTK_POLICY_AUTOMATIC,
|
||||||
GTK_POLICY_AUTOMATIC);
|
GTK_POLICY_AUTOMATIC);
|
||||||
|
|
||||||
perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
|
if (symbol_conf.report_hierarchy)
|
||||||
|
perf_gtk__show_hierarchy(scrolled_window, hists, min_pcnt);
|
||||||
|
else
|
||||||
|
perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
|
||||||
|
|
||||||
tab_label = gtk_label_new(evname);
|
tab_label = gtk_label_new(evname);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue