aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-record.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r--tools/perf/builtin-record.c66
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 @@
#include <sched.h>
#include <sys/mman.h>
+#ifndef HAVE_ON_EXIT
+#ifndef ATEXIT_MAX
+#define ATEXIT_MAX 32
+#endif
+static int __on_exit_count = 0;
+typedef void (*on_exit_func_t) (int, void *);
+static on_exit_func_t __on_exit_funcs[ATEXIT_MAX];
+static void *__on_exit_args[ATEXIT_MAX];
+static int __exitcode = 0;
+static void __handle_on_exit_funcs(void);
+static int on_exit(on_exit_func_t function, void *arg);
+#define exit(x) (exit)(__exitcode = (x))
+
+static int on_exit(on_exit_func_t function, void *arg)
+{
+ if (__on_exit_count == ATEXIT_MAX)
+ return -ENOMEM;
+ else if (__on_exit_count == 0)
+ atexit(__handle_on_exit_funcs);
+ __on_exit_funcs[__on_exit_count] = function;
+ __on_exit_args[__on_exit_count++] = arg;
+ return 0;
+}
+
+static void __handle_on_exit_funcs(void)
+{
+ int i;
+ for (i = 0; i < __on_exit_count; i++)
+ __on_exit_funcs[i] (__exitcode, __on_exit_args[i]);
+}
+#endif
+
enum write_mode_t {
WRITE_FORCE,
WRITE_APPEND
@@ -198,11 +230,15 @@ static int perf_record__open(struct perf_record *rec)
struct perf_record_opts *opts = &rec->opts;
int rc = 0;
- perf_evlist__config_attrs(evlist, opts);
-
+ /*
+ * Set the evsel leader links before we configure attributes,
+ * since some might depend on this info.
+ */
if (opts->group)
perf_evlist__set_leader(evlist);
+ perf_evlist__config_attrs(evlist, opts);
+
list_for_each_entry(pos, &evlist->entries, node) {
struct perf_event_attr *attr = &pos->attr;
/*
@@ -285,6 +321,11 @@ try_again:
perf_evsel__name(pos));
rc = -err;
goto out;
+ } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
+ ui__error("\'precise\' request may not be supported. "
+ "Try removing 'p' modifier\n");
+ rc = -err;
+ goto out;
}
printf("\n");
@@ -326,7 +367,8 @@ try_again:
"or try again with a smaller value of -m/--mmap_pages.\n"
"(current value: %d)\n", opts->mmap_pages);
rc = -errno;
- } else if (!is_power_of_2(opts->mmap_pages)) {
+ } else if (!is_power_of_2(opts->mmap_pages) &&
+ (opts->mmap_pages != UINT_MAX)) {
pr_err("--mmap_pages/-m value must be a power of two.");
rc = -EINVAL;
} else {
@@ -460,6 +502,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
struct perf_evlist *evsel_list = rec->evlist;
const char *output_name = rec->output_name;
struct perf_session *session;
+ bool disabled = false;
rec->progname = argv[0];
@@ -659,7 +702,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
}
}
- perf_evlist__enable(evsel_list);
+ /*
+ * When perf is starting the traced process, all the events
+ * (apart from group members) have enable_on_exec=1 set,
+ * so don't spoil it by prematurely enabling them.
+ */
+ if (!perf_target__none(&opts->target))
+ perf_evlist__enable(evsel_list);
/*
* Let the child rip
@@ -682,8 +731,15 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
waking++;
}
- if (done)
+ /*
+ * When perf is starting the traced process, at the end events
+ * die with the process and we wait for that. Thus no need to
+ * disable events in this case.
+ */
+ if (done && !disabled && !perf_target__none(&opts->target)) {
perf_evlist__disable(evsel_list);
+ disabled = true;
+ }
}
if (quiet || signr == SIGUSR1)