diff options
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 122 |
1 files changed, 58 insertions, 64 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 212214162bb2..71e6402729a8 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -246,10 +246,10 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, | |||
246 | struct hist_entry *he; | 246 | struct hist_entry *he; |
247 | 247 | ||
248 | pthread_mutex_lock(&evsel->hists.lock); | 248 | pthread_mutex_lock(&evsel->hists.lock); |
249 | he = __hists__add_entry(&evsel->hists, al, NULL, sample->period, | 249 | he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, |
250 | sample->weight); | 250 | sample->period, sample->weight, |
251 | sample->transaction); | ||
251 | pthread_mutex_unlock(&evsel->hists.lock); | 252 | pthread_mutex_unlock(&evsel->hists.lock); |
252 | |||
253 | if (he == NULL) | 253 | if (he == NULL) |
254 | return NULL; | 254 | return NULL; |
255 | 255 | ||
@@ -287,7 +287,7 @@ static void perf_top__print_sym_table(struct perf_top *top) | |||
287 | return; | 287 | return; |
288 | } | 288 | } |
289 | 289 | ||
290 | hists__collapse_resort(&top->sym_evsel->hists); | 290 | hists__collapse_resort(&top->sym_evsel->hists, NULL); |
291 | hists__output_resort(&top->sym_evsel->hists); | 291 | hists__output_resort(&top->sym_evsel->hists); |
292 | hists__decay_entries(&top->sym_evsel->hists, | 292 | hists__decay_entries(&top->sym_evsel->hists, |
293 | top->hide_user_symbols, | 293 | top->hide_user_symbols, |
@@ -553,7 +553,7 @@ static void perf_top__sort_new_samples(void *arg) | |||
553 | if (t->evlist->selected != NULL) | 553 | if (t->evlist->selected != NULL) |
554 | t->sym_evsel = t->evlist->selected; | 554 | t->sym_evsel = t->evlist->selected; |
555 | 555 | ||
556 | hists__collapse_resort(&t->sym_evsel->hists); | 556 | hists__collapse_resort(&t->sym_evsel->hists, NULL); |
557 | hists__output_resort(&t->sym_evsel->hists); | 557 | hists__output_resort(&t->sym_evsel->hists); |
558 | hists__decay_entries(&t->sym_evsel->hists, | 558 | hists__decay_entries(&t->sym_evsel->hists, |
559 | t->hide_user_symbols, | 559 | t->hide_user_symbols, |
@@ -771,7 +771,8 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
771 | sample->callchain) { | 771 | sample->callchain) { |
772 | err = machine__resolve_callchain(machine, evsel, | 772 | err = machine__resolve_callchain(machine, evsel, |
773 | al.thread, sample, | 773 | al.thread, sample, |
774 | &parent, &al); | 774 | &parent, &al, |
775 | top->max_stack); | ||
775 | if (err) | 776 | if (err) |
776 | return; | 777 | return; |
777 | } | 778 | } |
@@ -810,7 +811,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
810 | ret = perf_evlist__parse_sample(top->evlist, event, &sample); | 811 | ret = perf_evlist__parse_sample(top->evlist, event, &sample); |
811 | if (ret) { | 812 | if (ret) { |
812 | pr_err("Can't parse sample, err = %d\n", ret); | 813 | pr_err("Can't parse sample, err = %d\n", ret); |
813 | continue; | 814 | goto next_event; |
814 | } | 815 | } |
815 | 816 | ||
816 | evsel = perf_evlist__id2evsel(session->evlist, sample.id); | 817 | evsel = perf_evlist__id2evsel(session->evlist, sample.id); |
@@ -825,13 +826,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
825 | case PERF_RECORD_MISC_USER: | 826 | case PERF_RECORD_MISC_USER: |
826 | ++top->us_samples; | 827 | ++top->us_samples; |
827 | if (top->hide_user_symbols) | 828 | if (top->hide_user_symbols) |
828 | continue; | 829 | goto next_event; |
829 | machine = &session->machines.host; | 830 | machine = &session->machines.host; |
830 | break; | 831 | break; |
831 | case PERF_RECORD_MISC_KERNEL: | 832 | case PERF_RECORD_MISC_KERNEL: |
832 | ++top->kernel_samples; | 833 | ++top->kernel_samples; |
833 | if (top->hide_kernel_symbols) | 834 | if (top->hide_kernel_symbols) |
834 | continue; | 835 | goto next_event; |
835 | machine = &session->machines.host; | 836 | machine = &session->machines.host; |
836 | break; | 837 | break; |
837 | case PERF_RECORD_MISC_GUEST_KERNEL: | 838 | case PERF_RECORD_MISC_GUEST_KERNEL: |
@@ -847,7 +848,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
847 | */ | 848 | */ |
848 | /* Fall thru */ | 849 | /* Fall thru */ |
849 | default: | 850 | default: |
850 | continue; | 851 | goto next_event; |
851 | } | 852 | } |
852 | 853 | ||
853 | 854 | ||
@@ -856,9 +857,11 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
856 | &sample, machine); | 857 | &sample, machine); |
857 | } else if (event->header.type < PERF_RECORD_MAX) { | 858 | } else if (event->header.type < PERF_RECORD_MAX) { |
858 | hists__inc_nr_events(&evsel->hists, event->header.type); | 859 | hists__inc_nr_events(&evsel->hists, event->header.type); |
859 | machine__process_event(machine, event); | 860 | machine__process_event(machine, event, &sample); |
860 | } else | 861 | } else |
861 | ++session->stats.nr_unknown_events; | 862 | ++session->stats.nr_unknown_events; |
863 | next_event: | ||
864 | perf_evlist__mmap_consume(top->evlist, idx); | ||
862 | } | 865 | } |
863 | } | 866 | } |
864 | 867 | ||
@@ -930,11 +933,8 @@ static int __cmd_top(struct perf_top *top) | |||
930 | struct perf_record_opts *opts = &top->record_opts; | 933 | struct perf_record_opts *opts = &top->record_opts; |
931 | pthread_t thread; | 934 | pthread_t thread; |
932 | int ret; | 935 | int ret; |
933 | /* | 936 | |
934 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this | 937 | top->session = perf_session__new(NULL, false, NULL); |
935 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. | ||
936 | */ | ||
937 | top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL); | ||
938 | if (top->session == NULL) | 938 | if (top->session == NULL) |
939 | return -ENOMEM; | 939 | return -ENOMEM; |
940 | 940 | ||
@@ -950,14 +950,8 @@ static int __cmd_top(struct perf_top *top) | |||
950 | if (ret) | 950 | if (ret) |
951 | goto out_delete; | 951 | goto out_delete; |
952 | 952 | ||
953 | if (perf_target__has_task(&opts->target)) | 953 | machine__synthesize_threads(&top->session->machines.host, &opts->target, |
954 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, | 954 | top->evlist->threads, false); |
955 | perf_event__process, | ||
956 | &top->session->machines.host); | ||
957 | else | ||
958 | perf_event__synthesize_threads(&top->tool, perf_event__process, | ||
959 | &top->session->machines.host); | ||
960 | |||
961 | ret = perf_top__start_counters(top); | 955 | ret = perf_top__start_counters(top); |
962 | if (ret) | 956 | if (ret) |
963 | goto out_delete; | 957 | goto out_delete; |
@@ -973,7 +967,7 @@ static int __cmd_top(struct perf_top *top) | |||
973 | * XXX 'top' still doesn't start workloads like record, trace, but should, | 967 | * XXX 'top' still doesn't start workloads like record, trace, but should, |
974 | * so leave the check here. | 968 | * so leave the check here. |
975 | */ | 969 | */ |
976 | if (!perf_target__none(&opts->target)) | 970 | if (!target__none(&opts->target)) |
977 | perf_evlist__enable(top->evlist); | 971 | perf_evlist__enable(top->evlist); |
978 | 972 | ||
979 | /* Wait for a minimal set of events before starting the snapshot */ | 973 | /* Wait for a minimal set of events before starting the snapshot */ |
@@ -1016,16 +1010,16 @@ out_delete: | |||
1016 | } | 1010 | } |
1017 | 1011 | ||
1018 | static int | 1012 | static int |
1019 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 1013 | callchain_opt(const struct option *opt, const char *arg, int unset) |
1020 | { | 1014 | { |
1021 | /* | ||
1022 | * --no-call-graph | ||
1023 | */ | ||
1024 | if (unset) | ||
1025 | return 0; | ||
1026 | |||
1027 | symbol_conf.use_callchain = true; | 1015 | symbol_conf.use_callchain = true; |
1016 | return record_callchain_opt(opt, arg, unset); | ||
1017 | } | ||
1028 | 1018 | ||
1019 | static int | ||
1020 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | ||
1021 | { | ||
1022 | symbol_conf.use_callchain = true; | ||
1029 | return record_parse_callchain_opt(opt, arg, unset); | 1023 | return record_parse_callchain_opt(opt, arg, unset); |
1030 | } | 1024 | } |
1031 | 1025 | ||
@@ -1041,7 +1035,7 @@ parse_percent_limit(const struct option *opt, const char *arg, | |||
1041 | 1035 | ||
1042 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | 1036 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) |
1043 | { | 1037 | { |
1044 | int status; | 1038 | int status = -1; |
1045 | char errbuf[BUFSIZ]; | 1039 | char errbuf[BUFSIZ]; |
1046 | struct perf_top top = { | 1040 | struct perf_top top = { |
1047 | .count_filter = 5, | 1041 | .count_filter = 5, |
@@ -1051,14 +1045,15 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1051 | .user_freq = UINT_MAX, | 1045 | .user_freq = UINT_MAX, |
1052 | .user_interval = ULLONG_MAX, | 1046 | .user_interval = ULLONG_MAX, |
1053 | .freq = 4000, /* 4 KHz */ | 1047 | .freq = 4000, /* 4 KHz */ |
1054 | .target = { | 1048 | .target = { |
1055 | .uses_mmap = true, | 1049 | .uses_mmap = true, |
1056 | }, | 1050 | }, |
1057 | }, | 1051 | }, |
1052 | .max_stack = PERF_MAX_STACK_DEPTH, | ||
1058 | .sym_pcnt_filter = 5, | 1053 | .sym_pcnt_filter = 5, |
1059 | }; | 1054 | }; |
1060 | struct perf_record_opts *opts = &top.record_opts; | 1055 | struct perf_record_opts *opts = &top.record_opts; |
1061 | struct perf_target *target = &opts->target; | 1056 | struct target *target = &opts->target; |
1062 | const struct option options[] = { | 1057 | const struct option options[] = { |
1063 | OPT_CALLBACK('e', "event", &top.evlist, "event", | 1058 | OPT_CALLBACK('e', "event", &top.evlist, "event", |
1064 | "event selector. use 'perf list' to list available events", | 1059 | "event selector. use 'perf list' to list available events", |
@@ -1074,10 +1069,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1074 | "list of cpus to monitor"), | 1069 | "list of cpus to monitor"), |
1075 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 1070 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
1076 | "file", "vmlinux pathname"), | 1071 | "file", "vmlinux pathname"), |
1072 | OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux, | ||
1073 | "don't load vmlinux even if found"), | ||
1077 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, | 1074 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, |
1078 | "hide kernel symbols"), | 1075 | "hide kernel symbols"), |
1079 | OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages, | 1076 | OPT_CALLBACK('m', "mmap-pages", &opts->mmap_pages, "pages", |
1080 | "number of mmap data pages"), | 1077 | "number of mmap data pages", |
1078 | perf_evlist__parse_mmap_pages), | ||
1081 | OPT_INTEGER('r', "realtime", &top.realtime_prio, | 1079 | OPT_INTEGER('r', "realtime", &top.realtime_prio, |
1082 | "collect data with this RT SCHED_FIFO priority"), | 1080 | "collect data with this RT SCHED_FIFO priority"), |
1083 | OPT_INTEGER('d', "delay", &top.delay_secs, | 1081 | OPT_INTEGER('d', "delay", &top.delay_secs, |
@@ -1103,12 +1101,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1103 | OPT_INCR('v', "verbose", &verbose, | 1101 | OPT_INCR('v', "verbose", &verbose, |
1104 | "be more verbose (show counter open errors, etc)"), | 1102 | "be more verbose (show counter open errors, etc)"), |
1105 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | 1103 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", |
1106 | "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"), | 1104 | "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight," |
1105 | " abort, in_tx, transaction"), | ||
1107 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | 1106 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, |
1108 | "Show a column with the number of samples"), | 1107 | "Show a column with the number of samples"), |
1109 | OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, | 1108 | OPT_CALLBACK_NOOPT('G', NULL, &top.record_opts, |
1110 | "mode[,dump_size]", record_callchain_help, | 1109 | NULL, "enables call-graph recording", |
1111 | &parse_callchain_opt, "fp"), | 1110 | &callchain_opt), |
1111 | OPT_CALLBACK(0, "call-graph", &top.record_opts, | ||
1112 | "mode[,dump_size]", record_callchain_help, | ||
1113 | &parse_callchain_opt), | ||
1114 | OPT_INTEGER(0, "max-stack", &top.max_stack, | ||
1115 | "Set the maximum stack depth when parsing the callchain. " | ||
1116 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), | ||
1112 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", | 1117 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", |
1113 | "ignore callees of these functions in call graphs", | 1118 | "ignore callees of these functions in call graphs", |
1114 | report_parse_ignore_callees_opt), | 1119 | report_parse_ignore_callees_opt), |
@@ -1149,8 +1154,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1149 | if (sort_order == default_sort_order) | 1154 | if (sort_order == default_sort_order) |
1150 | sort_order = "dso,symbol"; | 1155 | sort_order = "dso,symbol"; |
1151 | 1156 | ||
1152 | if (setup_sorting() < 0) | 1157 | if (setup_sorting() < 0) { |
1153 | usage_with_options(top_usage, options); | 1158 | parse_options_usage(top_usage, options, "s", 1); |
1159 | goto out_delete_evlist; | ||
1160 | } | ||
1154 | 1161 | ||
1155 | /* display thread wants entries to be collapsed in a different tree */ | 1162 | /* display thread wants entries to be collapsed in a different tree */ |
1156 | sort__need_collapse = 1; | 1163 | sort__need_collapse = 1; |
@@ -1162,24 +1169,24 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1162 | 1169 | ||
1163 | setup_browser(false); | 1170 | setup_browser(false); |
1164 | 1171 | ||
1165 | status = perf_target__validate(target); | 1172 | status = target__validate(target); |
1166 | if (status) { | 1173 | if (status) { |
1167 | perf_target__strerror(target, status, errbuf, BUFSIZ); | 1174 | target__strerror(target, status, errbuf, BUFSIZ); |
1168 | ui__warning("%s", errbuf); | 1175 | ui__warning("%s\n", errbuf); |
1169 | } | 1176 | } |
1170 | 1177 | ||
1171 | status = perf_target__parse_uid(target); | 1178 | status = target__parse_uid(target); |
1172 | if (status) { | 1179 | if (status) { |
1173 | int saved_errno = errno; | 1180 | int saved_errno = errno; |
1174 | 1181 | ||
1175 | perf_target__strerror(target, status, errbuf, BUFSIZ); | 1182 | target__strerror(target, status, errbuf, BUFSIZ); |
1176 | ui__error("%s", errbuf); | 1183 | ui__error("%s\n", errbuf); |
1177 | 1184 | ||
1178 | status = -saved_errno; | 1185 | status = -saved_errno; |
1179 | goto out_delete_evlist; | 1186 | goto out_delete_evlist; |
1180 | } | 1187 | } |
1181 | 1188 | ||
1182 | if (perf_target__none(target)) | 1189 | if (target__none(target)) |
1183 | target->system_wide = true; | 1190 | target->system_wide = true; |
1184 | 1191 | ||
1185 | if (perf_evlist__create_maps(top.evlist, target) < 0) | 1192 | if (perf_evlist__create_maps(top.evlist, target) < 0) |
@@ -1196,20 +1203,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1196 | if (top.delay_secs < 1) | 1203 | if (top.delay_secs < 1) |
1197 | top.delay_secs = 1; | 1204 | top.delay_secs = 1; |
1198 | 1205 | ||
1199 | if (opts->user_interval != ULLONG_MAX) | 1206 | if (perf_record_opts__config(opts)) { |
1200 | opts->default_interval = opts->user_interval; | ||
1201 | if (opts->user_freq != UINT_MAX) | ||
1202 | opts->freq = opts->user_freq; | ||
1203 | |||
1204 | /* | ||
1205 | * User specified count overrides default frequency. | ||
1206 | */ | ||
1207 | if (opts->default_interval) | ||
1208 | opts->freq = 0; | ||
1209 | else if (opts->freq) { | ||
1210 | opts->default_interval = opts->freq; | ||
1211 | } else { | ||
1212 | ui__error("frequency and count are zero, aborting\n"); | ||
1213 | status = -EINVAL; | 1207 | status = -EINVAL; |
1214 | goto out_delete_maps; | 1208 | goto out_delete_maps; |
1215 | } | 1209 | } |