aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-05-22 10:25:40 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-05-22 10:25:40 -0400
commit46e3e055ce69a00d735e458445ab1d24718ff751 (patch)
tree06829420acf27f2deb05ac6ccc230268bf271318 /tools
parent6e78c9fd1bc2c7e04b3d7052e9eb27aa536e4e2c (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')
-rw-r--r--tools/perf/builtin-annotate.c61
-rw-r--r--tools/perf/builtin-report.c4
-rw-r--r--tools/perf/util/hist.c13
-rw-r--r--tools/perf/util/hist.h10
-rw-r--r--tools/perf/util/newt.c56
-rw-r--r--tools/perf/util/util.h15
6 files changed, 112 insertions, 47 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
280static void annotate_sym(struct hist_entry *he) 280static 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
322static void hists__find_annotations(struct hists *self) 324static 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) {
338find_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;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 2c39bd358975..a7b8760e401c 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -484,9 +484,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
484{ 484{
485 argc = parse_options(argc, argv, options, report_usage, 0); 485 argc = parse_options(argc, argv, options, report_usage, 0);
486 486
487 if (dump_trace) 487 if (strcmp(input_name, "-") != 0)
488 setup_pager();
489 else if (strcmp(input_name, "-") != 0)
490 setup_browser(); 488 setup_browser();
491 /* 489 /*
492 * Only in the newt browser we are doing integrated annotation, 490 * Only in the newt browser we are doing integrated annotation,
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 009ad76b0879..682a6d88862c 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -992,14 +992,14 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
992 char *filename = dso__build_id_filename(dso, NULL, 0); 992 char *filename = dso__build_id_filename(dso, NULL, 0);
993 char command[PATH_MAX * 2]; 993 char command[PATH_MAX * 2];
994 FILE *file; 994 FILE *file;
995 int err = -1; 995 int err = 0;
996 u64 len; 996 u64 len;
997 997
998 if (filename == NULL) { 998 if (filename == NULL) {
999 if (dso->has_build_id) { 999 if (dso->has_build_id) {
1000 pr_err("Can't annotate %s: not enough memory\n", 1000 pr_err("Can't annotate %s: not enough memory\n",
1001 sym->name); 1001 sym->name);
1002 return -1; 1002 return -ENOMEM;
1003 } 1003 }
1004 /* 1004 /*
1005 * If we don't have build-ids, well, lets hope that this 1005 * If we don't have build-ids, well, lets hope that this
@@ -1009,14 +1009,12 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
1009 } 1009 }
1010 1010
1011 if (dso->origin == DSO__ORIG_KERNEL) { 1011 if (dso->origin == DSO__ORIG_KERNEL) {
1012 if (dso->annotate_warned) { 1012 if (dso->annotate_warned)
1013 err = 0;
1014 goto out_free_filename; 1013 goto out_free_filename;
1015 } 1014 err = -ENOENT;
1016 dso->annotate_warned = 1; 1015 dso->annotate_warned = 1;
1017 pr_err("Can't annotate %s: No vmlinux file was found in the " 1016 pr_err("Can't annotate %s: No vmlinux file was found in the "
1018 "path:\n", sym->name); 1017 "path\n", sym->name);
1019 vmlinux_path__fprintf(stderr);
1020 goto out_free_filename; 1018 goto out_free_filename;
1021 } 1019 }
1022 1020
@@ -1046,7 +1044,6 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
1046 break; 1044 break;
1047 1045
1048 pclose(file); 1046 pclose(file);
1049 err = 0;
1050out_free_filename: 1047out_free_filename:
1051 if (dso->has_build_id) 1048 if (dso->has_build_id)
1052 free(filename); 1049 free(filename);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 6f17dcd8412c..2d5203fedb20 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -102,8 +102,18 @@ static inline int hists__browse(struct hists *self __used,
102{ 102{
103 return 0; 103 return 0;
104} 104}
105static inline int hist_entry__tui_annotate(struct hist_entry *self __used)
106{
107 return 0;
108}
109#define KEY_LEFT -1
110#define KEY_RIGHT -2
105#else 111#else
112#include <newt.h>
106int hists__browse(struct hists *self, const char *helpline, 113int hists__browse(struct hists *self, const char *helpline,
107 const char *input_name); 114 const char *input_name);
115int hist_entry__tui_annotate(struct hist_entry *self);
116#define KEY_LEFT NEWT_KEY_LEFT
117#define KEY_RIGHT NEWT_KEY_RIGHT
108#endif 118#endif
109#endif /* __PERF_HIST_H */ 119#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
index c65838c99354..ffd04720b754 100644
--- a/tools/perf/util/newt.c
+++ b/tools/perf/util/newt.c
@@ -235,6 +235,15 @@ static bool dialog_yesno(const char *msg)
235 return newtWinChoice(NULL, yes, no, (char *)msg) == 1; 235 return newtWinChoice(NULL, yes, no, (char *)msg) == 1;
236} 236}
237 237
238static void ui__error_window(const char *fmt, ...)
239{
240 va_list ap;
241
242 va_start(ap, fmt);
243 newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap);
244 va_end(ap);
245}
246
238#define HE_COLORSET_TOP 50 247#define HE_COLORSET_TOP 50
239#define HE_COLORSET_MEDIUM 51 248#define HE_COLORSET_MEDIUM 51
240#define HE_COLORSET_NORMAL 52 249#define HE_COLORSET_NORMAL 52
@@ -386,6 +395,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
386 newtFormAddHotKey(self->form, ' '); 395 newtFormAddHotKey(self->form, ' ');
387 newtFormAddHotKey(self->form, NEWT_KEY_HOME); 396 newtFormAddHotKey(self->form, NEWT_KEY_HOME);
388 newtFormAddHotKey(self->form, NEWT_KEY_END); 397 newtFormAddHotKey(self->form, NEWT_KEY_END);
398 newtFormAddHotKey(self->form, NEWT_KEY_TAB);
399 newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
389 400
390 if (ui_browser__refresh_entries(self) < 0) 401 if (ui_browser__refresh_entries(self) < 0)
391 return -1; 402 return -1;
@@ -398,6 +409,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
398 409
399 if (es->reason != NEWT_EXIT_HOTKEY) 410 if (es->reason != NEWT_EXIT_HOTKEY)
400 break; 411 break;
412 if (is_exit_key(es->u.key))
413 return es->u.key;
401 switch (es->u.key) { 414 switch (es->u.key) {
402 case NEWT_KEY_DOWN: 415 case NEWT_KEY_DOWN:
403 if (self->index == self->nr_entries - 1) 416 if (self->index == self->nr_entries - 1)
@@ -471,12 +484,10 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
471 } 484 }
472 } 485 }
473 break; 486 break;
474 case NEWT_KEY_ESCAPE: 487 case NEWT_KEY_RIGHT:
475 case NEWT_KEY_LEFT: 488 case NEWT_KEY_LEFT:
476 case CTRL('c'): 489 case NEWT_KEY_TAB:
477 case 'Q': 490 return es->u.key;
478 case 'q':
479 return 0;
480 default: 491 default:
481 continue; 492 continue;
482 } 493 }
@@ -668,18 +679,24 @@ static size_t hist_entry__append_browser(struct hist_entry *self,
668 return ret; 679 return ret;
669} 680}
670 681
671static void hist_entry__annotate_browser(struct hist_entry *self) 682int hist_entry__tui_annotate(struct hist_entry *self)
672{ 683{
673 struct ui_browser browser; 684 struct ui_browser browser;
674 struct newtExitStruct es; 685 struct newtExitStruct es;
675 struct objdump_line *pos, *n; 686 struct objdump_line *pos, *n;
676 LIST_HEAD(head); 687 LIST_HEAD(head);
688 int ret;
677 689
678 if (self->ms.sym == NULL) 690 if (self->ms.sym == NULL)
679 return; 691 return -1;
680 692
681 if (hist_entry__annotate(self, &head) < 0) 693 if (self->ms.map->dso->annotate_warned)
682 return; 694 return -1;
695
696 if (hist_entry__annotate(self, &head) < 0) {
697 ui__error_window(browser__last_msg);
698 return -1;
699 }
683 700
684 ui_helpline__push("Press <- or ESC to exit"); 701 ui_helpline__push("Press <- or ESC to exit");
685 702
@@ -694,7 +711,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self)
694 } 711 }
695 712
696 browser.width += 18; /* Percentage */ 713 browser.width += 18; /* Percentage */
697 ui_browser__run(&browser, self->ms.sym->name, &es); 714 ret = ui_browser__run(&browser, self->ms.sym->name, &es);
698 newtFormDestroy(browser.form); 715 newtFormDestroy(browser.form);
699 newtPopWindow(); 716 newtPopWindow();
700 list_for_each_entry_safe(pos, n, &head, node) { 717 list_for_each_entry_safe(pos, n, &head, node) {
@@ -702,6 +719,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self)
702 objdump_line__free(pos); 719 objdump_line__free(pos);
703 } 720 }
704 ui_helpline__pop(); 721 ui_helpline__pop();
722 return ret;
705} 723}
706 724
707static const void *newt__symbol_tree_get_current(newtComponent self) 725static const void *newt__symbol_tree_get_current(newtComponent self)
@@ -935,14 +953,14 @@ do_help:
935 continue; 953 continue;
936 default:; 954 default:;
937 } 955 }
938 if (toupper(es.u.key) == 'Q' || 956 if (is_exit_key(es.u.key)) {
939 es.u.key == CTRL('c')) 957 if (es.u.key == NEWT_KEY_ESCAPE) {
940 break; 958 if (dialog_yesno("Do you really want to exit?"))
941 if (es.u.key == NEWT_KEY_ESCAPE) { 959 break;
942 if (dialog_yesno("Do you really want to exit?")) 960 else
961 continue;
962 } else
943 break; 963 break;
944 else
945 continue;
946 } 964 }
947 965
948 if (es.u.key == NEWT_KEY_LEFT) { 966 if (es.u.key == NEWT_KEY_LEFT) {
@@ -1006,7 +1024,7 @@ do_annotate:
1006 if (he == NULL) 1024 if (he == NULL)
1007 continue; 1025 continue;
1008 1026
1009 hist_entry__annotate_browser(he); 1027 hist_entry__tui_annotate(he);
1010 } else if (choice == zoom_dso) { 1028 } else if (choice == zoom_dso) {
1011zoom_dso: 1029zoom_dso:
1012 if (dso_filter) { 1030 if (dso_filter) {
@@ -1074,7 +1092,7 @@ void setup_browser(void)
1074{ 1092{
1075 struct newtPercentTreeColors *c = &defaultPercentTreeColors; 1093 struct newtPercentTreeColors *c = &defaultPercentTreeColors;
1076 1094
1077 if (!isatty(1) || !use_browser) { 1095 if (!isatty(1) || !use_browser || dump_trace) {
1078 setup_pager(); 1096 setup_pager();
1079 return; 1097 return;
1080 } 1098 }
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 45b9655f3a5c..4e8b6b0c551c 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -81,7 +81,7 @@
81#include <inttypes.h> 81#include <inttypes.h>
82#include "../../../include/linux/magic.h" 82#include "../../../include/linux/magic.h"
83#include "types.h" 83#include "types.h"
84 84#include <sys/ttydefaults.h>
85 85
86#ifndef NO_ICONV 86#ifndef NO_ICONV
87#include <iconv.h> 87#include <iconv.h>
@@ -263,6 +263,19 @@ bool strglobmatch(const char *str, const char *pat);
263bool strlazymatch(const char *str, const char *pat); 263bool strlazymatch(const char *str, const char *pat);
264unsigned long convert_unit(unsigned long value, char *unit); 264unsigned long convert_unit(unsigned long value, char *unit);
265 265
266#ifndef ESC
267#define ESC 27
268#endif
269
270static inline bool is_exit_key(int key)
271{
272 char up;
273 if (key == CTRL('c') || key == ESC)
274 return true;
275 up = toupper(key);
276 return up == 'Q';
277}
278
266#define _STR(x) #x 279#define _STR(x) #x
267#define STR(x) _STR(x) 280#define STR(x) _STR(x)
268 281