diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-05-22 10:25:40 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-05-22 10:25:40 -0400 |
commit | 46e3e055ce69a00d735e458445ab1d24718ff751 (patch) | |
tree | 06829420acf27f2deb05ac6ccc230268bf271318 /tools/perf/builtin-annotate.c | |
parent | 6e78c9fd1bc2c7e04b3d7052e9eb27aa536e4e2c (diff) |
perf annotate: Add TUI interface
When annotating multiple entries, for instance, when running simply as:
$ perf annotate
the right and left keys, as well as TAB can be used to cycle thru the
multiple symbols being annotated.
If one doesn't like TUI annotate, disable it by editing ~/.perfconfig
and adding:
[tui]
annotate = off
Just like it is possible for report.
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r-- | tools/perf/builtin-annotate.c | 61 |
1 files changed, 45 insertions, 16 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 77bcc9b130f5..08278eda31a5 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -277,7 +277,7 @@ static void hist_entry__print_hits(struct hist_entry *self) | |||
277 | printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum); | 277 | printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum); |
278 | } | 278 | } |
279 | 279 | ||
280 | static void annotate_sym(struct hist_entry *he) | 280 | static int hist_entry__tty_annotate(struct hist_entry *he) |
281 | { | 281 | { |
282 | struct map *map = he->ms.map; | 282 | struct map *map = he->ms.map; |
283 | struct dso *dso = map->dso; | 283 | struct dso *dso = map->dso; |
@@ -288,7 +288,7 @@ static void annotate_sym(struct hist_entry *he) | |||
288 | struct objdump_line *pos, *n; | 288 | struct objdump_line *pos, *n; |
289 | 289 | ||
290 | if (hist_entry__annotate(he, &head) < 0) | 290 | if (hist_entry__annotate(he, &head) < 0) |
291 | return; | 291 | return -1; |
292 | 292 | ||
293 | if (full_paths) | 293 | if (full_paths) |
294 | d_filename = filename; | 294 | d_filename = filename; |
@@ -317,30 +317,59 @@ static void annotate_sym(struct hist_entry *he) | |||
317 | 317 | ||
318 | if (print_line) | 318 | if (print_line) |
319 | free_source_line(he, len); | 319 | free_source_line(he, len); |
320 | |||
321 | return 0; | ||
320 | } | 322 | } |
321 | 323 | ||
322 | static void hists__find_annotations(struct hists *self) | 324 | static void hists__find_annotations(struct hists *self) |
323 | { | 325 | { |
324 | struct rb_node *nd; | 326 | struct rb_node *first = rb_first(&self->entries), *nd = first; |
327 | int key = KEY_RIGHT; | ||
325 | 328 | ||
326 | for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { | 329 | while (nd) { |
327 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); | 330 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); |
328 | struct sym_priv *priv; | 331 | struct sym_priv *priv; |
329 | 332 | ||
330 | if (he->ms.sym == NULL) | 333 | if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) |
331 | continue; | 334 | goto find_next; |
332 | 335 | ||
333 | priv = symbol__priv(he->ms.sym); | 336 | priv = symbol__priv(he->ms.sym); |
334 | if (priv->hist == NULL) | 337 | if (priv->hist == NULL) { |
338 | find_next: | ||
339 | if (key == KEY_LEFT) | ||
340 | nd = rb_prev(nd); | ||
341 | else | ||
342 | nd = rb_next(nd); | ||
335 | continue; | 343 | continue; |
344 | } | ||
336 | 345 | ||
337 | annotate_sym(he); | 346 | if (use_browser) { |
338 | /* | 347 | key = hist_entry__tui_annotate(he); |
339 | * Since we have a hist_entry per IP for the same symbol, free | 348 | if (is_exit_key(key)) |
340 | * he->ms.sym->hist to signal we already processed this symbol. | 349 | break; |
341 | */ | 350 | switch (key) { |
342 | free(priv->hist); | 351 | case KEY_RIGHT: |
343 | priv->hist = NULL; | 352 | case '\t': |
353 | nd = rb_next(nd); | ||
354 | break; | ||
355 | case KEY_LEFT: | ||
356 | if (nd == first) | ||
357 | continue; | ||
358 | nd = rb_prev(nd); | ||
359 | default: | ||
360 | break; | ||
361 | } | ||
362 | } else { | ||
363 | hist_entry__tty_annotate(he); | ||
364 | nd = rb_next(nd); | ||
365 | /* | ||
366 | * Since we have a hist_entry per IP for the same | ||
367 | * symbol, free he->ms.sym->hist to signal we already | ||
368 | * processed this symbol. | ||
369 | */ | ||
370 | free(priv->hist); | ||
371 | priv->hist = NULL; | ||
372 | } | ||
344 | } | 373 | } |
345 | } | 374 | } |
346 | 375 | ||
@@ -416,6 +445,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) | |||
416 | { | 445 | { |
417 | argc = parse_options(argc, argv, options, annotate_usage, 0); | 446 | argc = parse_options(argc, argv, options, annotate_usage, 0); |
418 | 447 | ||
448 | setup_browser(); | ||
449 | |||
419 | symbol_conf.priv_size = sizeof(struct sym_priv); | 450 | symbol_conf.priv_size = sizeof(struct sym_priv); |
420 | symbol_conf.try_vmlinux_path = true; | 451 | symbol_conf.try_vmlinux_path = true; |
421 | 452 | ||
@@ -435,8 +466,6 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) | |||
435 | sym_hist_filter = argv[0]; | 466 | sym_hist_filter = argv[0]; |
436 | } | 467 | } |
437 | 468 | ||
438 | setup_pager(); | ||
439 | |||
440 | if (field_sep && *field_sep == '.') { | 469 | if (field_sep && *field_sep == '.') { |
441 | pr_err("'.' is the only non valid --field-separator argument\n"); | 470 | pr_err("'.' is the only non valid --field-separator argument\n"); |
442 | return -1; | 471 | return -1; |