perf ui/gtk: Implement basic GTK2 annotation browser

Basic implementation of perf annotate on GTK2.  Currently only
shows first symbol.  Add a new --gtk option to use it.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1360227734-375-2-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Namhyung Kim 2013-02-07 18:02:08 +09:00 committed by Arnaldo Carvalho de Melo
parent e3a34029c6
commit 2b676bf068
6 changed files with 218 additions and 4 deletions

View File

@ -61,11 +61,13 @@ OPTIONS
--stdio:: Use the stdio interface. --stdio:: Use the stdio interface.
--tui:: Use the TUI interface Use of --tui requires a tty, if one is not --tui:: Use the TUI interface. Use of --tui requires a tty, if one is not
present, as when piping to other commands, the stdio interface is present, as when piping to other commands, the stdio interface is
used. This interfaces starts by centering on the line with more used. This interfaces starts by centering on the line with more
samples, TAB/UNTAB cycles through the lines with more samples. samples, TAB/UNTAB cycles through the lines with more samples.
--gtk:: Use the GTK interface.
-C:: -C::
--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
be provided as a comma-separated list with no space: 0,1. Ranges of be provided as a comma-separated list with no space: 0,1. Ranges of

View File

@ -698,6 +698,7 @@ ifndef NO_GTK2
LIB_OBJS += $(OUTPUT)ui/gtk/util.o LIB_OBJS += $(OUTPUT)ui/gtk/util.o
LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
LIB_OBJS += $(OUTPUT)ui/gtk/progress.o LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
endif endif
endif endif

View File

