diff options
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 372 |
1 files changed, 115 insertions, 257 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c9ff3950cd4b..72f6eb7b4173 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -68,27 +68,7 @@ | |||
68 | #include <linux/unistd.h> | 68 | #include <linux/unistd.h> |
69 | #include <linux/types.h> | 69 | #include <linux/types.h> |
70 | 70 | ||
71 | void get_term_dimensions(struct winsize *ws) | 71 | static volatile int done; |
72 | { | ||
73 | char *s = getenv("LINES"); | ||
74 | |||
75 | if (s != NULL) { | ||
76 | ws->ws_row = atoi(s); | ||
77 | s = getenv("COLUMNS"); | ||
78 | if (s != NULL) { | ||
79 | ws->ws_col = atoi(s); | ||
80 | if (ws->ws_row && ws->ws_col) | ||
81 | return; | ||
82 | } | ||
83 | } | ||
84 | #ifdef TIOCGWINSZ | ||
85 | if (ioctl(1, TIOCGWINSZ, ws) == 0 && | ||
86 | ws->ws_row && ws->ws_col) | ||
87 | return; | ||
88 | #endif | ||
89 | ws->ws_row = 25; | ||
90 | ws->ws_col = 80; | ||
91 | } | ||
92 | 72 | ||
93 | static void perf_top__update_print_entries(struct perf_top *top) | 73 | static void perf_top__update_print_entries(struct perf_top *top) |
94 | { | 74 | { |
@@ -453,8 +433,10 @@ static int perf_top__key_mapped(struct perf_top *top, int c) | |||
453 | return 0; | 433 | return 0; |
454 | } | 434 | } |
455 | 435 | ||
456 | static void perf_top__handle_keypress(struct perf_top *top, int c) | 436 | static bool perf_top__handle_keypress(struct perf_top *top, int c) |
457 | { | 437 | { |
438 | bool ret = true; | ||
439 | |||
458 | if (!perf_top__key_mapped(top, c)) { | 440 | if (!perf_top__key_mapped(top, c)) { |
459 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 441 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
460 | struct termios tc, save; | 442 | struct termios tc, save; |
@@ -475,7 +457,7 @@ static void perf_top__handle_keypress(struct perf_top *top, int c) | |||
475 | 457 | ||
476 | tcsetattr(0, TCSAFLUSH, &save); | 458 | tcsetattr(0, TCSAFLUSH, &save); |
477 | if (!perf_top__key_mapped(top, c)) | 459 | if (!perf_top__key_mapped(top, c)) |
478 | return; | 460 | return ret; |
479 | } | 461 | } |
480 | 462 | ||
481 | switch (c) { | 463 | switch (c) { |
@@ -537,7 +519,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c) | |||
537 | printf("exiting.\n"); | 519 | printf("exiting.\n"); |
538 | if (top->dump_symtab) | 520 | if (top->dump_symtab) |
539 | perf_session__fprintf_dsos(top->session, stderr); | 521 | perf_session__fprintf_dsos(top->session, stderr); |
540 | exit(0); | 522 | ret = false; |
523 | break; | ||
541 | case 's': | 524 | case 's': |
542 | perf_top__prompt_symbol(top, "Enter details symbol"); | 525 | perf_top__prompt_symbol(top, "Enter details symbol"); |
543 | break; | 526 | break; |
@@ -560,6 +543,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c) | |||
560 | default: | 543 | default: |
561 | break; | 544 | break; |
562 | } | 545 | } |
546 | |||
547 | return ret; | ||
563 | } | 548 | } |
564 | 549 | ||
565 | static void perf_top__sort_new_samples(void *arg) | 550 | static void perf_top__sort_new_samples(void *arg) |
@@ -596,13 +581,12 @@ static void *display_thread_tui(void *arg) | |||
596 | * via --uid. | 581 | * via --uid. |
597 | */ | 582 | */ |
598 | list_for_each_entry(pos, &top->evlist->entries, node) | 583 | list_for_each_entry(pos, &top->evlist->entries, node) |
599 | pos->hists.uid_filter_str = top->target.uid_str; | 584 | pos->hists.uid_filter_str = top->record_opts.target.uid_str; |
600 | 585 | ||
601 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, | 586 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, |
602 | &top->session->header.env); | 587 | &top->session->header.env); |
603 | 588 | ||
604 | exit_browser(0); | 589 | done = 1; |
605 | exit(0); | ||
606 | return NULL; | 590 | return NULL; |
607 | } | 591 | } |
608 | 592 | ||
@@ -626,7 +610,7 @@ repeat: | |||
626 | /* trash return*/ | 610 | /* trash return*/ |
627 | getc(stdin); | 611 | getc(stdin); |
628 | 612 | ||
629 | while (1) { | 613 | while (!done) { |
630 | perf_top__print_sym_table(top); | 614 | perf_top__print_sym_table(top); |
631 | /* | 615 | /* |
632 | * Either timeout expired or we got an EINTR due to SIGWINCH, | 616 | * Either timeout expired or we got an EINTR due to SIGWINCH, |
@@ -640,15 +624,14 @@ repeat: | |||
640 | continue; | 624 | continue; |
641 | /* Fall trhu */ | 625 | /* Fall trhu */ |
642 | default: | 626 | default: |
643 | goto process_hotkey; | 627 | c = getc(stdin); |
628 | tcsetattr(0, TCSAFLUSH, &save); | ||
629 | |||
630 | if (perf_top__handle_keypress(top, c)) | ||
631 | goto repeat; | ||
632 | done = 1; | ||
644 | } | 633 | } |
645 | } | 634 | } |
646 | process_hotkey: | ||
647 | c = getc(stdin); | ||
648 | tcsetattr(0, TCSAFLUSH, &save); | ||
649 | |||
650 | perf_top__handle_keypress(top, c); | ||
651 | goto repeat; | ||
652 | 635 | ||
653 | return NULL; | 636 | return NULL; |
654 | } | 637 | } |
@@ -716,7 +699,7 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
716 | static struct intlist *seen; | 699 | static struct intlist *seen; |
717 | 700 | ||
718 | if (!seen) | 701 | if (!seen) |
719 | seen = intlist__new(); | 702 | seen = intlist__new(NULL); |
720 | 703 | ||
721 | if (!intlist__has_entry(seen, event->ip.pid)) { | 704 | if (!intlist__has_entry(seen, event->ip.pid)) { |
722 | pr_err("Can't find guest [%d]'s kernel information\n", | 705 | pr_err("Can't find guest [%d]'s kernel information\n", |
@@ -727,8 +710,8 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
727 | } | 710 | } |
728 | 711 | ||
729 | if (!machine) { | 712 | if (!machine) { |
730 | pr_err("%u unprocessable samples recorded.", | 713 | pr_err("%u unprocessable samples recorded.\r", |
731 | top->session->hists.stats.nr_unprocessable_samples++); | 714 | top->session->stats.nr_unprocessable_samples++); |
732 | return; | 715 | return; |
733 | } | 716 | } |
734 | 717 | ||
@@ -847,13 +830,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
847 | ++top->us_samples; | 830 | ++top->us_samples; |
848 | if (top->hide_user_symbols) | 831 | if (top->hide_user_symbols) |
849 | continue; | 832 | continue; |
850 | machine = perf_session__find_host_machine(session); | 833 | machine = &session->machines.host; |
851 | break; | 834 | break; |
852 | case PERF_RECORD_MISC_KERNEL: | 835 | case PERF_RECORD_MISC_KERNEL: |
853 | ++top->kernel_samples; | 836 | ++top->kernel_samples; |
854 | if (top->hide_kernel_symbols) | 837 | if (top->hide_kernel_symbols) |
855 | continue; | 838 | continue; |
856 | machine = perf_session__find_host_machine(session); | 839 | machine = &session->machines.host; |
857 | break; | 840 | break; |
858 | case PERF_RECORD_MISC_GUEST_KERNEL: | 841 | case PERF_RECORD_MISC_GUEST_KERNEL: |
859 | ++top->guest_kernel_samples; | 842 | ++top->guest_kernel_samples; |
@@ -878,7 +861,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
878 | hists__inc_nr_events(&evsel->hists, event->header.type); | 861 | hists__inc_nr_events(&evsel->hists, event->header.type); |
879 | machine__process_event(machine, event); | 862 | machine__process_event(machine, event); |
880 | } else | 863 | } else |
881 | ++session->hists.stats.nr_unknown_events; | 864 | ++session->stats.nr_unknown_events; |
882 | } | 865 | } |
883 | } | 866 | } |
884 | 867 | ||
@@ -890,123 +873,42 @@ static void perf_top__mmap_read(struct perf_top *top) | |||
890 | perf_top__mmap_read_idx(top, i); | 873 | perf_top__mmap_read_idx(top, i); |
891 | } | 874 | } |
892 | 875 | ||
893 | static void perf_top__start_counters(struct perf_top *top) | 876 | static int perf_top__start_counters(struct perf_top *top) |
894 | { | 877 | { |
878 | char msg[512]; | ||
895 | struct perf_evsel *counter; | 879 | struct perf_evsel *counter; |
896 | struct perf_evlist *evlist = top->evlist; | 880 | struct perf_evlist *evlist = top->evlist; |
881 | struct perf_record_opts *opts = &top->record_opts; | ||
897 | 882 | ||
898 | if (top->group) | 883 | perf_evlist__config(evlist, opts); |
899 | perf_evlist__set_leader(evlist); | ||
900 | 884 | ||
901 | list_for_each_entry(counter, &evlist->entries, node) { | 885 | list_for_each_entry(counter, &evlist->entries, node) { |
902 | struct perf_event_attr *attr = &counter->attr; | ||
903 | |||
904 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | ||
905 | |||
906 | if (top->freq) { | ||
907 | attr->sample_type |= PERF_SAMPLE_PERIOD; | ||
908 | attr->freq = 1; | ||
909 | attr->sample_freq = top->freq; | ||
910 | } | ||
911 | |||
912 | if (evlist->nr_entries > 1) { | ||
913 | attr->sample_type |= PERF_SAMPLE_ID; | ||
914 | attr->read_format |= PERF_FORMAT_ID; | ||
915 | } | ||
916 | |||
917 | if (perf_target__has_cpu(&top->target)) | ||
918 | attr->sample_type |= PERF_SAMPLE_CPU; | ||
919 | |||
920 | if (symbol_conf.use_callchain) | ||
921 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
922 | |||
923 | attr->mmap = 1; | ||
924 | attr->comm = 1; | ||
925 | attr->inherit = top->inherit; | ||
926 | fallback_missing_features: | ||
927 | if (top->exclude_guest_missing) | ||
928 | attr->exclude_guest = attr->exclude_host = 0; | ||
929 | retry_sample_id: | ||
930 | attr->sample_id_all = top->sample_id_all_missing ? 0 : 1; | ||
931 | try_again: | 886 | try_again: |
932 | if (perf_evsel__open(counter, top->evlist->cpus, | 887 | if (perf_evsel__open(counter, top->evlist->cpus, |
933 | top->evlist->threads) < 0) { | 888 | top->evlist->threads) < 0) { |
934 | int err = errno; | 889 | if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { |
935 | |||
936 | if (err == EPERM || err == EACCES) { | ||
937 | ui__error_paranoid(); | ||
938 | goto out_err; | ||
939 | } else if (err == EINVAL) { | ||
940 | if (!top->exclude_guest_missing && | ||
941 | (attr->exclude_guest || attr->exclude_host)) { | ||
942 | pr_debug("Old kernel, cannot exclude " | ||
943 | "guest or host samples.\n"); | ||
944 | top->exclude_guest_missing = true; | ||
945 | goto fallback_missing_features; | ||
946 | } else if (!top->sample_id_all_missing) { | ||
947 | /* | ||
948 | * Old kernel, no attr->sample_id_type_all field | ||
949 | */ | ||
950 | top->sample_id_all_missing = true; | ||
951 | goto retry_sample_id; | ||
952 | } | ||
953 | } | ||
954 | /* | ||
955 | * If it's cycles then fall back to hrtimer | ||
956 | * based cpu-clock-tick sw counter, which | ||
957 | * is always available even if no PMU support: | ||
958 | */ | ||
959 | if ((err == ENOENT || err == ENXIO) && | ||
960 | (attr->type == PERF_TYPE_HARDWARE) && | ||
961 | (attr->config == PERF_COUNT_HW_CPU_CYCLES)) { | ||
962 | |||
963 | if (verbose) | 890 | if (verbose) |
964 | ui__warning("Cycles event not supported,\n" | 891 | ui__warning("%s\n", msg); |
965 | "trying to fall back to cpu-clock-ticks\n"); | ||
966 | |||
967 | attr->type = PERF_TYPE_SOFTWARE; | ||
968 | attr->config = PERF_COUNT_SW_CPU_CLOCK; | ||
969 | if (counter->name) { | ||
970 | free(counter->name); | ||
971 | counter->name = NULL; | ||
972 | } | ||
973 | goto try_again; | 892 | goto try_again; |
974 | } | 893 | } |
975 | 894 | ||
976 | if (err == ENOENT) { | 895 | perf_evsel__open_strerror(counter, &opts->target, |
977 | ui__error("The %s event is not supported.\n", | 896 | errno, msg, sizeof(msg)); |
978 | perf_evsel__name(counter)); | 897 | ui__error("%s\n", msg); |
979 | goto out_err; | ||
980 | } else if (err == EMFILE) { | ||
981 | ui__error("Too many events are opened.\n" | ||
982 | "Try again after reducing the number of events\n"); | ||
983 | goto out_err; | ||
984 | } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) { | ||
985 | ui__error("\'precise\' request may not be supported. " | ||
986 | "Try removing 'p' modifier\n"); | ||
987 | goto out_err; | ||
988 | } | ||
989 | |||
990 | ui__error("The sys_perf_event_open() syscall " | ||
991 | "returned with %d (%s). /bin/dmesg " | ||
992 | "may provide additional information.\n" | ||
993 | "No CONFIG_PERF_EVENTS=y kernel support " | ||
994 | "configured?\n", err, strerror(err)); | ||
995 | goto out_err; | 898 | goto out_err; |
996 | } | 899 | } |
997 | } | 900 | } |
998 | 901 | ||
999 | if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { | 902 | if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { |
1000 | ui__error("Failed to mmap with %d (%s)\n", | 903 | ui__error("Failed to mmap with %d (%s)\n", |
1001 | errno, strerror(errno)); | 904 | errno, strerror(errno)); |
1002 | goto out_err; | 905 | goto out_err; |
1003 | } | 906 | } |
1004 | 907 | ||
1005 | return; | 908 | return 0; |
1006 | 909 | ||
1007 | out_err: | 910 | out_err: |
1008 | exit_browser(0); | 911 | return -1; |
1009 | exit(0); | ||
1010 | } | 912 | } |
1011 | 913 | ||
1012 | static int perf_top__setup_sample_type(struct perf_top *top) | 914 | static int perf_top__setup_sample_type(struct perf_top *top) |
@@ -1016,7 +918,7 @@ static int perf_top__setup_sample_type(struct perf_top *top) | |||
1016 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); | 918 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); |
1017 | return -EINVAL; | 919 | return -EINVAL; |
1018 | } | 920 | } |
1019 | } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { | 921 | } else if (callchain_param.mode != CHAIN_NONE) { |
1020 | if (callchain_register_param(&callchain_param) < 0) { | 922 | if (callchain_register_param(&callchain_param) < 0) { |
1021 | ui__error("Can't register callchain params.\n"); | 923 | ui__error("Can't register callchain params.\n"); |
1022 | return -EINVAL; | 924 | return -EINVAL; |
@@ -1028,6 +930,7 @@ static int perf_top__setup_sample_type(struct perf_top *top) | |||
1028 | 930 | ||
1029 | static int __cmd_top(struct perf_top *top) | 931 | static int __cmd_top(struct perf_top *top) |
1030 | { | 932 | { |
933 | struct perf_record_opts *opts = &top->record_opts; | ||
1031 | pthread_t thread; | 934 | pthread_t thread; |
1032 | int ret; | 935 | int ret; |
1033 | /* | 936 | /* |
@@ -1042,26 +945,42 @@ static int __cmd_top(struct perf_top *top) | |||
1042 | if (ret) | 945 | if (ret) |
1043 | goto out_delete; | 946 | goto out_delete; |
1044 | 947 | ||
1045 | if (perf_target__has_task(&top->target)) | 948 | if (perf_target__has_task(&opts->target)) |
1046 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, | 949 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, |
1047 | perf_event__process, | 950 | perf_event__process, |
1048 | &top->session->host_machine); | 951 | &top->session->machines.host); |
1049 | else | 952 | else |
1050 | perf_event__synthesize_threads(&top->tool, perf_event__process, | 953 | perf_event__synthesize_threads(&top->tool, perf_event__process, |
1051 | &top->session->host_machine); | 954 | &top->session->machines.host); |
1052 | perf_top__start_counters(top); | 955 | |
956 | ret = perf_top__start_counters(top); | ||
957 | if (ret) | ||
958 | goto out_delete; | ||
959 | |||
1053 | top->session->evlist = top->evlist; | 960 | top->session->evlist = top->evlist; |
1054 | perf_session__set_id_hdr_size(top->session); | 961 | perf_session__set_id_hdr_size(top->session); |
1055 | 962 | ||
963 | /* | ||
964 | * When perf is starting the traced process, all the events (apart from | ||
965 | * group members) have enable_on_exec=1 set, so don't spoil it by | ||
966 | * prematurely enabling them. | ||
967 | * | ||
968 | * XXX 'top' still doesn't start workloads like record, trace, but should, | ||
969 | * so leave the check here. | ||
970 | */ | ||
971 | if (!perf_target__none(&opts->target)) | ||
972 | perf_evlist__enable(top->evlist); | ||
973 | |||
1056 | /* Wait for a minimal set of events before starting the snapshot */ | 974 | /* Wait for a minimal set of events before starting the snapshot */ |
1057 | poll(top->evlist->pollfd, top->evlist->nr_fds, 100); | 975 | poll(top->evlist->pollfd, top->evlist->nr_fds, 100); |
1058 | 976 | ||
1059 | perf_top__mmap_read(top); | 977 | perf_top__mmap_read(top); |
1060 | 978 | ||
979 | ret = -1; | ||
1061 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : | 980 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : |
1062 | display_thread), top)) { | 981 | display_thread), top)) { |
1063 | ui__error("Could not create display thread.\n"); | 982 | ui__error("Could not create display thread.\n"); |
1064 | exit(-1); | 983 | goto out_delete; |
1065 | } | 984 | } |
1066 | 985 | ||
1067 | if (top->realtime_prio) { | 986 | if (top->realtime_prio) { |
@@ -1070,11 +989,11 @@ static int __cmd_top(struct perf_top *top) | |||
1070 | param.sched_priority = top->realtime_prio; | 989 | param.sched_priority = top->realtime_prio; |
1071 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { | 990 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { |
1072 | ui__error("Could not set realtime priority.\n"); | 991 | ui__error("Could not set realtime priority.\n"); |
1073 | exit(-1); | 992 | goto out_delete; |
1074 | } | 993 | } |
1075 | } | 994 | } |
1076 | 995 | ||
1077 | while (1) { | 996 | while (!done) { |
1078 | u64 hits = top->samples; | 997 | u64 hits = top->samples; |
1079 | 998 | ||
1080 | perf_top__mmap_read(top); | 999 | perf_top__mmap_read(top); |
@@ -1083,126 +1002,67 @@ static int __cmd_top(struct perf_top *top) | |||
1083 | ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); | 1002 | ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); |
1084 | } | 1003 | } |
1085 | 1004 | ||
1005 | ret = 0; | ||
1086 | out_delete: | 1006 | out_delete: |
1087 | perf_session__delete(top->session); | 1007 | perf_session__delete(top->session); |
1088 | top->session = NULL; | 1008 | top->session = NULL; |
1089 | 1009 | ||
1090 | return 0; | 1010 | return ret; |
1091 | } | 1011 | } |
1092 | 1012 | ||
1093 | static int | 1013 | static int |
1094 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 1014 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
1095 | { | 1015 | { |
1096 | struct perf_top *top = (struct perf_top *)opt->value; | ||
1097 | char *tok, *tok2; | ||
1098 | char *endptr; | ||
1099 | |||
1100 | /* | 1016 | /* |
1101 | * --no-call-graph | 1017 | * --no-call-graph |
1102 | */ | 1018 | */ |
1103 | if (unset) { | 1019 | if (unset) |
1104 | top->dont_use_callchains = true; | ||
1105 | return 0; | 1020 | return 0; |
1106 | } | ||
1107 | 1021 | ||
1108 | symbol_conf.use_callchain = true; | 1022 | symbol_conf.use_callchain = true; |
1109 | 1023 | ||
1110 | if (!arg) | 1024 | return record_parse_callchain_opt(opt, arg, unset); |
1111 | return 0; | ||
1112 | |||
1113 | tok = strtok((char *)arg, ","); | ||
1114 | if (!tok) | ||
1115 | return -1; | ||
1116 | |||
1117 | /* get the output mode */ | ||
1118 | if (!strncmp(tok, "graph", strlen(arg))) | ||
1119 | callchain_param.mode = CHAIN_GRAPH_ABS; | ||
1120 | |||
1121 | else if (!strncmp(tok, "flat", strlen(arg))) | ||
1122 | callchain_param.mode = CHAIN_FLAT; | ||
1123 | |||
1124 | else if (!strncmp(tok, "fractal", strlen(arg))) | ||
1125 | callchain_param.mode = CHAIN_GRAPH_REL; | ||
1126 | |||
1127 | else if (!strncmp(tok, "none", strlen(arg))) { | ||
1128 | callchain_param.mode = CHAIN_NONE; | ||
1129 | symbol_conf.use_callchain = false; | ||
1130 | |||
1131 | return 0; | ||
1132 | } else | ||
1133 | return -1; | ||
1134 | |||
1135 | /* get the min percentage */ | ||
1136 | tok = strtok(NULL, ","); | ||
1137 | if (!tok) | ||
1138 | goto setup; | ||
1139 | |||
1140 | callchain_param.min_percent = strtod(tok, &endptr); | ||
1141 | if (tok == endptr) | ||
1142 | return -1; | ||
1143 | |||
1144 | /* get the print limit */ | ||
1145 | tok2 = strtok(NULL, ","); | ||
1146 | if (!tok2) | ||
1147 | goto setup; | ||
1148 | |||
1149 | if (tok2[0] != 'c') { | ||
1150 | callchain_param.print_limit = strtod(tok2, &endptr); | ||
1151 | tok2 = strtok(NULL, ","); | ||
1152 | if (!tok2) | ||
1153 | goto setup; | ||
1154 | } | ||
1155 | |||
1156 | /* get the call chain order */ | ||
1157 | if (!strcmp(tok2, "caller")) | ||
1158 | callchain_param.order = ORDER_CALLER; | ||
1159 | else if (!strcmp(tok2, "callee")) | ||
1160 | callchain_param.order = ORDER_CALLEE; | ||
1161 | else | ||
1162 | return -1; | ||
1163 | setup: | ||
1164 | if (callchain_register_param(&callchain_param) < 0) { | ||
1165 | fprintf(stderr, "Can't register callchain params\n"); | ||
1166 | return -1; | ||
1167 | } | ||
1168 | return 0; | ||
1169 | } | 1025 | } |
1170 | 1026 | ||
1171 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | 1027 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) |
1172 | { | 1028 | { |
1173 | struct perf_evsel *pos; | ||
1174 | int status; | 1029 | int status; |
1175 | char errbuf[BUFSIZ]; | 1030 | char errbuf[BUFSIZ]; |
1176 | struct perf_top top = { | 1031 | struct perf_top top = { |
1177 | .count_filter = 5, | 1032 | .count_filter = 5, |
1178 | .delay_secs = 2, | 1033 | .delay_secs = 2, |
1179 | .freq = 4000, /* 4 KHz */ | 1034 | .record_opts = { |
1180 | .mmap_pages = 128, | 1035 | .mmap_pages = UINT_MAX, |
1181 | .sym_pcnt_filter = 5, | 1036 | .user_freq = UINT_MAX, |
1182 | .target = { | 1037 | .user_interval = ULLONG_MAX, |
1183 | .uses_mmap = true, | 1038 | .freq = 4000, /* 4 KHz */ |
1039 | .target = { | ||
1040 | .uses_mmap = true, | ||
1041 | }, | ||
1184 | }, | 1042 | }, |
1043 | .sym_pcnt_filter = 5, | ||
1185 | }; | 1044 | }; |
1186 | char callchain_default_opt[] = "fractal,0.5,callee"; | 1045 | struct perf_record_opts *opts = &top.record_opts; |
1046 | struct perf_target *target = &opts->target; | ||
1187 | const struct option options[] = { | 1047 | const struct option options[] = { |
1188 | OPT_CALLBACK('e', "event", &top.evlist, "event", | 1048 | OPT_CALLBACK('e', "event", &top.evlist, "event", |
1189 | "event selector. use 'perf list' to list available events", | 1049 | "event selector. use 'perf list' to list available events", |
1190 | parse_events_option), | 1050 | parse_events_option), |
1191 | OPT_INTEGER('c', "count", &top.default_interval, | 1051 | OPT_U64('c', "count", &opts->user_interval, "event period to sample"), |
1192 | "event period to sample"), | 1052 | OPT_STRING('p', "pid", &target->pid, "pid", |
1193 | OPT_STRING('p', "pid", &top.target.pid, "pid", | ||
1194 | "profile events on existing process id"), | 1053 | "profile events on existing process id"), |
1195 | OPT_STRING('t', "tid", &top.target.tid, "tid", | 1054 | OPT_STRING('t', "tid", &target->tid, "tid", |
1196 | "profile events on existing thread id"), | 1055 | "profile events on existing thread id"), |
1197 | OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide, | 1056 | OPT_BOOLEAN('a', "all-cpus", &target->system_wide, |
1198 | "system-wide collection from all CPUs"), | 1057 | "system-wide collection from all CPUs"), |
1199 | OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu", | 1058 | OPT_STRING('C', "cpu", &target->cpu_list, "cpu", |
1200 | "list of cpus to monitor"), | 1059 | "list of cpus to monitor"), |
1201 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 1060 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
1202 | "file", "vmlinux pathname"), | 1061 | "file", "vmlinux pathname"), |
1203 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, | 1062 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, |
1204 | "hide kernel symbols"), | 1063 | "hide kernel symbols"), |
1205 | OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"), | 1064 | OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages, |
1065 | "number of mmap data pages"), | ||
1206 | OPT_INTEGER('r', "realtime", &top.realtime_prio, | 1066 | OPT_INTEGER('r', "realtime", &top.realtime_prio, |
1207 | "collect data with this RT SCHED_FIFO priority"), | 1067 | "collect data with this RT SCHED_FIFO priority"), |
1208 | OPT_INTEGER('d', "delay", &top.delay_secs, | 1068 | OPT_INTEGER('d', "delay", &top.delay_secs, |
@@ -1211,16 +1071,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1211 | "dump the symbol table used for profiling"), | 1071 | "dump the symbol table used for profiling"), |
1212 | OPT_INTEGER('f', "count-filter", &top.count_filter, | 1072 | OPT_INTEGER('f', "count-filter", &top.count_filter, |
1213 | "only display functions with more events than this"), | 1073 | "only display functions with more events than this"), |
1214 | OPT_BOOLEAN('g', "group", &top.group, | 1074 | OPT_BOOLEAN('g', "group", &opts->group, |
1215 | "put the counters into a counter group"), | 1075 | "put the counters into a counter group"), |
1216 | OPT_BOOLEAN('i', "inherit", &top.inherit, | 1076 | OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, |
1217 | "child tasks inherit counters"), | 1077 | "child tasks do not inherit counters"), |
1218 | OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", | 1078 | OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", |
1219 | "symbol to annotate"), | 1079 | "symbol to annotate"), |
1220 | OPT_BOOLEAN('z', "zero", &top.zero, | 1080 | OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"), |
1221 | "zero history across updates"), | 1081 | OPT_UINTEGER('F', "freq", &opts->user_freq, "profile at this frequency"), |
1222 | OPT_INTEGER('F', "freq", &top.freq, | ||
1223 | "profile at this frequency"), | ||
1224 | OPT_INTEGER('E', "entries", &top.print_entries, | 1082 | OPT_INTEGER('E', "entries", &top.print_entries, |
1225 | "display this many functions"), | 1083 | "display this many functions"), |
1226 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, | 1084 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, |
@@ -1233,10 +1091,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1233 | "sort by key(s): pid, comm, dso, symbol, parent"), | 1091 | "sort by key(s): pid, comm, dso, symbol, parent"), |
1234 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | 1092 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, |
1235 | "Show a column with the number of samples"), | 1093 | "Show a column with the number of samples"), |
1236 | OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order", | 1094 | OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, |
1237 | "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " | 1095 | "mode[,dump_size]", record_callchain_help, |
1238 | "Default: fractal,0.5,callee", &parse_callchain_opt, | 1096 | &parse_callchain_opt, "fp"), |
1239 | callchain_default_opt), | ||
1240 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, | 1097 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, |
1241 | "Show a column with the sum of periods"), | 1098 | "Show a column with the sum of periods"), |
1242 | OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", | 1099 | OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", |
@@ -1251,7 +1108,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1251 | "Display raw encoding of assembly instructions (default)"), | 1108 | "Display raw encoding of assembly instructions (default)"), |
1252 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | 1109 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", |
1253 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | 1110 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
1254 | OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), | 1111 | OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), |
1255 | OPT_END() | 1112 | OPT_END() |
1256 | }; | 1113 | }; |
1257 | const char * const top_usage[] = { | 1114 | const char * const top_usage[] = { |
@@ -1272,7 +1129,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1272 | if (sort_order == default_sort_order) | 1129 | if (sort_order == default_sort_order) |
1273 | sort_order = "dso,symbol"; | 1130 | sort_order = "dso,symbol"; |
1274 | 1131 | ||
1275 | setup_sorting(top_usage, options); | 1132 | if (setup_sorting() < 0) |
1133 | usage_with_options(top_usage, options); | ||
1276 | 1134 | ||
1277 | if (top.use_stdio) | 1135 | if (top.use_stdio) |
1278 | use_browser = 0; | 1136 | use_browser = 0; |
@@ -1281,33 +1139,33 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1281 | 1139 | ||
1282 | setup_browser(false); | 1140 | setup_browser(false); |
1283 | 1141 | ||
1284 | status = perf_target__validate(&top.target); | 1142 | status = perf_target__validate(target); |
1285 | if (status) { | 1143 | if (status) { |
1286 | perf_target__strerror(&top.target, status, errbuf, BUFSIZ); | 1144 | perf_target__strerror(target, status, errbuf, BUFSIZ); |
1287 | ui__warning("%s", errbuf); | 1145 | ui__warning("%s", errbuf); |
1288 | } | 1146 | } |
1289 | 1147 | ||
1290 | status = perf_target__parse_uid(&top.target); | 1148 | status = perf_target__parse_uid(target); |
1291 | if (status) { | 1149 | if (status) { |
1292 | int saved_errno = errno; | 1150 | int saved_errno = errno; |
1293 | 1151 | ||
1294 | perf_target__strerror(&top.target, status, errbuf, BUFSIZ); | 1152 | perf_target__strerror(target, status, errbuf, BUFSIZ); |
1295 | ui__error("%s", errbuf); | 1153 | ui__error("%s", errbuf); |
1296 | 1154 | ||
1297 | status = -saved_errno; | 1155 | status = -saved_errno; |
1298 | goto out_delete_evlist; | 1156 | goto out_delete_evlist; |
1299 | } | 1157 | } |
1300 | 1158 | ||
1301 | if (perf_target__none(&top.target)) | 1159 | if (perf_target__none(target)) |
1302 | top.target.system_wide = true; | 1160 | target->system_wide = true; |
1303 | 1161 | ||
1304 | if (perf_evlist__create_maps(top.evlist, &top.target) < 0) | 1162 | if (perf_evlist__create_maps(top.evlist, target) < 0) |
1305 | usage_with_options(top_usage, options); | 1163 | usage_with_options(top_usage, options); |
1306 | 1164 | ||
1307 | if (!top.evlist->nr_entries && | 1165 | if (!top.evlist->nr_entries && |
1308 | perf_evlist__add_default(top.evlist) < 0) { | 1166 | perf_evlist__add_default(top.evlist) < 0) { |
1309 | ui__error("Not enough memory for event selector list\n"); | 1167 | ui__error("Not enough memory for event selector list\n"); |
1310 | return -ENOMEM; | 1168 | goto out_delete_maps; |
1311 | } | 1169 | } |
1312 | 1170 | ||
1313 | symbol_conf.nr_events = top.evlist->nr_entries; | 1171 | symbol_conf.nr_events = top.evlist->nr_entries; |
@@ -1315,24 +1173,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1315 | if (top.delay_secs < 1) | 1173 | if (top.delay_secs < 1) |
1316 | top.delay_secs = 1; | 1174 | top.delay_secs = 1; |
1317 | 1175 | ||
1176 | if (opts->user_interval != ULLONG_MAX) | ||
1177 | opts->default_interval = opts->user_interval; | ||
1178 | if (opts->user_freq != UINT_MAX) | ||
1179 | opts->freq = opts->user_freq; | ||
1180 | |||
1318 | /* | 1181 | /* |
1319 | * User specified count overrides default frequency. | 1182 | * User specified count overrides default frequency. |
1320 | */ | 1183 | */ |
1321 | if (top.default_interval) | 1184 | if (opts->default_interval) |
1322 | top.freq = 0; | 1185 | opts->freq = 0; |
1323 | else if (top.freq) { | 1186 | else if (opts->freq) { |
1324 | top.default_interval = top.freq; | 1187 | opts->default_interval = opts->freq; |
1325 | } else { | 1188 | } else { |
1326 | ui__error("frequency and count are zero, aborting\n"); | 1189 | ui__error("frequency and count are zero, aborting\n"); |
1327 | exit(EXIT_FAILURE); | 1190 | status = -EINVAL; |
1328 | } | 1191 | goto out_delete_maps; |
1329 | |||
1330 | list_for_each_entry(pos, &top.evlist->entries, node) { | ||
1331 | /* | ||
1332 | * Fill in the ones not specifically initialized via -c: | ||
1333 | */ | ||
1334 | if (!pos->attr.sample_period) | ||
1335 | pos->attr.sample_period = top.default_interval; | ||
1336 | } | 1192 | } |
1337 | 1193 | ||
1338 | top.sym_evsel = perf_evlist__first(top.evlist); | 1194 | top.sym_evsel = perf_evlist__first(top.evlist); |
@@ -1365,6 +1221,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1365 | 1221 | ||
1366 | status = __cmd_top(&top); | 1222 | status = __cmd_top(&top); |
1367 | 1223 | ||
1224 | out_delete_maps: | ||
1225 | perf_evlist__delete_maps(top.evlist); | ||
1368 | out_delete_evlist: | 1226 | out_delete_evlist: |
1369 | perf_evlist__delete(top.evlist); | 1227 | perf_evlist__delete(top.evlist); |
1370 | 1228 | ||