perf tools: Handle kernels that don't support attr.exclude_{guest,host}
[firefly-linux-kernel-4.4.55.git] / tools / perf / builtin-record.c
index 0abfb18b911fb93f022f0e6ac1e7b4dda4fb1e4d..d6c10e8ff6b6d532015055156c83ae573f42214d 100644 (file)
@@ -44,6 +44,7 @@ struct perf_record {
        struct perf_evlist      *evlist;
        struct perf_session     *session;
        const char              *progname;
+       const char              *uid_str;
        int                     output;
        unsigned int            page_size;
        int                     realtime_prio;
@@ -204,6 +205,9 @@ static void perf_record__open(struct perf_record *rec)
 
                if (opts->group && pos != first)
                        group_fd = first->fd;
+fallback_missing_features:
+               if (opts->exclude_guest_missing)
+                       attr->exclude_guest = attr->exclude_host = 0;
 retry_sample_id:
                attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
 try_again:
@@ -217,15 +221,23 @@ try_again:
                        } else if (err ==  ENODEV && opts->cpu_list) {
                                die("No such device - did you specify"
                                        " an out-of-range profile CPU?\n");
-                       } else if (err == EINVAL && opts->sample_id_all_avail) {
-                               /*
-                                * Old kernel, no attr->sample_id_type_all field
-                                */
-                               opts->sample_id_all_avail = false;
-                               if (!opts->sample_time && !opts->raw_samples && !time_needed)
-                                       attr->sample_type &= ~PERF_SAMPLE_TIME;
-
-                               goto retry_sample_id;
+                       } else if (err == EINVAL) {
+                               if (!opts->exclude_guest_missing &&
+                                   (attr->exclude_guest || attr->exclude_host)) {
+                                       pr_debug("Old kernel, cannot exclude "
+                                                "guest or host samples.\n");
+                                       opts->exclude_guest_missing = true;
+                                       goto fallback_missing_features;
+                               } else if (opts->sample_id_all_avail) {
+                                       /*
+                                        * Old kernel, no attr->sample_id_type_all field
+                                        */
+                                       opts->sample_id_all_avail = false;
+                                       if (!opts->sample_time && !opts->raw_samples && !time_needed)
+                                               attr->sample_type &= ~PERF_SAMPLE_TIME;
+
+                                       goto retry_sample_id;
+                               }
                        }
 
                        /*
@@ -385,7 +397,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
 {
        struct stat st;
        int flags;
-       int err, output;
+       int err, output, feat;
        unsigned long waking = 0;
        const bool forks = argc > 0;
        struct machine *machine;
@@ -452,8 +464,14 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
 
        rec->session = session;
 
-       if (!rec->no_buildid)
-               perf_header__set_feat(&session->header, HEADER_BUILD_ID);
+       for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
+               perf_header__set_feat(&session->header, feat);
+
+       if (rec->no_buildid)
+               perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
+
+       if (!have_tracepoints(&evsel_list->entries))
+               perf_header__clear_feat(&session->header, HEADER_TRACE_INFO);
 
        if (!rec->file_new) {
                err = perf_session__read_header(session, output);
@@ -461,22 +479,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                        goto out_delete_session;
        }
 
-       if (have_tracepoints(&evsel_list->entries))
-               perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
-
-       perf_header__set_feat(&session->header, HEADER_HOSTNAME);
-       perf_header__set_feat(&session->header, HEADER_OSRELEASE);
-       perf_header__set_feat(&session->header, HEADER_ARCH);
-       perf_header__set_feat(&session->header, HEADER_CPUDESC);
-       perf_header__set_feat(&session->header, HEADER_NRCPUS);
-       perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
-       perf_header__set_feat(&session->header, HEADER_CMDLINE);
-       perf_header__set_feat(&session->header, HEADER_VERSION);
-       perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
-       perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
-       perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
-       perf_header__set_feat(&session->header, HEADER_CPUID);
-
        if (forks) {
                err = perf_evlist__prepare_workload(evsel_list, opts, argv);
                if (err < 0) {
@@ -503,9 +505,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                        return err;
        }
 
-       if (!!rec->no_buildid
+       if (!rec->no_buildid
            && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
-               pr_err("Couldn't generating buildids. "
+               pr_err("Couldn't generate buildids. "
                       "Use --no-buildid to profile anyway.\n");
                return -1;
        }
@@ -654,8 +656,6 @@ static const char * const record_usage[] = {
  */
 static struct perf_record record = {
        .opts = {
-               .target_pid          = -1,
-               .target_tid          = -1,
                .mmap_pages          = UINT_MAX,
                .user_freq           = UINT_MAX,
                .user_interval       = ULLONG_MAX,
@@ -679,9 +679,9 @@ const struct option record_options[] = {
                     parse_events_option),
        OPT_CALLBACK(0, "filter", &record.evlist, "filter",
                     "event filter", parse_filter),
-       OPT_INTEGER('p', "pid", &record.opts.target_pid,
+       OPT_STRING('p', "pid", &record.opts.target_pid, "pid",
                    "record events on existing process id"),
-       OPT_INTEGER('t', "tid", &record.opts.target_tid,
+       OPT_STRING('t', "tid", &record.opts.target_tid, "tid",
                    "record events on existing thread id"),
        OPT_INTEGER('r', "realtime", &record.realtime_prio,
                    "collect data with this RT SCHED_FIFO priority"),
@@ -727,6 +727,7 @@ const struct option record_options[] = {
        OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
                     "monitor event in cgroup name only",
                     parse_cgroups),
+       OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
        OPT_END()
 };
 
@@ -747,8 +748,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 
        argc = parse_options(argc, argv, record_options, record_usage,
                            PARSE_OPT_STOP_AT_NON_OPTION);
-       if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
-               !rec->opts.system_wide && !rec->opts.cpu_list)
+       if (!argc && !rec->opts.target_pid && !rec->opts.target_tid &&
+               !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
                usage_with_options(record_usage, record_options);
 
        if (rec->force && rec->append_file) {
@@ -788,11 +789,17 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
                goto out_symbol_exit;
        }
 
-       if (rec->opts.target_pid != -1)
+       rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
+                                        rec->opts.target_pid);
+       if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
+               goto out_free_fd;
+
+       if (rec->opts.target_pid)
                rec->opts.target_tid = rec->opts.target_pid;
 
        if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
-                                    rec->opts.target_tid, rec->opts.cpu_list) < 0)
+                                    rec->opts.target_tid, rec->opts.uid,
+                                    rec->opts.cpu_list) < 0)
                usage_with_options(record_usage, record_options);
 
        list_for_each_entry(pos, &evsel_list->entries, node) {