Skip to content

Commit

Permalink
perf annotate browser: Allow navigation to called functions
Browse files Browse the repository at this point in the history
I.e. when in the annotate TUI window, if Enter is pressed over an
assembly line with a 'callq' it will try to open another TUI window with
that symbol.

This is just a proof of concept and works only on x86_64, more work is
needed to support kernel modules, userland, other arches, etc, but
should already be useful as-is.

Suggested-by: Ingo Molnar <mingo@elte.hu>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-opyvskw5na3qdmkv8vxi3zbr@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Arnaldo Carvalho de Melo committed Oct 7, 2011
1 parent 19d4ac3 commit 3495854
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 25 deletions.
9 changes: 6 additions & 3 deletions tools/perf/builtin-annotate.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
print_line, full_paths, 0, 0);
}

static void hists__find_annotations(struct hists *self, int evidx)
static void hists__find_annotations(struct hists *self, int evidx,
int nr_events)
{
struct rb_node *nd = rb_first(&self->entries), *next;
int key = KEY_RIGHT;
Expand All @@ -137,7 +138,8 @@ static void hists__find_annotations(struct hists *self, int evidx)
}

if (use_browser > 0) {
key = hist_entry__tui_annotate(he, evidx, NULL, NULL, 0);
key = hist_entry__tui_annotate(he, evidx, nr_events,
NULL, NULL, 0);
switch (key) {
case KEY_RIGHT:
next = rb_next(nd);
Expand Down Expand Up @@ -215,7 +217,8 @@ static int __cmd_annotate(void)
total_nr_samples += nr_samples;
hists__collapse_resort(hists);
hists__output_resort(hists);
hists__find_annotations(hists, pos->idx);
hists__find_annotations(hists, pos->idx,
session->evlist->nr_entries);
}
}

Expand Down
2 changes: 1 addition & 1 deletion tools/perf/util/annotate.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ static inline int symbol__tui_annotate(struct symbol *sym __used,
}
#else
int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
void(*timer)(void *arg), void *arg,
int nr_events, void(*timer)(void *arg), void *arg,
int delay_secs);
#endif

Expand Down
4 changes: 2 additions & 2 deletions tools/perf/util/hist.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
}

static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
int evidx __used,
int evidx __used, int nr_events __used,
void(*timer)(void *arg) __used,
void *arg __used, int delay_secs __used);
{
Expand All @@ -120,7 +120,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
#define KEY_RIGHT -2
#else
#include <newt.h>
int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
void(*timer)(void *arg), void *arg, int delay_secs);

#define KEY_LEFT NEWT_KEY_LEFT
Expand Down
69 changes: 58 additions & 11 deletions tools/perf/util/ui/browsers/annotate.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct annotate_browser {
struct ui_browser b;
struct rb_root entries;
struct rb_node *curr_hot;
struct objdump_line *selection;
};

struct objdump_line_rb_node {
Expand All @@ -36,6 +37,7 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)

static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
{
struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
struct objdump_line *ol = rb_entry(entry, struct objdump_line, node);
bool current_entry = ui_browser__is_current_entry(self, row);
int width = self->width;
Expand All @@ -58,6 +60,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro

if (!current_entry)
ui_browser__set_color(self, HE_COLORSET_CODE);
else
ab->selection = ol;
}

static double objdump_line__calc_percent(struct objdump_line *self,
Expand Down Expand Up @@ -141,7 +145,8 @@ static void annotate_browser__set_top(struct annotate_browser *self,
static void annotate_browser__calc_percent(struct annotate_browser *browser,
int evidx)
{
struct symbol *sym = browser->b.priv;
struct map_symbol *ms = browser->b.priv;
struct symbol *sym = ms->sym;
struct annotation *notes = symbol__annotation(sym);
struct objdump_line *pos;

Expand All @@ -164,17 +169,18 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
}

static int annotate_browser__run(struct annotate_browser *self, int evidx,
void(*timer)(void *arg) __used, void *arg __used,
int delay_secs)
int nr_events, void(*timer)(void *arg),
void *arg, int delay_secs)
{
struct rb_node *nd = NULL;
struct symbol *sym = self->b.priv;
struct map_symbol *ms = self->b.priv;
struct symbol *sym = ms->sym;
/*
* RIGHT To allow builtin-annotate to cycle thru multiple symbols by
* examining the exit key for this function.
*/
int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
NEWT_KEY_RIGHT, 0 };
NEWT_KEY_RIGHT, NEWT_KEY_ENTER, 0 };
int key;