@ -34,7 +34,7 @@
struct perf_annotate { struct perf_annotate {
struct perf_tool tool; struct perf_tool tool;
bool force, use_tui, use_stdio; bool force, use_tui, use_stdio, use_gtk;
bool full_paths; bool full_paths;
bool print_line; bool print_line;
const char *sym_hist_filter; const char *sym_hist_filter;
@ -138,7 +138,10 @@ static void hists__find_annotations(struct hists *self, int evidx,
continue; continue;
} }
if (use_browser > 0) { if (use_browser == 2) {
hist_entry__gtk_annotate(he, evidx, NULL);
return;
} else if (use_browser == 1) {
key = hist_entry__tui_annotate(he, evidx, NULL); key = hist_entry__tui_annotate(he, evidx, NULL);
switch (key) { switch (key) {
case K_RIGHT: case K_RIGHT:
@ -270,6 +273,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
"be more verbose (show symbol address, etc)"), "be more verbose (show symbol address, etc)"),
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
"dump raw trace in ASCII"), "dump raw trace in ASCII"),
OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"),
OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"),
OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"),
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
@ -300,6 +304,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
use_browser = 0; use_browser = 0;
else if (annotate.use_tui) else if (annotate.use_tui)
use_browser = 1; use_browser = 1;
else if (annotate.use_gtk)
use_browser = 2;
setup_browser(true); setup_browser(true);

View File

@ -0,0 +1,185 @@
#include "gtk.h"
#include "util/debug.h"
#include "util/annotate.h"
#include "ui/helpline.h"
enum {
ANN_COL__PERCENT,
ANN_COL__OFFSET,
ANN_COL__LINE,
MAX_ANN_COLS
};
static const char *const col_names[] = {
"Overhead",
"Offset",
"Line"
};
static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
struct disasm_line *dl, int evidx)
{
struct sym_hist *symhist;
double percent = 0.0;
const char *markup;
int ret = 0;
strcpy(buf, "");
if (dl->offset == (s64) -1)
return 0;
symhist = annotation__histogram(symbol__annotation(sym), evidx);
if (!symhist->addr[dl->offset])
return 0;
percent = 100.0 * symhist->addr[dl->offset] / symhist->sum;
markup = perf_gtk__get_percent_color(percent);
if (markup)
ret += scnprintf(buf, size, "%s", markup);
ret += scnprintf(buf + ret, size - ret, "%6.2f%%", percent);
if (markup)
ret += scnprintf(buf + ret, size - ret, "</span>");
return ret;
}
static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym,
struct map *map, struct disasm_line *dl)
{
u64 start = map__rip_2objdump(map, sym->start);
strcpy(buf, "");
if (dl->offset == (s64) -1)
return 0;
return scnprintf(buf, size, "%"PRIx64, start + dl->offset);
}
static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
struct map *map, int evidx,
struct hist_browser_timer *hbt __maybe_unused)
{
struct disasm_line *pos, *n;
struct annotation *notes;
GType col_types[MAX_ANN_COLS];
GtkCellRenderer *renderer;
GtkListStore *store;
GtkWidget *view;
int i;
char s[512];
if (map->dso->annotate_warned)
return -1;
if (symbol__annotate(sym, map, 0) < 0) {
ui__error("%s", ui_helpline__current);
return -1;
}
notes = symbol__annotation(sym);
for (i = 0; i < MAX_ANN_COLS; i++) {
col_types[i] = G_TYPE_STRING;
}
store = gtk_list_store_newv(MAX_ANN_COLS, col_types);
view = gtk_tree_view_new();
renderer = gtk_cell_renderer_text_new();
for (i = 0; i < MAX_ANN_COLS; i++) {
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-1, col_names[i], renderer,
i == ANN_COL__PERCENT ? "markup" : "text",
i, NULL);
}
gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
g_object_unref(GTK_TREE_MODEL(store));
list_for_each_entry(pos, &notes->src->source, node) {
GtkTreeIter iter;
gtk_list_store_append(store, &iter);
if (perf_gtk__get_percent(s, sizeof(s), sym, pos, evidx))
gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1);
if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos))
gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1);
gtk_list_store_set(store, &iter, ANN_COL__LINE, pos->line, -1);
}
gtk_container_add(GTK_CONTAINER(window), view);
list_for_each_entry_safe(pos, n, &notes->src->source, node) {
list_del(&pos->node);
disasm_line__free(pos);
}
return 0;
}
int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
struct hist_browser_timer *hbt)
{
GtkWidget *vbox;
GtkWidget *notebook;
GtkWidget *infobar;
GtkWidget *statbar;
GtkWidget *window;
GtkWidget *scrolled_window;
GtkWidget *tab_label;
signal(SIGSEGV, perf_gtk__signal);
signal(SIGFPE, perf_gtk__signal);
signal(SIGINT, perf_gtk__signal);
signal(SIGQUIT, perf_gtk__signal);
signal(SIGTERM, perf_gtk__signal);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "perf annotate");
g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
pgctx = perf_gtk__activate_context(window);
if (!pgctx)
return -1;
vbox = gtk_vbox_new(FALSE, 0);
notebook = gtk_notebook_new();
scrolled_window = gtk_scrolled_window_new(NULL, NULL);
tab_label = gtk_label_new(sym->name);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window,
tab_label);
gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
infobar = perf_gtk__setup_info_bar();
if (infobar)
gtk_box_pack_start(GTK_BOX(vbox), infobar, FALSE, FALSE, 0);
statbar = perf_gtk__setup_statusbar();
gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt);
gtk_widget_show_all(window);
perf_gtk__resize_window(window);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_main();
perf_gtk__deactivate_context(&pgctx);
return 0;
}

View File

@ -8,7 +8,7 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
void setup_browser(bool fallback_to_pager) void setup_browser(bool fallback_to_pager)
{ {
if (!isatty(1) || dump_trace) if (use_browser < 2 && (!isatty(1) || dump_trace))
use_browser = 0; use_browser = 0;
/* default to TUI */ /* default to TUI */

View File

@ -6,6 +6,7 @@
#include "types.h" #include "types.h"
#include "symbol.h" #include "symbol.h"
#include "hist.h" #include "hist.h"
#include "sort.h"
#include <linux/list.h> #include <linux/list.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <pthread.h> #include <pthread.h>
@ -154,6 +155,25 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
} }
#endif #endif
#ifdef GTK2_SUPPORT
int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
struct hist_browser_timer *hbt);
static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx,
struct hist_browser_timer *hbt)
{
return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt);
}
#else
static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused,
int evidx __maybe_unused,
struct hist_browser_timer *hbt
__maybe_unused)
{
return 0;
}
#endif
extern const char *disassembler_style; extern const char *disassembler_style;
#endif /* __PERF_ANNOTATE_H */ #endif /* __PERF_ANNOTATE_H */