diff options
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r-- | tools/perf/builtin-record.c | 66 |
1 files changed, 61 insertions, 5 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index e9231659754d..f3151d3c70ce 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -31,6 +31,38 @@ | |||
31 | #include <sched.h> | 31 | #include <sched.h> |
32 | #include <sys/mman.h> | 32 | #include <sys/mman.h> |
33 | 33 | ||
34 | #ifndef HAVE_ON_EXIT | ||
35 | #ifndef ATEXIT_MAX | ||
36 | #define ATEXIT_MAX 32 | ||
37 | #endif | ||
38 | static int __on_exit_count = 0; | ||
39 | typedef void (*on_exit_func_t) (int, void *); | ||
40 | static on_exit_func_t __on_exit_funcs[ATEXIT_MAX]; | ||
41 | static void *__on_exit_args[ATEXIT_MAX]; | ||
42 | static int __exitcode = 0; | ||
43 | static void __handle_on_exit_funcs(void); | ||
44 | static int on_exit(on_exit_func_t function, void *arg); | ||
45 | #define exit(x) (exit)(__exitcode = (x)) | ||
46 | |||
47 | static int on_exit(on_exit_func_t function, void *arg) | ||
48 | { | ||
49 | if (__on_exit_count == ATEXIT_MAX) | ||
50 | return -ENOMEM; | ||
51 | else if (__on_exit_count == 0) | ||
52 | atexit(__handle_on_exit_funcs); | ||
53 | __on_exit_funcs[__on_exit_count] = function; | ||
54 | __on_exit_args[__on_exit_count++] = arg; | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static void __handle_on_exit_funcs(void) | ||
59 | { | ||
60 | int i; | ||
61 | for (i = 0; i < __on_exit_count; i++) | ||
62 | __on_exit_funcs[i] (__exitcode, __on_exit_args[i]); | ||
63 | } | ||
64 | #endif | ||
65 | |||
34 | enum write_mode_t { | 66 | enum write_mode_t { |
35 | WRITE_FORCE, | 67 | WRITE_FORCE, |
36 | WRITE_APPEND | 68 | WRITE_APPEND |
@@ -198,11 +230,15 @@ static int perf_record__open(struct perf_record *rec) | |||
198 | struct perf_record_opts *opts = &rec->opts; | 230 | struct perf_record_opts *opts = &rec->opts; |
199 | int rc = 0; | 231 | int rc = 0; |
200 | 232 | ||
201 | perf_evlist__config_attrs(evlist, opts); | 233 | /* |
202 | 234 | * Set the evsel leader links before we configure attributes, | |
235 | * since some might depend on this info. | ||
236 | */ | ||
203 | if (opts->group) | 237 | if (opts->group) |
204 | perf_evlist__set_leader(evlist); | 238 | perf_evlist__set_leader(evlist); |
205 | 239 | ||
240 | perf_evlist__config_attrs(evlist, opts); | ||
241 | |||
206 | list_for_each_entry(pos, &evlist->entries, node) { | 242 | list_for_each_entry(pos, &evlist->entries, node) { |
207 | struct perf_event_attr *attr = &pos->attr; | 243 | struct perf_event_attr *attr = &pos->attr; |
208 | /* | 244 | /* |
@@ -285,6 +321,11 @@ try_again: | |||
285 | perf_evsel__name(pos)); | 321 | perf_evsel__name(pos)); |
286 | rc = -err; | 322 | rc = -err; |
287 | goto out; | 323 | goto out; |
324 | } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) { | ||
325 | ui__error("\'precise\' request may not be supported. " | ||
326 | "Try removing 'p' modifier\n"); | ||
327 | rc = -err; | ||
328 | goto out; | ||
288 | } | 329 | } |
289 | 330 | ||
290 | printf("\n"); | 331 | printf("\n"); |
@@ -326,7 +367,8 @@ try_again: | |||
326 | "or try again with a smaller value of -m/--mmap_pages.\n" | 367 | "or try again with a smaller value of -m/--mmap_pages.\n" |
327 | "(current value: %d)\n", opts->mmap_pages); | 368 | "(current value: %d)\n", opts->mmap_pages); |
328 | rc = -errno; | 369 | rc = -errno; |
329 | } else if (!is_power_of_2(opts->mmap_pages)) { | 370 | } else if (!is_power_of_2(opts->mmap_pages) && |
371 | (opts->mmap_pages != UINT_MAX)) { | ||
330 | pr_err("--mmap_pages/-m value must be a power of two."); | 372 | pr_err("--mmap_pages/-m value must be a power of two."); |
331 | rc = -EINVAL; | 373 | rc = -EINVAL; |
332 | } else { | 374 | } else { |
@@ -460,6 +502,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
460 | struct perf_evlist *evsel_list = rec->evlist; | 502 | struct perf_evlist *evsel_list = rec->evlist; |
461 | const char *output_name = rec->output_name; | 503 | const char *output_name = rec->output_name; |
462 | struct perf_session *session; | 504 | struct perf_session *session; |
505 | bool disabled = false; | ||
463 | 506 | ||
464 | rec->progname = argv[0]; | 507 | rec->progname = argv[0]; |
465 | 508 | ||
@@ -659,7 +702,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
659 | } | 702 | } |
660 | } | 703 | } |
661 | 704 | ||
662 | perf_evlist__enable(evsel_list); | 705 | /* |
706 | * When perf is starting the traced process, all the events | ||
707 | * (apart from group members) have enable_on_exec=1 set, | ||
708 | * so don't spoil it by prematurely enabling them. | ||
709 | */ | ||
710 | if (!perf_target__none(&opts->target)) | ||
711 | perf_evlist__enable(evsel_list); | ||
663 | 712 | ||
664 | /* | 713 | /* |
665 | * Let the child rip | 714 | * Let the child rip |
@@ -682,8 +731,15 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
682 | waking++; | 731 | waking++; |
683 | } | 732 | } |
684 | 733 | ||
685 | if (done) | 734 | /* |
735 | * When perf is starting the traced process, at the end events | ||
736 | * die with the process and we wait for that. Thus no need to | ||
737 | * disable events in this case. | ||
738 | */ | ||
739 | if (done && !disabled && !perf_target__none(&opts->target)) { | ||
686 | perf_evlist__disable(evsel_list); | 740 | perf_evlist__disable(evsel_list); |
741 | disabled = true; | ||
742 | } | ||
687 | } | 743 | } |
688 | 744 | ||
689 | if (quiet || signr == SIGUSR1) | 745 | if (quiet || signr == SIGUSR1) |