diff options
| -rw-r--r-- | tools/perf/builtin-annotate.c | 61 | ||||
| -rw-r--r-- | tools/perf/builtin-report.c | 4 | ||||
| -rw-r--r-- | tools/perf/util/hist.c | 13 | ||||
| -rw-r--r-- | tools/perf/util/hist.h | 10 | ||||
| -rw-r--r-- | tools/perf/util/newt.c | 56 | ||||
| -rw-r--r-- | tools/perf/util/util.h | 15 |
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 | ||
| 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; |
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; | ||
| 1050 | out_free_filename: | 1047 | out_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 | } |
| 105 | static 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> | ||
| 106 | int hists__browse(struct hists *self, const char *helpline, | 113 | int hists__browse(struct hists *self, const char *helpline, |
| 107 | const char *input_name); | 114 | const char *input_name); |
| 115 | int 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 | ||
| 238 | static 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 | ||
| 671 | static void hist_entry__annotate_browser(struct hist_entry *self) | 682 | int 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 | ||
| 707 | static const void *newt__symbol_tree_get_current(newtComponent self) | 725 | static 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) { |
| 1011 | zoom_dso: | 1029 | zoom_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); | |||
| 263 | bool strlazymatch(const char *str, const char *pat); | 263 | bool strlazymatch(const char *str, const char *pat); |
| 264 | unsigned long convert_unit(unsigned long value, char *unit); | 264 | unsigned long convert_unit(unsigned long value, char *unit); |
| 265 | 265 | ||
| 266 | #ifndef ESC | ||
| 267 | #define ESC 27 | ||
| 268 | #endif | ||
| 269 | |||
| 270 | static 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 | ||
