diff options
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r-- | tools/perf/builtin-record.c | 180 |
1 files changed, 48 insertions, 132 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6ab58cc99d53..c3ac5415c097 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -35,32 +35,24 @@ enum write_mode_t { | |||
35 | WRITE_APPEND | 35 | WRITE_APPEND |
36 | }; | 36 | }; |
37 | 37 | ||
38 | static u64 user_interval = ULLONG_MAX; | 38 | static struct perf_record_opts record_opts = { |
39 | static u64 default_interval = 0; | 39 | .target_pid = -1, |
40 | .target_tid = -1, | ||
41 | .user_freq = UINT_MAX, | ||
42 | .user_interval = ULLONG_MAX, | ||
43 | .freq = 1000, | ||
44 | .sample_id_all_avail = true, | ||
45 | }; | ||
40 | 46 | ||
41 | static unsigned int page_size; | 47 | static unsigned int page_size; |
42 | static unsigned int mmap_pages = UINT_MAX; | 48 | static unsigned int mmap_pages = UINT_MAX; |
43 | static unsigned int user_freq = UINT_MAX; | ||
44 | static int freq = 1000; | ||
45 | static int output; | 49 | static int output; |
46 | static int pipe_output = 0; | 50 | static int pipe_output = 0; |
47 | static const char *output_name = NULL; | 51 | static const char *output_name = NULL; |
48 | static bool group = false; | 52 | static bool group = false; |
49 | static int realtime_prio = 0; | 53 | static int realtime_prio = 0; |
50 | static bool nodelay = false; | ||
51 | static bool raw_samples = false; | ||
52 | static bool sample_id_all_avail = true; | ||
53 | static bool system_wide = false; | ||
54 | static pid_t target_pid = -1; | ||
55 | static pid_t target_tid = -1; | ||
56 | static pid_t child_pid = -1; | 54 | static pid_t child_pid = -1; |
57 | static bool no_inherit = false; | ||
58 | static enum write_mode_t write_mode = WRITE_FORCE; | 55 | static enum write_mode_t write_mode = WRITE_FORCE; |
59 | static bool call_graph = false; | ||
60 | static bool inherit_stat = false; | ||
61 | static bool no_samples = false; | ||
62 | static bool sample_address = false; | ||
63 | static bool sample_time = false; | ||
64 | static bool no_buildid = false; | 56 | static bool no_buildid = false; |
65 | static bool no_buildid_cache = false; | 57 | static bool no_buildid_cache = false; |
66 | static struct perf_evlist *evsel_list; | 58 | static struct perf_evlist *evsel_list; |
@@ -72,7 +64,6 @@ static int file_new = 1; | |||
72 | static off_t post_processing_offset; | 64 | static off_t post_processing_offset; |
73 | 65 | ||
74 | static struct perf_session *session; | 66 | static struct perf_session *session; |
75 | static const char *cpu_list; | ||
76 | static const char *progname; | 67 | static const char *progname; |
77 | 68 | ||
78 | static void advance_output(size_t size) | 69 | static void advance_output(size_t size) |
@@ -169,78 +160,6 @@ static void sig_atexit(void) | |||
169 | kill(getpid(), signr); | 160 | kill(getpid(), signr); |
170 | } | 161 | } |
171 | 162 | ||
172 | static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) | ||
173 | { | ||
174 | struct perf_event_attr *attr = &evsel->attr; | ||
175 | int track = !evsel->idx; /* only the first counter needs these */ | ||
176 | |||
177 | attr->disabled = 1; | ||
178 | attr->inherit = !no_inherit; | ||
179 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | ||
180 | PERF_FORMAT_TOTAL_TIME_RUNNING | | ||
181 | PERF_FORMAT_ID; | ||
182 | |||
183 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; | ||
184 | |||
185 | if (evlist->nr_entries > 1) | ||
186 | attr->sample_type |= PERF_SAMPLE_ID; | ||
187 | |||
188 | /* | ||
189 | * We default some events to a 1 default interval. But keep | ||
190 | * it a weak assumption overridable by the user. | ||
191 | */ | ||
192 | if (!attr->sample_period || (user_freq != UINT_MAX && | ||
193 | user_interval != ULLONG_MAX)) { | ||
194 | if (freq) { | ||
195 | attr->sample_type |= PERF_SAMPLE_PERIOD; | ||
196 | attr->freq = 1; | ||
197 | attr->sample_freq = freq; | ||
198 | } else { | ||
199 | attr->sample_period = default_interval; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | if (no_samples) | ||
204 | attr->sample_freq = 0; | ||
205 | |||
206 | if (inherit_stat) | ||
207 | attr->inherit_stat = 1; | ||
208 | |||
209 | if (sample_address) { | ||
210 | attr->sample_type |= PERF_SAMPLE_ADDR; | ||
211 | attr->mmap_data = track; | ||
212 | } | ||
213 | |||
214 | if (call_graph) | ||
215 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
216 | |||
217 | if (system_wide) | ||
218 | attr->sample_type |= PERF_SAMPLE_CPU; | ||
219 | |||
220 | if (sample_id_all_avail && | ||
221 | (sample_time || system_wide || !no_inherit || cpu_list)) | ||
222 | attr->sample_type |= PERF_SAMPLE_TIME; | ||
223 | |||
224 | if (raw_samples) { | ||
225 | attr->sample_type |= PERF_SAMPLE_TIME; | ||
226 | attr->sample_type |= PERF_SAMPLE_RAW; | ||
227 | attr->sample_type |= PERF_SAMPLE_CPU; | ||
228 | } | ||
229 | |||
230 | if (nodelay) { | ||
231 | attr->watermark = 0; | ||
232 | attr->wakeup_events = 1; | ||
233 | } | ||
234 | |||
235 | attr->mmap = track; | ||
236 | attr->comm = track; | ||
237 | |||
238 | if (target_pid == -1 && target_tid == -1 && !system_wide) { | ||
239 | attr->disabled = 1; | ||
240 | attr->enable_on_exec = 1; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | static bool perf_evlist__equal(struct perf_evlist *evlist, | 163 | static bool perf_evlist__equal(struct perf_evlist *evlist, |
245 | struct perf_evlist *other) | 164 | struct perf_evlist *other) |
246 | { | 165 | { |
@@ -264,11 +183,10 @@ static void open_counters(struct perf_evlist *evlist) | |||
264 | { | 183 | { |
265 | struct perf_evsel *pos, *first; | 184 | struct perf_evsel *pos, *first; |
266 | 185 | ||
267 | if (evlist->cpus->map[0] < 0) | ||
268 | no_inherit = true; | ||
269 | |||
270 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | 186 | first = list_entry(evlist->entries.next, struct perf_evsel, node); |
271 | 187 | ||
188 | perf_evlist__config_attrs(evlist, &record_opts); | ||
189 | |||
272 | list_for_each_entry(pos, &evlist->entries, node) { | 190 | list_for_each_entry(pos, &evlist->entries, node) { |
273 | struct perf_event_attr *attr = &pos->attr; | 191 | struct perf_event_attr *attr = &pos->attr; |
274 | struct xyarray *group_fd = NULL; | 192 | struct xyarray *group_fd = NULL; |
@@ -288,10 +206,8 @@ static void open_counters(struct perf_evlist *evlist) | |||
288 | 206 | ||
289 | if (group && pos != first) | 207 | if (group && pos != first) |
290 | group_fd = first->fd; | 208 | group_fd = first->fd; |
291 | |||
292 | config_attr(pos, evlist); | ||
293 | retry_sample_id: | 209 | retry_sample_id: |
294 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | 210 | attr->sample_id_all = record_opts.sample_id_all_avail ? 1 : 0; |
295 | try_again: | 211 | try_again: |
296 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, | 212 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, |
297 | group_fd) < 0) { | 213 | group_fd) < 0) { |
@@ -300,15 +216,15 @@ try_again: | |||
300 | if (err == EPERM || err == EACCES) { | 216 | if (err == EPERM || err == EACCES) { |
301 | ui__error_paranoid(); | 217 | ui__error_paranoid(); |
302 | exit(EXIT_FAILURE); | 218 | exit(EXIT_FAILURE); |
303 | } else if (err == ENODEV && cpu_list) { | 219 | } else if (err == ENODEV && record_opts.cpu_list) { |
304 | die("No such device - did you specify" | 220 | die("No such device - did you specify" |
305 | " an out-of-range profile CPU?\n"); | 221 | " an out-of-range profile CPU?\n"); |
306 | } else if (err == EINVAL && sample_id_all_avail) { | 222 | } else if (err == EINVAL && record_opts.sample_id_all_avail) { |
307 | /* | 223 | /* |
308 | * Old kernel, no attr->sample_id_type_all field | 224 | * Old kernel, no attr->sample_id_type_all field |
309 | */ | 225 | */ |
310 | sample_id_all_avail = false; | 226 | record_opts.sample_id_all_avail = false; |
311 | if (!sample_time && !raw_samples && !time_needed) | 227 | if (!record_opts.sample_time && !record_opts.raw_samples && !time_needed) |
312 | attr->sample_type &= ~PERF_SAMPLE_TIME; | 228 | attr->sample_type &= ~PERF_SAMPLE_TIME; |
313 | 229 | ||
314 | goto retry_sample_id; | 230 | goto retry_sample_id; |
@@ -482,13 +398,13 @@ static int __cmd_record(int argc, const char **argv) | |||
482 | 398 | ||
483 | if (!output_name) { | 399 | if (!output_name) { |
484 | if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) | 400 | if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) |
485 | pipe_output = 1; | 401 | pipe_output = true; |
486 | else | 402 | else |
487 | output_name = "perf.data"; | 403 | output_name = "perf.data"; |
488 | } | 404 | } |
489 | if (output_name) { | 405 | if (output_name) { |
490 | if (!strcmp(output_name, "-")) | 406 | if (!strcmp(output_name, "-")) |
491 | pipe_output = 1; | 407 | pipe_output = true; |
492 | else if (!stat(output_name, &st) && st.st_size) { | 408 | else if (!stat(output_name, &st) && st.st_size) { |
493 | if (write_mode == WRITE_FORCE) { | 409 | if (write_mode == WRITE_FORCE) { |
494 | char oldname[PATH_MAX]; | 410 | char oldname[PATH_MAX]; |
@@ -592,7 +508,7 @@ static int __cmd_record(int argc, const char **argv) | |||
592 | exit(-1); | 508 | exit(-1); |
593 | } | 509 | } |
594 | 510 | ||
595 | if (!system_wide && target_tid == -1 && target_pid == -1) | 511 | if (!record_opts.system_wide && record_opts.target_tid == -1 && record_opts.target_pid == -1) |
596 | evsel_list->threads->map[0] = child_pid; | 512 | evsel_list->threads->map[0] = child_pid; |
597 | 513 | ||
598 | close(child_ready_pipe[1]); | 514 | close(child_ready_pipe[1]); |
@@ -689,7 +605,7 @@ static int __cmd_record(int argc, const char **argv) | |||
689 | perf_session__process_machines(session, | 605 | perf_session__process_machines(session, |
690 | perf_event__synthesize_guest_os); | 606 | perf_event__synthesize_guest_os); |
691 | 607 | ||
692 | if (!system_wide) | 608 | if (!record_opts.system_wide) |
693 | perf_event__synthesize_thread_map(evsel_list->threads, | 609 | perf_event__synthesize_thread_map(evsel_list->threads, |
694 | process_synthesized_event, | 610 | process_synthesized_event, |
695 | session); | 611 | session); |
@@ -766,44 +682,44 @@ const struct option record_options[] = { | |||
766 | parse_events_option), | 682 | parse_events_option), |
767 | OPT_CALLBACK(0, "filter", &evsel_list, "filter", | 683 | OPT_CALLBACK(0, "filter", &evsel_list, "filter", |
768 | "event filter", parse_filter), | 684 | "event filter", parse_filter), |
769 | OPT_INTEGER('p', "pid", &target_pid, | 685 | OPT_INTEGER('p', "pid", &record_opts.target_pid, |
770 | "record events on existing process id"), | 686 | "record events on existing process id"), |
771 | OPT_INTEGER('t', "tid", &target_tid, | 687 | OPT_INTEGER('t', "tid", &record_opts.target_tid, |
772 | "record events on existing thread id"), | 688 | "record events on existing thread id"), |
773 | OPT_INTEGER('r', "realtime", &realtime_prio, | 689 | OPT_INTEGER('r', "realtime", &realtime_prio, |
774 | "collect data with this RT SCHED_FIFO priority"), | 690 | "collect data with this RT SCHED_FIFO priority"), |
775 | OPT_BOOLEAN('D', "no-delay", &nodelay, | 691 | OPT_BOOLEAN('D', "no-delay", &record_opts.no_delay, |
776 | "collect data without buffering"), | 692 | "collect data without buffering"), |
777 | OPT_BOOLEAN('R', "raw-samples", &raw_samples, | 693 | OPT_BOOLEAN('R', "raw-samples", &record_opts.raw_samples, |
778 | "collect raw sample records from all opened counters"), | 694 | "collect raw sample records from all opened counters"), |
779 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 695 | OPT_BOOLEAN('a', "all-cpus", &record_opts.system_wide, |
780 | "system-wide collection from all CPUs"), | 696 | "system-wide collection from all CPUs"), |
781 | OPT_BOOLEAN('A', "append", &append_file, | 697 | OPT_BOOLEAN('A', "append", &append_file, |
782 | "append to the output file to do incremental profiling"), | 698 | "append to the output file to do incremental profiling"), |
783 | OPT_STRING('C', "cpu", &cpu_list, "cpu", | 699 | OPT_STRING('C', "cpu", &record_opts.cpu_list, "cpu", |
784 | "list of cpus to monitor"), | 700 | "list of cpus to monitor"), |
785 | OPT_BOOLEAN('f', "force", &force, | 701 | OPT_BOOLEAN('f', "force", &force, |
786 | "overwrite existing data file (deprecated)"), | 702 | "overwrite existing data file (deprecated)"), |
787 | OPT_U64('c', "count", &user_interval, "event period to sample"), | 703 | OPT_U64('c', "count", &record_opts.user_interval, "event period to sample"), |
788 | OPT_STRING('o', "output", &output_name, "file", | 704 | OPT_STRING('o', "output", &output_name, "file", |
789 | "output file name"), | 705 | "output file name"), |
790 | OPT_BOOLEAN('i', "no-inherit", &no_inherit, | 706 | OPT_BOOLEAN('i', "no-inherit", &record_opts.no_inherit, |
791 | "child tasks do not inherit counters"), | 707 | "child tasks do not inherit counters"), |
792 | OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), | 708 | OPT_UINTEGER('F', "freq", &record_opts.user_freq, "profile at this frequency"), |
793 | OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), | 709 | OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), |
794 | OPT_BOOLEAN(0, "group", &group, | 710 | OPT_BOOLEAN(0, "group", &group, |
795 | "put the counters into a counter group"), | 711 | "put the counters into a counter group"), |
796 | OPT_BOOLEAN('g', "call-graph", &call_graph, | 712 | OPT_BOOLEAN('g', "call-graph", &record_opts.call_graph, |
797 | "do call-graph (stack chain/backtrace) recording"), | 713 | "do call-graph (stack chain/backtrace) recording"), |
798 | OPT_INCR('v', "verbose", &verbose, | 714 | OPT_INCR('v', "verbose", &verbose, |
799 | "be more verbose (show counter open errors, etc)"), | 715 | "be more verbose (show counter open errors, etc)"), |
800 | OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), | 716 | OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), |
801 | OPT_BOOLEAN('s', "stat", &inherit_stat, | 717 | OPT_BOOLEAN('s', "stat", &record_opts.inherit_stat, |
802 | "per thread counts"), | 718 | "per thread counts"), |
803 | OPT_BOOLEAN('d', "data", &sample_address, | 719 | OPT_BOOLEAN('d', "data", &record_opts.sample_address, |
804 | "Sample addresses"), | 720 | "Sample addresses"), |
805 | OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"), | 721 | OPT_BOOLEAN('T', "timestamp", &record_opts.sample_time, "Sample timestamps"), |
806 | OPT_BOOLEAN('n', "no-samples", &no_samples, | 722 | OPT_BOOLEAN('n', "no-samples", &record_opts.no_samples, |
807 | "don't sample"), | 723 | "don't sample"), |
808 | OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, | 724 | OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, |
809 | "do not update the buildid cache"), | 725 | "do not update the buildid cache"), |
@@ -828,8 +744,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
828 | 744 | ||
829 | argc = parse_options(argc, argv, record_options, record_usage, | 745 | argc = parse_options(argc, argv, record_options, record_usage, |
830 | PARSE_OPT_STOP_AT_NON_OPTION); | 746 | PARSE_OPT_STOP_AT_NON_OPTION); |
831 | if (!argc && target_pid == -1 && target_tid == -1 && | 747 | if (!argc && record_opts.target_pid == -1 && record_opts.target_tid == -1 && |
832 | !system_wide && !cpu_list) | 748 | !record_opts.system_wide && !record_opts.cpu_list) |
833 | usage_with_options(record_usage, record_options); | 749 | usage_with_options(record_usage, record_options); |
834 | 750 | ||
835 | if (force && append_file) { | 751 | if (force && append_file) { |
@@ -842,7 +758,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
842 | write_mode = WRITE_FORCE; | 758 | write_mode = WRITE_FORCE; |
843 | } | 759 | } |
844 | 760 | ||
845 | if (nr_cgroups && !system_wide) { | 761 | if (nr_cgroups && !record_opts.system_wide) { |
846 | fprintf(stderr, "cgroup monitoring only available in" | 762 | fprintf(stderr, "cgroup monitoring only available in" |
847 | " system-wide mode\n"); | 763 | " system-wide mode\n"); |
848 | usage_with_options(record_usage, record_options); | 764 | usage_with_options(record_usage, record_options); |
@@ -869,11 +785,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
869 | goto out_symbol_exit; | 785 | goto out_symbol_exit; |
870 | } | 786 | } |
871 | 787 | ||
872 | if (target_pid != -1) | 788 | if (record_opts.target_pid != -1) |
873 | target_tid = target_pid; | 789 | record_opts.target_tid = record_opts.target_pid; |
874 | 790 | ||
875 | if (perf_evlist__create_maps(evsel_list, target_pid, | 791 | if (perf_evlist__create_maps(evsel_list, record_opts.target_pid, |
876 | target_tid, cpu_list) < 0) | 792 | record_opts.target_tid, record_opts.cpu_list) < 0) |
877 | usage_with_options(record_usage, record_options); | 793 | usage_with_options(record_usage, record_options); |
878 | 794 | ||
879 | list_for_each_entry(pos, &evsel_list->entries, node) { | 795 | list_for_each_entry(pos, &evsel_list->entries, node) { |
@@ -887,18 +803,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
887 | if (perf_evlist__alloc_pollfd(evsel_list) < 0) | 803 | if (perf_evlist__alloc_pollfd(evsel_list) < 0) |
888 | goto out_free_fd; | 804 | goto out_free_fd; |
889 | 805 | ||
890 | if (user_interval != ULLONG_MAX) | 806 | if (record_opts.user_interval != ULLONG_MAX) |
891 | default_interval = user_interval; | 807 | record_opts.default_interval = record_opts.user_interval; |
892 | if (user_freq != UINT_MAX) | 808 | if (record_opts.user_freq != UINT_MAX) |
893 | freq = user_freq; | 809 | record_opts.freq = record_opts.user_freq; |
894 | 810 | ||
895 | /* | 811 | /* |
896 | * User specified count overrides default frequency. | 812 | * User specified count overrides default frequency. |
897 | */ | 813 | */ |
898 | if (default_interval) | 814 | if (record_opts.default_interval) |
899 | freq = 0; | 815 | record_opts.freq = 0; |
900 | else if (freq) { | 816 | else if (record_opts.freq) { |
901 | default_interval = freq; | 817 | record_opts.default_interval = record_opts.freq; |
902 | } else { | 818 | } else { |
903 | fprintf(stderr, "frequency and count are zero, aborting\n"); | 819 | fprintf(stderr, "frequency and count are zero, aborting\n"); |
904 | err = -EINVAL; | 820 | err = -EINVAL; |