aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-top.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r--tools/perf/builtin-top.c135
1 files changed, 83 insertions, 52 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 377971dc89a3..0aa7747ff139 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>
@@ -251,6 +251,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
251 char bf[160]; 251 char bf[160];
252 int printed = 0; 252 int printed = 0;
253 const int win_width = top->winsize.ws_col - 1; 253 const int win_width = top->winsize.ws_col - 1;
254 struct hists *hists = evsel__hists(top->sym_evsel);
254 255
255 puts(CONSOLE_CLEAR); 256 puts(CONSOLE_CLEAR);
256 257
@@ -261,13 +262,13 @@ static void perf_top__print_sym_table(struct perf_top *top)
261 262
262 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 263 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
263 264
264 if (top->sym_evsel->hists.stats.nr_lost_warned != 265 if (hists->stats.nr_lost_warned !=
265 top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { 266 hists->stats.nr_events[PERF_RECORD_LOST]) {
266 top->sym_evsel->hists.stats.nr_lost_warned = 267 hists->stats.nr_lost_warned =
267 top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; 268 hists->stats.nr_events[PERF_RECORD_LOST];
268 color_fprintf(stdout, PERF_COLOR_RED, 269 color_fprintf(stdout, PERF_COLOR_RED,
269 "WARNING: LOST %d chunks, Check IO/CPU overload", 270 "WARNING: LOST %d chunks, Check IO/CPU overload",
270 top->sym_evsel->hists.stats.nr_lost_warned); 271 hists->stats.nr_lost_warned);
271 ++printed; 272 ++printed;
272 } 273 }
273 274
@@ -276,16 +277,19 @@ static void perf_top__print_sym_table(struct perf_top *top)
276 return; 277 return;
277 } 278 }
278 279
279 hists__collapse_resort(&top->sym_evsel->hists, NULL); 280 if (top->zero) {
280 hists__output_resort(&top->sym_evsel->hists); 281 hists__delete_entries(hists);
281 hists__decay_entries(&top->sym_evsel->hists, 282 } else {
282 top->hide_user_symbols, 283 hists__decay_entries(hists, top->hide_user_symbols,
283 top->hide_kernel_symbols); 284 top->hide_kernel_symbols);
284 hists__output_recalc_col_len(&top->sym_evsel->hists, 285 }
285 top->print_entries - printed); 286
287 hists__collapse_resort(hists, NULL);
288 hists__output_resort(hists);
289
290 hists__output_recalc_col_len(hists, top->print_entries - printed);
286 putchar('\n'); 291 putchar('\n');
287 hists__fprintf(&top->sym_evsel->hists, false, 292 hists__fprintf(hists, false, top->print_entries - printed, win_width,
288 top->print_entries - printed, win_width,
289 top->min_percent, stdout); 293 top->min_percent, stdout);
290} 294}
291 295
@@ -328,6 +332,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
328{ 332{
329 char *buf = malloc(0), *p; 333 char *buf = malloc(0), *p;
330 struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL; 334 struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL;
335 struct hists *hists = evsel__hists(top->sym_evsel);
331 struct rb_node *next; 336 struct rb_node *next;
332 size_t dummy = 0; 337 size_t dummy = 0;
333 338
@@ -345,7 +350,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
345 if (p) 350 if (p)
346 *p = 0; 351 *p = 0;
347 352
348 next = rb_first(&top->sym_evsel->hists.entries); 353 next = rb_first(&hists->entries);
349 while (next) { 354 while (next) {
350 n = rb_entry(next, struct hist_entry, rb_node); 355 n = rb_entry(next, struct hist_entry, rb_node);
351 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { 356 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
@@ -427,18 +432,13 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
427 432
428 if (!perf_top__key_mapped(top, c)) { 433 if (!perf_top__key_mapped(top, c)) {
429 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 434 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
430 struct termios tc, save; 435 struct termios save;
431 436
432 perf_top__print_mapped_keys(top); 437 perf_top__print_mapped_keys(top);
433 fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); 438 fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
434 fflush(stdout); 439 fflush(stdout);
435 440
436 tcgetattr(0, &save); 441 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 442
443 poll(&stdin_poll, 1, -1); 443 poll(&stdin_poll, 1, -1);
444 c = getc(stdin); 444 c = getc(stdin);
@@ -537,16 +537,24 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
537static void perf_top__sort_new_samples(void *arg) 537static void perf_top__sort_new_samples(void *arg)
538{ 538{
539 struct perf_top *t = arg; 539 struct perf_top *t = arg;
540 struct hists *hists;
541
540 perf_top__reset_sample_counters(t); 542 perf_top__reset_sample_counters(t);
541 543
542 if (t->evlist->selected != NULL) 544 if (t->evlist->selected != NULL)
543 t->sym_evsel = t->evlist->selected; 545 t->sym_evsel = t->evlist->selected;
544 546
545 hists__collapse_resort(&t->sym_evsel->hists, NULL); 547 hists = evsel__hists(t->sym_evsel);
546 hists__output_resort(&t->sym_evsel->hists); 548
547 hists__decay_entries(&t->sym_evsel->hists, 549 if (t->zero) {
548 t->hide_user_symbols, 550 hists__delete_entries(hists);
549 t->hide_kernel_symbols); 551 } else {
552 hists__decay_entries(hists, t->hide_user_symbols,
553 t->hide_kernel_symbols);
554 }
555
556 hists__collapse_resort(hists, NULL);
557 hists__output_resort(hists);
550} 558}
551 559
552static void *display_thread_tui(void *arg) 560static void *display_thread_tui(void *arg)
@@ -567,8 +575,10 @@ static void *display_thread_tui(void *arg)
567 * Zooming in/out UIDs. For now juse use whatever the user passed 575 * Zooming in/out UIDs. For now juse use whatever the user passed
568 * via --uid. 576 * via --uid.
569 */ 577 */
570 evlist__for_each(top->evlist, pos) 578 evlist__for_each(top->evlist, pos) {
571 pos->hists.uid_filter_str = top->record_opts.target.uid_str; 579 struct hists *hists = evsel__hists(pos);
580 hists->uid_filter_str = top->record_opts.target.uid_str;
581 }
572 582
573 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, 583 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
574 &top->session->header.env); 584 &top->session->header.env);
@@ -577,23 +587,32 @@ static void *display_thread_tui(void *arg)
577 return NULL; 587 return NULL;
578} 588}
579 589
590static void display_sig(int sig __maybe_unused)
591{
592 done = 1;
593}
594
595static void display_setup_sig(void)
596{
597 signal(SIGSEGV, display_sig);
598 signal(SIGFPE, display_sig);
599 signal(SIGINT, display_sig);
600 signal(SIGQUIT, display_sig);
601 signal(SIGTERM, display_sig);
602}
603
580static void *display_thread(void *arg) 604static void *display_thread(void *arg)
581{ 605{
582 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 606 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
583 struct termios tc, save; 607 struct termios save;
584 struct perf_top *top = arg; 608 struct perf_top *top = arg;
585 int delay_msecs, c; 609 int delay_msecs, c;
586 610
587 tcgetattr(0, &save); 611 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(); 612 pthread__unblock_sigwinch();
594repeat: 613repeat:
595 delay_msecs = top->delay_secs * 1000; 614 delay_msecs = top->delay_secs * 1000;
596 tcsetattr(0, TCSANOW, &tc); 615 set_term_quiet_input(&save);
597 /* trash return*/ 616 /* trash return*/
598 getc(stdin); 617 getc(stdin);
599 618
@@ -620,13 +639,16 @@ repeat:
620 } 639 }
621 } 640 }
622 641
642 tcsetattr(0, TCSAFLUSH, &save);
623 return NULL; 643 return NULL;
624} 644}
625 645
626static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) 646static int symbol_filter(struct map *map, struct symbol *sym)
627{ 647{
628 const char *name = sym->name; 648 const char *name = sym->name;
629 649
650 if (!map->dso->kernel)
651 return 0;
630 /* 652 /*
631 * ppc64 uses function descriptors and appends a '.' to the 653 * ppc64 uses function descriptors and appends a '.' to the
632 * start of every instruction address. Remove it. 654 * start of every instruction address. Remove it.
@@ -750,6 +772,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
750 } 772 }
751 773
752 if (al.sym == NULL || !al.sym->ignore) { 774 if (al.sym == NULL || !al.sym->ignore) {
775 struct hists *hists = evsel__hists(evsel);
753 struct hist_entry_iter iter = { 776 struct hist_entry_iter iter = {
754 .add_entry_cb = hist_iter__top_callback, 777 .add_entry_cb = hist_iter__top_callback,
755 }; 778 };
@@ -759,14 +782,14 @@ static void perf_event__process_sample(struct perf_tool *tool,
759 else 782 else
760 iter.ops = &hist_iter_normal; 783 iter.ops = &hist_iter_normal;
761 784
762 pthread_mutex_lock(&evsel->hists.lock); 785 pthread_mutex_lock(&hists->lock);
763 786
764 err = hist_entry_iter__add(&iter, &al, evsel, sample, 787 err = hist_entry_iter__add(&iter, &al, evsel, sample,
765 top->max_stack, top); 788 top->max_stack, top);
766 if (err < 0) 789 if (err < 0)
767 pr_err("Problem incrementing symbol period, skipping event\n"); 790 pr_err("Problem incrementing symbol period, skipping event\n");
768 791
769 pthread_mutex_unlock(&evsel->hists.lock); 792 pthread_mutex_unlock(&hists->lock);
770 } 793 }
771 794
772 return; 795 return;
@@ -831,7 +854,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
831 perf_event__process_sample(&top->tool, event, evsel, 854 perf_event__process_sample(&top->tool, event, evsel,
832 &sample, machine); 855 &sample, machine);
833 } else if (event->header.type < PERF_RECORD_MAX) { 856 } else if (event->header.type < PERF_RECORD_MAX) {
834 hists__inc_nr_events(&evsel->hists, event->header.type); 857 hists__inc_nr_events(evsel__hists(evsel), event->header.type);
835 machine__process_event(machine, event, &sample); 858 machine__process_event(machine, event, &sample);
836 } else 859 } else
837 ++session->stats.nr_unknown_events; 860 ++session->stats.nr_unknown_events;
@@ -876,7 +899,7 @@ try_again:
876 899
877 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { 900 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
878 ui__error("Failed to mmap with %d (%s)\n", 901 ui__error("Failed to mmap with %d (%s)\n",
879 errno, strerror(errno)); 902 errno, strerror_r(errno, msg, sizeof(msg)));
880 goto out_err; 903 goto out_err;
881 } 904 }
882 905
@@ -911,7 +934,7 @@ static int __cmd_top(struct perf_top *top)
911 934
912 top->session = perf_session__new(NULL, false, NULL); 935 top->session = perf_session__new(NULL, false, NULL);
913 if (top->session == NULL) 936 if (top->session == NULL)
914 return -ENOMEM; 937 return -1;
915 938
916 machines__set_symbol_filter(&top->session->machines, symbol_filter); 939 machines__set_symbol_filter(&top->session->machines, symbol_filter);
917 940
@@ -946,7 +969,7 @@ static int __cmd_top(struct perf_top *top)
946 perf_evlist__enable(top->evlist); 969 perf_evlist__enable(top->evlist);
947 970
948 /* Wait for a minimal set of events before starting the snapshot */ 971 /* Wait for a minimal set of events before starting the snapshot */
949 poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 972 perf_evlist__poll(top->evlist, 100);
950 973
951 perf_top__mmap_read(top); 974 perf_top__mmap_read(top);
952 975
@@ -963,7 +986,7 @@ static int __cmd_top(struct perf_top *top)
963 param.sched_priority = top->realtime_prio; 986 param.sched_priority = top->realtime_prio;
964 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 987 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
965 ui__error("Could not set realtime priority.\n"); 988 ui__error("Could not set realtime priority.\n");
966 goto out_delete; 989 goto out_join;
967 } 990 }
968 } 991 }
969 992
@@ -973,10 +996,12 @@ static int __cmd_top(struct perf_top *top)
973 perf_top__mmap_read(top); 996 perf_top__mmap_read(top);
974 997
975 if (hits == top->samples) 998 if (hits == top->samples)
976 ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 999 ret = perf_evlist__poll(top->evlist, 100);
977 } 1000 }
978 1001
979 ret = 0; 1002 ret = 0;
1003out_join:
1004 pthread_join(thread, NULL);
980out_delete: 1005out_delete:
981 perf_session__delete(top->session); 1006 perf_session__delete(top->session);
982 top->session = NULL; 1007 top->session = NULL;
@@ -1000,10 +1025,8 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1000 1025
1001static int perf_top_config(const char *var, const char *value, void *cb) 1026static int perf_top_config(const char *var, const char *value, void *cb)
1002{ 1027{
1003 struct perf_top *top = cb;
1004
1005 if (!strcmp(var, "top.call-graph")) 1028 if (!strcmp(var, "top.call-graph"))
1006 return record_parse_callchain(value, &top->record_opts); 1029 var = "call-graph.record-mode"; /* fall-through */
1007 if (!strcmp(var, "top.children")) { 1030 if (!strcmp(var, "top.children")) {
1008 symbol_conf.cumulate_callchain = perf_config_bool(var, value); 1031 symbol_conf.cumulate_callchain = perf_config_bool(var, value);
1009 return 0; 1032 return 0;
@@ -1024,7 +1047,6 @@ parse_percent_limit(const struct option *opt, const char *arg,
1024 1047
1025int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) 1048int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1026{ 1049{
1027 int status = -1;
1028 char errbuf[BUFSIZ]; 1050 char errbuf[BUFSIZ];
1029 struct perf_top top = { 1051 struct perf_top top = {
1030 .count_filter = 5, 1052 .count_filter = 5,
@@ -1122,6 +1144,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1122 "Interleave source code with assembly code (default)"), 1144 "Interleave source code with assembly code (default)"),
1123 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, 1145 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
1124 "Display raw encoding of assembly instructions (default)"), 1146 "Display raw encoding of assembly instructions (default)"),
1147 OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
1148 "Enable kernel symbol demangling"),
1125 OPT_STRING(0, "objdump", &objdump_path, "path", 1149 OPT_STRING(0, "objdump", &objdump_path, "path",
1126 "objdump binary to use for disassembly and annotations"), 1150 "objdump binary to use for disassembly and annotations"),
1127 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1151 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
@@ -1131,12 +1155,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1131 "Don't show entries under that percent", parse_percent_limit), 1155 "Don't show entries under that percent", parse_percent_limit),
1132 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", 1156 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
1133 "How to display percentage of filtered entries", parse_filter_percentage), 1157 "How to display percentage of filtered entries", parse_filter_percentage),
1158 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
1159 "width[,width...]",
1160 "don't try to adjust column width, use these fixed values"),
1134 OPT_END() 1161 OPT_END()
1135 }; 1162 };
1136 const char * const top_usage[] = { 1163 const char * const top_usage[] = {
1137 "perf top [<options>]", 1164 "perf top [<options>]",
1138 NULL 1165 NULL
1139 }; 1166 };
1167 int status = hists__init();
1168
1169 if (status < 0)
1170 return status;
1140 1171
1141 top.evlist = perf_evlist__new(); 1172 top.evlist = perf_evlist__new();
1142 if (top.evlist == NULL) 1173 if (top.evlist == NULL)
@@ -1217,7 +1248,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1217 symbol_conf.priv_size = sizeof(struct annotation); 1248 symbol_conf.priv_size = sizeof(struct annotation);
1218 1249
1219 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1250 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1220 if (symbol__init() < 0) 1251 if (symbol__init(NULL) < 0)
1221 return -1; 1252 return -1;
1222 1253
1223 sort__setup_elide(stdout); 1254 sort__setup_elide(stdout);