diff options
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 87 |
1 files changed, 55 insertions, 32 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 377971dc89a3..fc3d55f832ac 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -59,7 +59,7 @@ | |||
59 | 59 | ||
60 | #include <sys/syscall.h> | 60 | #include <sys/syscall.h> |
61 | #include <sys/ioctl.h> | 61 | #include <sys/ioctl.h> |
62 | #include <sys/poll.h> | 62 | #include <poll.h> |
63 | #include <sys/prctl.h> | 63 | #include <sys/prctl.h> |
64 | #include <sys/wait.h> | 64 | #include <sys/wait.h> |
65 | #include <sys/uio.h> | 65 | #include <sys/uio.h> |
@@ -276,11 +276,17 @@ static void perf_top__print_sym_table(struct perf_top *top) | |||
276 | return; | 276 | return; |
277 | } | 277 | } |
278 | 278 | ||
279 | if (top->zero) { | ||
280 | hists__delete_entries(&top->sym_evsel->hists); | ||
281 | } else { | ||
282 | hists__decay_entries(&top->sym_evsel->hists, | ||
283 | top->hide_user_symbols, | ||
284 | top->hide_kernel_symbols); | ||
285 | } | ||
286 | |||
279 | hists__collapse_resort(&top->sym_evsel->hists, NULL); | 287 | hists__collapse_resort(&top->sym_evsel->hists, NULL); |
280 | hists__output_resort(&top->sym_evsel->hists); | 288 | hists__output_resort(&top->sym_evsel->hists); |
281 | hists__decay_entries(&top->sym_evsel->hists, | 289 | |
282 | top->hide_user_symbols, | ||
283 | top->hide_kernel_symbols); | ||
284 | hists__output_recalc_col_len(&top->sym_evsel->hists, | 290 | hists__output_recalc_col_len(&top->sym_evsel->hists, |
285 | top->print_entries - printed); | 291 | top->print_entries - printed); |
286 | putchar('\n'); | 292 | putchar('\n'); |
@@ -427,18 +433,13 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) | |||
427 | 433 | ||
428 | if (!perf_top__key_mapped(top, c)) { | 434 | if (!perf_top__key_mapped(top, c)) { |
429 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 435 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
430 | struct termios tc, save; | 436 | struct termios save; |
431 | 437 | ||
432 | perf_top__print_mapped_keys(top); | 438 | perf_top__print_mapped_keys(top); |
433 | fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); | 439 | fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); |
434 | fflush(stdout); | 440 | fflush(stdout); |
435 | 441 | ||
436 | tcgetattr(0, &save); | 442 | set_term_quiet_input(&save); |
437 | tc = save; | ||
438 | tc.c_lflag &= ~(ICANON | ECHO); | ||
439 | tc.c_cc[VMIN] = 0; | ||
440 | tc.c_cc[VTIME] = 0; | ||
441 | tcsetattr(0, TCSANOW, &tc); | ||
442 | 443 | ||
443 | poll(&stdin_poll, 1, -1); | 444 | poll(&stdin_poll, 1, -1); |
444 | c = getc(stdin); | 445 | c = getc(stdin); |
@@ -542,11 +543,16 @@ static void perf_top__sort_new_samples(void *arg) | |||
542 | if (t->evlist->selected != NULL) | 543 | if (t->evlist->selected != NULL) |
543 | t->sym_evsel = t->evlist->selected; | 544 | t->sym_evsel = t->evlist->selected; |
544 | 545 | ||
546 | if (t->zero) { | ||
547 | hists__delete_entries(&t->sym_evsel->hists); | ||
548 | } else { | ||
549 | hists__decay_entries(&t->sym_evsel->hists, | ||
550 | t->hide_user_symbols, | ||
551 | t->hide_kernel_symbols); | ||
552 | } | ||
553 | |||
545 | hists__collapse_resort(&t->sym_evsel->hists, NULL); | 554 | hists__collapse_resort(&t->sym_evsel->hists, NULL); |
546 | hists__output_resort(&t->sym_evsel->hists); | 555 | hists__output_resort(&t->sym_evsel->hists); |
547 | hists__decay_entries(&t->sym_evsel->hists, | ||
548 | t->hide_user_symbols, | ||
549 | t->hide_kernel_symbols); | ||
550 | } | 556 | } |
551 | 557 | ||
552 | static void *display_thread_tui(void *arg) | 558 | static void *display_thread_tui(void *arg) |
@@ -577,23 +583,32 @@ static void *display_thread_tui(void *arg) | |||
577 | return NULL; | 583 | return NULL; |
578 | } | 584 | } |
579 | 585 | ||
586 | static void display_sig(int sig __maybe_unused) | ||
587 | { | ||
588 | done = 1; | ||
589 | } | ||
590 | |||
591 | static void display_setup_sig(void) | ||
592 | { | ||
593 | signal(SIGSEGV, display_sig); | ||
594 | signal(SIGFPE, display_sig); | ||
595 | signal(SIGINT, display_sig); | ||
596 | signal(SIGQUIT, display_sig); | ||
597 | signal(SIGTERM, display_sig); | ||
598 | } | ||
599 | |||
580 | static void *display_thread(void *arg) | 600 | static void *display_thread(void *arg) |
581 | { | 601 | { |
582 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 602 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
583 | struct termios tc, save; | 603 | struct termios save; |
584 | struct perf_top *top = arg; | 604 | struct perf_top *top = arg; |
585 | int delay_msecs, c; | 605 | int delay_msecs, c; |
586 | 606 | ||
587 | tcgetattr(0, &save); | 607 | display_setup_sig(); |
588 | tc = save; | ||
589 | tc.c_lflag &= ~(ICANON | ECHO); | ||
590 | tc.c_cc[VMIN] = 0; | ||
591 | tc.c_cc[VTIME] = 0; | ||
592 | |||
593 | pthread__unblock_sigwinch(); | 608 | pthread__unblock_sigwinch(); |
594 | repeat: | 609 | repeat: |
595 | delay_msecs = top->delay_secs * 1000; | 610 | delay_msecs = top->delay_secs * 1000; |
596 | tcsetattr(0, TCSANOW, &tc); | 611 | set_term_quiet_input(&save); |
597 | /* trash return*/ | 612 | /* trash return*/ |
598 | getc(stdin); | 613 | getc(stdin); |
599 | 614 | ||
@@ -620,13 +635,16 @@ repeat: | |||
620 | } | 635 | } |
621 | } | 636 | } |
622 | 637 | ||
638 | tcsetattr(0, TCSAFLUSH, &save); | ||
623 | return NULL; | 639 | return NULL; |
624 | } | 640 | } |
625 | 641 | ||
626 | static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) | 642 | static int symbol_filter(struct map *map, struct symbol *sym) |
627 | { | 643 | { |
628 | const char *name = sym->name; | 644 | const char *name = sym->name; |
629 | 645 | ||
646 | if (!map->dso->kernel) | ||
647 | return 0; | ||
630 | /* | 648 | /* |
631 | * ppc64 uses function descriptors and appends a '.' to the | 649 | * ppc64 uses function descriptors and appends a '.' to the |
632 | * start of every instruction address. Remove it. | 650 | * start of every instruction address. Remove it. |
@@ -876,7 +894,7 @@ try_again: | |||
876 | 894 | ||
877 | if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { | 895 | if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { |
878 | ui__error("Failed to mmap with %d (%s)\n", | 896 | ui__error("Failed to mmap with %d (%s)\n", |
879 | errno, strerror(errno)); | 897 | errno, strerror_r(errno, msg, sizeof(msg))); |
880 | goto out_err; | 898 | goto out_err; |
881 | } | 899 | } |
882 | 900 | ||
@@ -911,7 +929,7 @@ static int __cmd_top(struct perf_top *top) | |||
911 | 929 | ||
912 | top->session = perf_session__new(NULL, false, NULL); | 930 | top->session = perf_session__new(NULL, false, NULL); |
913 | if (top->session == NULL) | 931 | if (top->session == NULL) |
914 | return -ENOMEM; | 932 | return -1; |
915 | 933 | ||
916 | machines__set_symbol_filter(&top->session->machines, symbol_filter); | 934 | machines__set_symbol_filter(&top->session->machines, symbol_filter); |
917 | 935 | ||
@@ -946,7 +964,7 @@ static int __cmd_top(struct perf_top *top) | |||
946 | perf_evlist__enable(top->evlist); | 964 | perf_evlist__enable(top->evlist); |
947 | 965 | ||
948 | /* Wait for a minimal set of events before starting the snapshot */ | 966 | /* Wait for a minimal set of events before starting the snapshot */ |
949 | poll(top->evlist->pollfd, top->evlist->nr_fds, 100); | 967 | perf_evlist__poll(top->evlist, 100); |
950 | 968 | ||
951 | perf_top__mmap_read(top); | 969 | perf_top__mmap_read(top); |
952 | 970 | ||
@@ -963,7 +981,7 @@ static int __cmd_top(struct perf_top *top) | |||
963 | param.sched_priority = top->realtime_prio; | 981 | param.sched_priority = top->realtime_prio; |
964 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { | 982 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { |
965 | ui__error("Could not set realtime priority.\n"); | 983 | ui__error("Could not set realtime priority.\n"); |
966 | goto out_delete; | 984 | goto out_join; |
967 | } | 985 | } |
968 | } | 986 | } |
969 | 987 | ||
@@ -973,10 +991,12 @@ static int __cmd_top(struct perf_top *top) | |||
973 | perf_top__mmap_read(top); | 991 | perf_top__mmap_read(top); |
974 | 992 | ||
975 | if (hits == top->samples) | 993 | if (hits == top->samples) |
976 | ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); | 994 | ret = perf_evlist__poll(top->evlist, 100); |
977 | } | 995 | } |
978 | 996 | ||
979 | ret = 0; | 997 | ret = 0; |
998 | out_join: | ||
999 | pthread_join(thread, NULL); | ||
980 | out_delete: | 1000 | out_delete: |
981 | perf_session__delete(top->session); | 1001 | perf_session__delete(top->session); |
982 | top->session = NULL; | 1002 | top->session = NULL; |
@@ -1000,10 +1020,8 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) | |||
1000 | 1020 | ||
1001 | static int perf_top_config(const char *var, const char *value, void *cb) | 1021 | static int perf_top_config(const char *var, const char *value, void *cb) |
1002 | { | 1022 | { |
1003 | struct perf_top *top = cb; | ||
1004 | |||
1005 | if (!strcmp(var, "top.call-graph")) | 1023 | if (!strcmp(var, "top.call-graph")) |
1006 | return record_parse_callchain(value, &top->record_opts); | 1024 | var = "call-graph.record-mode"; /* fall-through */ |
1007 | if (!strcmp(var, "top.children")) { | 1025 | if (!strcmp(var, "top.children")) { |
1008 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); | 1026 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); |
1009 | return 0; | 1027 | return 0; |
@@ -1122,6 +1140,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1122 | "Interleave source code with assembly code (default)"), | 1140 | "Interleave source code with assembly code (default)"), |
1123 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, | 1141 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, |
1124 | "Display raw encoding of assembly instructions (default)"), | 1142 | "Display raw encoding of assembly instructions (default)"), |
1143 | OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, | ||
1144 | "Enable kernel symbol demangling"), | ||
1125 | OPT_STRING(0, "objdump", &objdump_path, "path", | 1145 | OPT_STRING(0, "objdump", &objdump_path, "path", |
1126 | "objdump binary to use for disassembly and annotations"), | 1146 | "objdump binary to use for disassembly and annotations"), |
1127 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | 1147 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", |
@@ -1131,6 +1151,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1131 | "Don't show entries under that percent", parse_percent_limit), | 1151 | "Don't show entries under that percent", parse_percent_limit), |
1132 | OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", | 1152 | OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", |
1133 | "How to display percentage of filtered entries", parse_filter_percentage), | 1153 | "How to display percentage of filtered entries", parse_filter_percentage), |
1154 | OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, | ||
1155 | "width[,width...]", | ||
1156 | "don't try to adjust column width, use these fixed values"), | ||
1134 | OPT_END() | 1157 | OPT_END() |
1135 | }; | 1158 | }; |
1136 | const char * const top_usage[] = { | 1159 | const char * const top_usage[] = { |
@@ -1217,7 +1240,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1217 | symbol_conf.priv_size = sizeof(struct annotation); | 1240 | symbol_conf.priv_size = sizeof(struct annotation); |
1218 | 1241 | ||
1219 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); | 1242 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); |
1220 | if (symbol__init() < 0) | 1243 | if (symbol__init(NULL) < 0) |
1221 | return -1; | 1244 | return -1; |
1222 | 1245 | ||
1223 | sort__setup_elide(stdout); | 1246 | sort__setup_elide(stdout); |