diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-10-05 18:35:54 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-10-07 16:00:09 -0400 |
commit | 34958544b3da17e98d98d7b872c6516995ad66bb (patch) | |
tree | 02a028e28e3f996be6fe2b0ff2258241361a05a0 /tools | |
parent | 19d4ac3c1039fb952f4c073fd0898e9295a836c8 (diff) |
perf annotate browser: Allow navigation to called functions
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>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-annotate.c | 9 | ||||
-rw-r--r-- | tools/perf/util/annotate.h | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 4 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/annotate.c | 69 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/hists.c | 20 |
5 files changed, 79 insertions, 25 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 39e3d382b2d8..24db9d2db7b4 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -114,7 +114,8 @@ static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) | |||
114 | print_line, full_paths, 0, 0); | 114 | print_line, full_paths, 0, 0); |
115 | } | 115 | } |
116 | 116 | ||
117 | static void hists__find_annotations(struct hists *self, int evidx) | 117 | static void hists__find_annotations(struct hists *self, int evidx, |
118 | int nr_events) | ||
118 | { | 119 | { |
119 | struct rb_node *nd = rb_first(&self->entries), *next; | 120 | struct rb_node *nd = rb_first(&self->entries), *next; |
120 | int key = KEY_RIGHT; | 121 | int key = KEY_RIGHT; |
@@ -137,7 +138,8 @@ find_next: | |||
137 | } | 138 | } |
138 | 139 | ||
139 | if (use_browser > 0) { | 140 | if (use_browser > 0) { |
140 | key = hist_entry__tui_annotate(he, evidx, NULL, NULL, 0); | 141 | key = hist_entry__tui_annotate(he, evidx, nr_events, |
142 | NULL, NULL, 0); | ||
141 | switch (key) { | 143 | switch (key) { |
142 | case KEY_RIGHT: | 144 | case KEY_RIGHT: |
143 | next = rb_next(nd); | 145 | next = rb_next(nd); |
@@ -215,7 +217,8 @@ static int __cmd_annotate(void) | |||
215 | total_nr_samples += nr_samples; | 217 | total_nr_samples += nr_samples; |
216 | hists__collapse_resort(hists); | 218 | hists__collapse_resort(hists); |
217 | hists__output_resort(hists); | 219 | hists__output_resort(hists); |
218 | hists__find_annotations(hists, pos->idx); | 220 | hists__find_annotations(hists, pos->idx, |
221 | session->evlist->nr_entries); | ||
219 | } | 222 | } |
220 | } | 223 | } |
221 | 224 | ||
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index aafbc7e9a9ba..d9072523d342 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -99,7 +99,7 @@ static inline int symbol__tui_annotate(struct symbol *sym __used, | |||
99 | } | 99 | } |
100 | #else | 100 | #else |
101 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | 101 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, |
102 | void(*timer)(void *arg), void *arg, | 102 | int nr_events, void(*timer)(void *arg), void *arg, |
103 | int delay_secs); | 103 | int delay_secs); |
104 | #endif | 104 | #endif |
105 | 105 | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index f87677bfaff9..7ea1e560e008 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -110,7 +110,7 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, | |||
110 | } | 110 | } |
111 | 111 | ||
112 | static inline int hist_entry__tui_annotate(struct hist_entry *self __used, | 112 | static inline int hist_entry__tui_annotate(struct hist_entry *self __used, |
113 | int evidx __used, | 113 | int evidx __used, int nr_events __used, |
114 | void(*timer)(void *arg) __used, | 114 | void(*timer)(void *arg) __used, |
115 | void *arg __used, int delay_secs __used); | 115 | void *arg __used, int delay_secs __used); |
116 | { | 116 | { |
@@ -120,7 +120,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used, | |||
120 | #define KEY_RIGHT -2 | 120 | #define KEY_RIGHT -2 |
121 | #else | 121 | #else |
122 | #include <newt.h> | 122 | #include <newt.h> |
123 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, | 123 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, |
124 | void(*timer)(void *arg), void *arg, int delay_secs); | 124 | void(*timer)(void *arg), void *arg, int delay_secs); |
125 | 125 | ||
126 | #define KEY_LEFT NEWT_KEY_LEFT | 126 | #define KEY_LEFT NEWT_KEY_LEFT |
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 76c1d083aa94..77421bab8fdd 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c | |||
@@ -20,6 +20,7 @@ struct annotate_browser { | |||
20 | struct ui_browser b; | 20 | struct ui_browser b; |
21 | struct rb_root entries; | 21 | struct rb_root entries; |
22 | struct rb_node *curr_hot; | 22 | struct rb_node *curr_hot; |
23 | struct objdump_line *selection; | ||
23 | }; | 24 | }; |
24 | 25 | ||
25 | struct objdump_line_rb_node { | 26 | struct objdump_line_rb_node { |
@@ -36,6 +37,7 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self) | |||
36 | 37 | ||
37 | static void annotate_browser__write(struct ui_browser *self, void *entry, int row) | 38 | static void annotate_browser__write(struct ui_browser *self, void *entry, int row) |
38 | { | 39 | { |
40 | struct annotate_browser *ab = container_of(self, struct annotate_browser, b); | ||
39 | struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); | 41 | struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); |
40 | bool current_entry = ui_browser__is_current_entry(self, row); | 42 | bool current_entry = ui_browser__is_current_entry(self, row); |
41 | int width = self->width; | 43 | int width = self->width; |
@@ -58,6 +60,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro | |||
58 | 60 | ||
59 | if (!current_entry) | 61 | if (!current_entry) |
60 | ui_browser__set_color(self, HE_COLORSET_CODE); | 62 | ui_browser__set_color(self, HE_COLORSET_CODE); |
63 | else | ||
64 | ab->selection = ol; | ||
61 | } | 65 | } |
62 | 66 | ||
63 | static double objdump_line__calc_percent(struct objdump_line *self, | 67 | static double objdump_line__calc_percent(struct objdump_line *self, |
@@ -141,7 +145,8 @@ static void annotate_browser__set_top(struct annotate_browser *self, | |||
141 | static void annotate_browser__calc_percent(struct annotate_browser *browser, | 145 | static void annotate_browser__calc_percent(struct annotate_browser *browser, |
142 | int evidx) | 146 | int evidx) |
143 | { | 147 | { |
144 | struct symbol *sym = browser->b.priv; | 148 | struct map_symbol *ms = browser->b.priv; |
149 | struct symbol *sym = ms->sym; | ||
145 | struct annotation *notes = symbol__annotation(sym); | 150 | struct annotation *notes = symbol__annotation(sym); |
146 | struct objdump_line *pos; | 151 | struct objdump_line *pos; |
147 | 152 | ||
@@ -164,17 +169,18 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, | |||
164 | } | 169 | } |
165 | 170 | ||
166 | static int annotate_browser__run(struct annotate_browser *self, int evidx, | 171 | static int annotate_browser__run(struct annotate_browser *self, int evidx, |
167 | void(*timer)(void *arg) __used, void *arg __used, | 172 | int nr_events, void(*timer)(void *arg), |
168 | int delay_secs) | 173 | void *arg, int delay_secs) |
169 | { | 174 | { |
170 | struct rb_node *nd = NULL; | 175 | struct rb_node *nd = NULL; |
171 | struct symbol *sym = self->b.priv; | 176 | struct map_symbol *ms = self->b.priv; |
177 | struct symbol *sym = ms->sym; | ||
172 | /* | 178 | /* |
173 | * RIGHT To allow builtin-annotate to cycle thru multiple symbols by | 179 | * RIGHT To allow builtin-annotate to cycle thru multiple symbols by |
174 | * examining the exit key for this function. | 180 | * examining the exit key for this function. |
175 | */ | 181 | */ |
176 | int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB, | 182 | int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB, |
177 | NEWT_KEY_RIGHT, 0 }; | 183 | NEWT_KEY_RIGHT, NEWT_KEY_ENTER, 0 }; |
178 | int key; | 184 | int key; |
179 | 185 | ||
180 | if (ui_browser__show(&self->b, sym->name, | 186 | if (ui_browser__show(&self->b, sym->name, |
@@ -238,6 +244,42 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, | |||
238 | case 'H': | 244 | case 'H': |
239 | nd = self->curr_hot; | 245 | nd = self->curr_hot; |
240 | break; | 246 | break; |
247 | case NEWT_KEY_ENTER: | ||
248 | if (self->selection != NULL) { | ||
249 | char *s = strstr(self->selection->line, "callq "); | ||
250 | struct annotation *notes; | ||
251 | struct symbol *target; | ||
252 | u64 ip; | ||
253 | |||
254 | if (s == NULL) | ||
255 | continue; | ||
256 | |||
257 | s = strchr(s, ' '); | ||
258 | if (s++ == NULL) | ||
259 | continue; | ||
260 | |||
261 | ip = strtoull(s, NULL, 16); | ||
262 | ip = ms->map->map_ip(ms->map, ip); | ||
263 | target = map__find_symbol(ms->map, ip, NULL); | ||
264 | if (target == NULL) | ||
265 | continue; | ||
266 | |||
267 | notes = symbol__annotation(target); | ||
268 | pthread_mutex_lock(¬es->lock); | ||
269 | |||
270 | if (notes->src == NULL && | ||
271 | symbol__alloc_hist(target, nr_events) < 0) { | ||
272 | pthread_mutex_unlock(¬es->lock); | ||
273 | ui__warning("Not enough memory for annotating '%s' symbol!\n", | ||
274 | target->name); | ||
275 | continue; | ||
276 | } | ||
277 | |||
278 | pthread_mutex_unlock(¬es->lock); | ||
279 | symbol__tui_annotate(target, ms->map, evidx, nr_events, | ||
280 | timer, arg, delay_secs); | ||
281 | } | ||
282 | break; | ||
241 | default: | 283 | default: |
242 | goto out; | 284 | goto out; |
243 | } | 285 | } |
@@ -250,25 +292,29 @@ out: | |||
250 | return key; | 292 | return key; |
251 | } | 293 | } |
252 | 294 | ||
253 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, | 295 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, |
254 | void(*timer)(void *arg), void *arg, int delay_secs) | 296 | void(*timer)(void *arg), void *arg, int delay_secs) |
255 | { | 297 | { |
256 | return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, | 298 | return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events, |
257 | timer, arg, delay_secs); | 299 | timer, arg, delay_secs); |
258 | } | 300 | } |
259 | 301 | ||
260 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | 302 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, |
261 | void(*timer)(void *arg), void *arg, | 303 | int nr_events, void(*timer)(void *arg), void *arg, |
262 | int delay_secs) | 304 | int delay_secs) |
263 | { | 305 | { |
264 | struct objdump_line *pos, *n; | 306 | struct objdump_line *pos, *n; |
265 | struct annotation *notes; | 307 | struct annotation *notes; |
308 | struct map_symbol ms = { | ||
309 | .map = map, | ||
310 | .sym = sym, | ||
311 | }; | ||
266 | struct annotate_browser browser = { | 312 | struct annotate_browser browser = { |
267 | .b = { | 313 | .b = { |
268 | .refresh = ui_browser__list_head_refresh, | 314 | .refresh = ui_browser__list_head_refresh, |
269 | .seek = ui_browser__list_head_seek, | 315 | .seek = ui_browser__list_head_seek, |
270 | .write = annotate_browser__write, | 316 | .write = annotate_browser__write, |
271 | .priv = sym, | 317 | .priv = &ms, |
272 | }, | 318 | }, |
273 | }; | 319 | }; |
274 | int ret; | 320 | int ret; |
@@ -300,7 +346,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
300 | 346 | ||
301 | browser.b.entries = ¬es->src->source, | 347 | browser.b.entries = ¬es->src->source, |
302 | browser.b.width += 18; /* Percentage */ | 348 | browser.b.width += 18; /* Percentage */ |
303 | ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs); | 349 | ret = annotate_browser__run(&browser, evidx, nr_events, |
350 | timer, arg, delay_secs); | ||
304 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { | 351 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { |
305 | list_del(&pos->node); | 352 | list_del(&pos->node); |
306 | objdump_line__free(pos); | 353 | objdump_line__free(pos); |
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 6244d19bd1f2..f0515cbabda5 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c | |||
@@ -825,7 +825,7 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size, | |||
825 | return printed; | 825 | return printed; |
826 | } | 826 | } |
827 | 827 | ||
828 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, | 828 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, |
829 | const char *helpline, const char *ev_name, | 829 | const char *helpline, const char *ev_name, |
830 | bool left_exits, | 830 | bool left_exits, |
831 | void(*timer)(void *arg), void *arg, | 831 | void(*timer)(void *arg), void *arg, |
@@ -968,7 +968,7 @@ do_annotate: | |||
968 | if (he == NULL) | 968 | if (he == NULL) |
969 | continue; | 969 | continue; |
970 | 970 | ||
971 | hist_entry__tui_annotate(he, evsel->idx, | 971 | hist_entry__tui_annotate(he, evsel->idx, nr_events, |
972 | timer, arg, delay_secs); | 972 | timer, arg, delay_secs); |
973 | } else if (choice == browse_map) | 973 | } else if (choice == browse_map) |
974 | map__browse(browser->selection->map); | 974 | map__browse(browser->selection->map); |
@@ -1042,7 +1042,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser, | |||
1042 | menu->selection = evsel; | 1042 | menu->selection = evsel; |
1043 | } | 1043 | } |
1044 | 1044 | ||
1045 | static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help, | 1045 | static int perf_evsel_menu__run(struct perf_evsel_menu *menu, |
1046 | int nr_events, const char *help, | ||
1046 | void(*timer)(void *arg), void *arg, int delay_secs) | 1047 | void(*timer)(void *arg), void *arg, int delay_secs) |
1047 | { | 1048 | { |
1048 | int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; | 1049 | int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; |
@@ -1077,8 +1078,9 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help, | |||
1077 | perf_evlist__set_selected(evlist, pos); | 1078 | perf_evlist__set_selected(evlist, pos); |
1078 | browse_hists: | 1079 | browse_hists: |
1079 | ev_name = event_name(pos); | 1080 | ev_name = event_name(pos); |
1080 | key = perf_evsel__hists_browse(pos, help, ev_name, true, | 1081 | key = perf_evsel__hists_browse(pos, nr_events, help, |
1081 | timer, arg, delay_secs); | 1082 | ev_name, true, timer, |
1083 | arg, delay_secs); | ||
1082 | ui_browser__show_title(&menu->b, title); | 1084 | ui_browser__show_title(&menu->b, title); |
1083 | break; | 1085 | break; |
1084 | case NEWT_KEY_LEFT: | 1086 | case NEWT_KEY_LEFT: |
@@ -1150,7 +1152,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | |||
1150 | pos->name = strdup(ev_name); | 1152 | pos->name = strdup(ev_name); |
1151 | } | 1153 | } |
1152 | 1154 | ||
1153 | return perf_evsel_menu__run(&menu, help, timer, arg, delay_secs); | 1155 | return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer, |
1156 | arg, delay_secs); | ||
1154 | } | 1157 | } |
1155 | 1158 | ||
1156 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | 1159 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, |
@@ -1162,8 +1165,9 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | |||
1162 | struct perf_evsel *first = list_entry(evlist->entries.next, | 1165 | struct perf_evsel *first = list_entry(evlist->entries.next, |
1163 | struct perf_evsel, node); | 1166 | struct perf_evsel, node); |
1164 | const char *ev_name = event_name(first); | 1167 | const char *ev_name = event_name(first); |
1165 | return perf_evsel__hists_browse(first, help, ev_name, false, | 1168 | return perf_evsel__hists_browse(first, evlist->nr_entries, help, |
1166 | timer, arg, delay_secs); | 1169 | ev_name, false, timer, arg, |
1170 | delay_secs); | ||
1167 | } | 1171 | } |
1168 | 1172 | ||
1169 | return __perf_evlist__tui_browse_hists(evlist, help, | 1173 | return __perf_evlist__tui_browse_hists(evlist, help, |