if (ui_browser__show(&self->b, sym->name,
Expand Down Expand Up @@ -238,6 +244,42 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
case 'H':
nd = self->curr_hot;
break;
case NEWT_KEY_ENTER:
if (self->selection != NULL) {
char *s = strstr(self->selection->line, "callq ");
struct annotation *notes;
struct symbol *target;
u64 ip;

if (s == NULL)
continue;

s = strchr(s, ' ');
if (s++ == NULL)
continue;

ip = strtoull(s, NULL, 16);
ip = ms->map->map_ip(ms->map, ip);
target = map__find_symbol(ms->map, ip, NULL);
if (target == NULL)
continue;

notes = symbol__annotation(target);
pthread_mutex_lock(&notes->lock);

if (notes->src == NULL &&
symbol__alloc_hist(target, nr_events) < 0) {
pthread_mutex_unlock(&notes->lock);
ui__warning("Not enough memory for annotating '%s' symbol!\n",
target->name);
continue;
}

pthread_mutex_unlock(&notes->lock);
symbol__tui_annotate(target, ms->map, evidx, nr_events,
timer, arg, delay_secs);
}
break;
default:
goto out;
}
Expand All @@ -250,25 +292,29 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
return key;
}

int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
void(*timer)(void *arg), void *arg, int delay_secs)
{
return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events,
timer, arg, delay_secs);
}

int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
void(*timer)(void *arg), void *arg,
int delay_secs)
int nr_events, void(*timer)(void *arg), void *arg,
int delay_secs)
{
struct objdump_line *pos, *n;
struct annotation *notes;
struct map_symbol ms = {
.map = map,
.sym = sym,
};
struct annotate_browser browser = {
.b = {
.refresh = ui_browser__list_head_refresh,
.seek = ui_browser__list_head_seek,
.write = annotate_browser__write,
.priv = sym,
.priv = &ms,
},
};
int ret;
Expand Down Expand Up @@ -300,7 +346,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,

browser.b.entries = &notes->src->source,
browser.b.width += 18; /* Percentage */
ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
ret = annotate_browser__run(&browser, evidx, nr_events,
timer, arg, delay_secs);
list_for_each_entry_safe(pos, n, &notes->src->source, node) {
list_del(&pos->node);
objdump_line__free(pos);
Expand Down
20 changes: 12 additions & 8 deletions tools/perf/util/ui/browsers/hists.c
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,7 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
return printed;
}

static int perf_evsel__hists_browse(struct perf_evsel *evsel,
static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
const char *helpline, const char *ev_name,
bool left_exits,
void(*timer)(void *arg), void *arg,
Expand Down Expand Up @@ -968,7 +968,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
if (he == NULL)
continue;

hist_entry__tui_annotate(he, evsel->idx,
hist_entry__tui_annotate(he, evsel->idx, nr_events,
timer, arg, delay_secs);
} else if (choice == browse_map)
map__browse(browser->selection->map);
Expand Down Expand Up @@ -1042,7 +1042,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
menu->selection = evsel;
}

static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help,
static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
int nr_events, const char *help,
void(*timer)(void *arg), void *arg, int delay_secs)
{
int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
Expand Down Expand Up @@ -1077,8 +1078,9 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help,
perf_evlist__set_selected(evlist, pos);
browse_hists:
ev_name = event_name(pos);
key = perf_evsel__hists_browse(pos, help, ev_name, true,
timer, arg, delay_secs);
key = perf_evsel__hists_browse(pos, nr_events, help,
ev_name, true, timer,
arg, delay_secs);
ui_browser__show_title(&menu->b, title);
break;
case NEWT_KEY_LEFT:
Expand Down Expand Up @@ -1150,7 +1152,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
pos->name = strdup(ev_name);
}

return perf_evsel_menu__run(&menu, help, timer, arg, delay_secs);
return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
arg, delay_secs);
}

int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
Expand All @@ -1162,8 +1165,9 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
struct perf_evsel *first = list_entry(evlist->entries.next,
struct perf_evsel, node);
const char *ev_name = event_name(first);
return perf_evsel__hists_browse(first, help, ev_name, false,
timer, arg, delay_secs);
return perf_evsel__hists_browse(first, evlist->nr_entries, help,
ev_name, false, timer, arg,
delay_secs);
}

return __perf_evlist__tui_browse_hists(evlist, help,
Expand Down

0 comments on commit 3495854

Please sign in to comment.