]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - tools/perf/util/evsel.c
Merge branches 'pm-core', 'pm-qos', 'pm-domains' and 'pm-opp'
[linux.git] / tools / perf / util / evsel.c
index b2365a63db45c16f62c13093f55187f78ffd9c12..ac59710b79e0b4cbee35cacc1e40a2102e091d8e 100644 (file)
@@ -990,6 +990,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
         * it overloads any global configuration.
         */
        apply_config_terms(evsel, opts);
+
+       evsel->ignore_missing_thread = opts->ignore_missing_thread;
 }
 
 static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -1419,8 +1421,35 @@ static int __open_attr__fprintf(FILE *fp, const char *name, const char *val,
        return fprintf(fp, "  %-32s %s\n", name, val);
 }
 
-static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-                             struct thread_map *threads)
+static bool ignore_missing_thread(struct perf_evsel *evsel,
+                                 struct thread_map *threads,
+                                 int thread, int err)
+{
+       if (!evsel->ignore_missing_thread)
+               return false;
+
+       /* The system wide setup does not work with threads. */
+       if (evsel->system_wide)
+               return false;
+
+       /* The -ESRCH is perf event syscall errno for pid's not found. */
+       if (err != -ESRCH)
+               return false;
+
+       /* If there's only one thread, let it fail. */
+       if (threads->nr == 1)
+               return false;
+
+       if (thread_map__remove(threads, thread))
+               return false;
+
+       pr_warning("WARNING: Ignored open failure for pid %d\n",
+                  thread_map__pid(threads, thread));
+       return true;
+}
+
+int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
+                    struct thread_map *threads)
 {
        int cpu, thread, nthreads;
        unsigned long flags = PERF_FLAG_FD_CLOEXEC;
@@ -1430,6 +1459,30 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
        if (perf_missing_features.write_backward && evsel->attr.write_backward)
                return -EINVAL;
 
+       if (cpus == NULL) {
+               static struct cpu_map *empty_cpu_map;
+
+               if (empty_cpu_map == NULL) {
+                       empty_cpu_map = cpu_map__dummy_new();
+                       if (empty_cpu_map == NULL)
+                               return -ENOMEM;
+               }
+
+               cpus = empty_cpu_map;
+       }
+
+       if (threads == NULL) {
+               static struct thread_map *empty_thread_map;
+
+               if (empty_thread_map == NULL) {
+                       empty_thread_map = thread_map__new_by_tid(-1);
+                       if (empty_thread_map == NULL)
+                               return -ENOMEM;
+               }
+
+               threads = empty_thread_map;
+       }
+
        if (evsel->system_wide)
                nthreads = 1;
        else
@@ -1474,7 +1527,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
        for (cpu = 0; cpu < cpus->nr; cpu++) {
 
                for (thread = 0; thread < nthreads; thread++) {
-                       int group_fd;
+                       int fd, group_fd;
 
                        if (!evsel->cgrp && !evsel->system_wide)
                                pid = thread_map__pid(threads, thread);
@@ -1484,21 +1537,37 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
                        pr_debug2("sys_perf_event_open: pid %d  cpu %d  group_fd %d  flags %#lx",
                                  pid, cpus->map[cpu], group_fd, flags);
 
-                       FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
-                                                                    pid,
-                                                                    cpus->map[cpu],
-                                                                    group_fd, flags);
-                       if (FD(evsel, cpu, thread) < 0) {
+                       fd = sys_perf_event_open(&evsel->attr, pid, cpus->map[cpu],
+                                                group_fd, flags);
+
+                       FD(evsel, cpu, thread) = fd;
+
+                       if (fd < 0) {
                                err = -errno;
+
+                               if (ignore_missing_thread(evsel, threads, thread, err)) {
+                                       /*
+                                        * We just removed 1 thread, so take a step
+                                        * back on thread index and lower the upper
+                                        * nthreads limit.
+                                        */
+                                       nthreads--;
+                                       thread--;
+
+                                       /* ... and pretend like nothing have happened. */
+                                       err = 0;
+                                       continue;
+                               }
+
                                pr_debug2("\nsys_perf_event_open failed, error %d\n",
                                          err);
                                goto try_fallback;
                        }
 
-                       pr_debug2(" = %d\n", FD(evsel, cpu, thread));
+                       pr_debug2(" = %d\n", fd);
 
                        if (evsel->bpf_fd >= 0) {
-                               int evt_fd = FD(evsel, cpu, thread);
+                               int evt_fd = fd;
                                int bpf_fd = evsel->bpf_fd;
 
                                err = ioctl(evt_fd,
@@ -1610,46 +1679,16 @@ void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads)
        perf_evsel__free_fd(evsel);
 }
 
-static struct {
-       struct cpu_map map;
-       int cpus[1];
-} empty_cpu_map = {
-       .map.nr = 1,
-       .cpus   = { -1, },
-};
-
-static struct {
-       struct thread_map map;
-       int threads[1];
-} empty_thread_map = {
-       .map.nr  = 1,
-       .threads = { -1, },
-};
-
-int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-                    struct thread_map *threads)
-{
-       if (cpus == NULL) {
-               /* Work around old compiler warnings about strict aliasing */
-               cpus = &empty_cpu_map.map;
-       }
-
-       if (threads == NULL)
-               threads = &empty_thread_map.map;
-
-       return __perf_evsel__open(evsel, cpus, threads);
-}
-
 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
                             struct cpu_map *cpus)
 {
-       return __perf_evsel__open(evsel, cpus, &empty_thread_map.map);
+       return perf_evsel__open(evsel, cpus, NULL);
 }
 
 int perf_evsel__open_per_thread(struct perf_evsel *evsel,
                                struct thread_map *threads)
 {
-       return __perf_evsel__open(evsel, &empty_cpu_map.map, threads);
+       return perf_evsel__open(evsel, NULL, threads);
 }
 
 static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
@@ -2424,7 +2463,9 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
                 "  -1: Allow use of (almost) all events by all users\n"
                 ">= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK\n"
                 ">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n"
-                ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN",
+                ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN\n\n"
+                "To make this setting permanent, edit /etc/sysctl.conf too, e.g.:\n\n"
+                "      kernel.perf_event_paranoid = -1\n" ,
                                 target->system_wide ? "system-wide " : "",
                                 perf_event_paranoid());
        case ENOENT: