]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - tools/perf/util/evlist.c
perf probe: Make error messages thread-safe
[mirror_ubuntu-artful-kernel.git] / tools / perf / util / evlist.c
index 59ef2802fcf631fa0e7d6f2f97e59e6881f675d4..5dcd28c79c6e9728edfc7189d294dc7de7e4a7ae 100644 (file)
@@ -122,6 +122,7 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
 {
        list_add_tail(&entry->node, &evlist->entries);
        entry->idx = evlist->nr_entries;
+       entry->tracking = !entry->idx;
 
        if (!evlist->nr_entries++)
                perf_evlist__set_id_pos(evlist);
@@ -265,17 +266,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,
        return 0;
 }
 
+static int perf_evlist__nr_threads(struct perf_evlist *evlist,
+                                  struct perf_evsel *evsel)
+{
+       if (evsel->system_wide)
+               return 1;
+       else
+               return thread_map__nr(evlist->threads);
+}
+
 void perf_evlist__disable(struct perf_evlist *evlist)
 {
        int cpu, thread;
        struct perf_evsel *pos;
        int nr_cpus = cpu_map__nr(evlist->cpus);
-       int nr_threads = thread_map__nr(evlist->threads);
+       int nr_threads;
 
        for (cpu = 0; cpu < nr_cpus; cpu++) {
                evlist__for_each(evlist, pos) {
                        if (!perf_evsel__is_group_leader(pos) || !pos->fd)
                                continue;
+                       nr_threads = perf_evlist__nr_threads(evlist, pos);
                        for (thread = 0; thread < nr_threads; thread++)
                                ioctl(FD(pos, cpu, thread),
                                      PERF_EVENT_IOC_DISABLE, 0);
@@ -288,12 +299,13 @@ void perf_evlist__enable(struct perf_evlist *evlist)
        int cpu, thread;
        struct perf_evsel *pos;
        int nr_cpus = cpu_map__nr(evlist->cpus);
-       int nr_threads = thread_map__nr(evlist->threads);
+       int nr_threads;
 
        for (cpu = 0; cpu < nr_cpus; cpu++) {
                evlist__for_each(evlist, pos) {
                        if (!perf_evsel__is_group_leader(pos) || !pos->fd)
                                continue;
+                       nr_threads = perf_evlist__nr_threads(evlist, pos);
                        for (thread = 0; thread < nr_threads; thread++)
                                ioctl(FD(pos, cpu, thread),
                                      PERF_EVENT_IOC_ENABLE, 0);
@@ -305,12 +317,14 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
                               struct perf_evsel *evsel)
 {
        int cpu, thread, err;
+       int nr_cpus = cpu_map__nr(evlist->cpus);
+       int nr_threads = perf_evlist__nr_threads(evlist, evsel);
 
        if (!evsel->fd)
                return 0;
 
-       for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-               for (thread = 0; thread < evlist->threads->nr; thread++) {
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               for (thread = 0; thread < nr_threads; thread++) {
                        err = ioctl(FD(evsel, cpu, thread),
                                    PERF_EVENT_IOC_DISABLE, 0);
                        if (err)
@@ -324,12 +338,14 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
                              struct perf_evsel *evsel)
 {
        int cpu, thread, err;
+       int nr_cpus = cpu_map__nr(evlist->cpus);
+       int nr_threads = perf_evlist__nr_threads(evlist, evsel);
 
        if (!evsel->fd)
                return -EINVAL;
 
-       for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-               for (thread = 0; thread < evlist->threads->nr; thread++) {
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               for (thread = 0; thread < nr_threads; thread++) {
                        err = ioctl(FD(evsel, cpu, thread),
                                    PERF_EVENT_IOC_ENABLE, 0);
                        if (err)
@@ -339,11 +355,67 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
        return 0;
 }
 
+static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
+                                        struct perf_evsel *evsel, int cpu)
+{
+       int thread, err;
+       int nr_threads = perf_evlist__nr_threads(evlist, evsel);
+
+       if (!evsel->fd)
+               return -EINVAL;
+
+       for (thread = 0; thread < nr_threads; thread++) {
+               err = ioctl(FD(evsel, cpu, thread),
+                           PERF_EVENT_IOC_ENABLE, 0);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+static int perf_evlist__enable_event_thread(struct perf_evlist *evlist,
+                                           struct perf_evsel *evsel,
+                                           int thread)
+{
+       int cpu, err;
+       int nr_cpus = cpu_map__nr(evlist->cpus);
+
+       if (!evsel->fd)
+               return -EINVAL;
+
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
+                                 struct perf_evsel *evsel, int idx)
+{
+       bool per_cpu_mmaps = !cpu_map__empty(evlist->cpus);
+
+       if (per_cpu_mmaps)
+               return perf_evlist__enable_event_cpu(evlist, evsel, idx);
+       else
+               return perf_evlist__enable_event_thread(evlist, evsel, idx);
+}
+
 static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
        int nr_cpus = cpu_map__nr(evlist->cpus);
        int nr_threads = thread_map__nr(evlist->threads);
-       int nfds = nr_cpus * nr_threads * evlist->nr_entries;
+       int nfds = 0;
+       struct perf_evsel *evsel;
+
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               if (evsel->system_wide)
+                       nfds += nr_cpus;
+               else
+                       nfds += nr_cpus * nr_threads;
+       }
+
        evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
        return evlist->pollfd != NULL ? 0 : -ENOMEM;
 }
@@ -606,12 +678,17 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
        return evlist->mmap != NULL ? 0 : -ENOMEM;
 }
 
-static int __perf_evlist__mmap(struct perf_evlist *evlist,
-                              int idx, int prot, int mask, int fd)
+struct mmap_params {
+       int prot;
+       int mask;
+};
+
+static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
+                              struct mmap_params *mp, int fd)
 {
        evlist->mmap[idx].prev = 0;
-       evlist->mmap[idx].mask = mask;
-       evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
+       evlist->mmap[idx].mask = mp->mask;
+       evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot,
                                      MAP_SHARED, fd, 0);
        if (evlist->mmap[idx].base == MAP_FAILED) {
                pr_debug2("failed to mmap perf event ring buffer, error %d\n",
@@ -625,18 +702,22 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
 }
 
 static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
-                                      int prot, int mask, int cpu, int thread,
-                                      int *output)
+                                      struct mmap_params *mp, int cpu,
+                                      int thread, int *output)
 {
        struct perf_evsel *evsel;
 
        evlist__for_each(evlist, evsel) {
-               int fd = FD(evsel, cpu, thread);
+               int fd;
+
+               if (evsel->system_wide && thread)
+                       continue;
+
+               fd = FD(evsel, cpu, thread);
 
                if (*output == -1) {
                        *output = fd;
-                       if (__perf_evlist__mmap(evlist, idx, prot, mask,
-                                               *output) < 0)
+                       if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0)
                                return -1;
                } else {
                        if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
@@ -651,8 +732,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
        return 0;
 }
 
-static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
-                                    int mask)
+static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,
+                                    struct mmap_params *mp)
 {
        int cpu, thread;
        int nr_cpus = cpu_map__nr(evlist->cpus);
@@ -663,8 +744,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
                int output = -1;
 
                for (thread = 0; thread < nr_threads; thread++) {
-                       if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask,
-                                                       cpu, thread, &output))
+                       if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu,
+                                                       thread, &output))
                                goto out_unmap;
                }
        }
@@ -677,8 +758,8 @@ out_unmap:
        return -1;
 }
 
-static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
-                                       int mask)
+static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,
+                                       struct mmap_params *mp)
 {
        int thread;
        int nr_threads = thread_map__nr(evlist->threads);
@@ -687,8 +768,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
        for (thread = 0; thread < nr_threads; thread++) {
                int output = -1;
 
-               if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0,
-                                               thread, &output))
+               if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread,
+                                               &output))
                        goto out_unmap;
        }
 
@@ -793,7 +874,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
        struct perf_evsel *evsel;
        const struct cpu_map *cpus = evlist->cpus;
        const struct thread_map *threads = evlist->threads;
-       int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask;
+       struct mmap_params mp = {
+               .prot = PROT_READ | (overwrite ? 0 : PROT_WRITE),
+       };
 
        if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
                return -ENOMEM;
@@ -804,7 +887,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
        evlist->overwrite = overwrite;
        evlist->mmap_len = perf_evlist__mmap_size(pages);
        pr_debug("mmap size %zuB\n", evlist->mmap_len);
-       mask = evlist->mmap_len - page_size - 1;
+       mp.mask = evlist->mmap_len - page_size - 1;
 
        evlist__for_each(evlist, evsel) {
                if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -814,9 +897,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
        }
 
        if (cpu_map__empty(cpus))
-               return perf_evlist__mmap_per_thread(evlist, prot, mask);
+               return perf_evlist__mmap_per_thread(evlist, &mp);
 
-       return perf_evlist__mmap_per_cpu(evlist, prot, mask);
+       return perf_evlist__mmap_per_cpu(evlist, &mp);
 }
 
 int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
@@ -1055,6 +1138,8 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
        }
 
        if (!evlist->workload.pid) {
+               int ret;
+
                if (pipe_output)
                        dup2(2, 1);
 
@@ -1072,8 +1157,22 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
                /*
                 * Wait until the parent tells us to go.
                 */
-               if (read(go_pipe[0], &bf, 1) == -1)
-                       perror("unable to read pipe");
+               ret = read(go_pipe[0], &bf, 1);
+               /*
+                * The parent will ask for the execvp() to be performed by
+                * writing exactly one byte, in workload.cork_fd, usually via
+                * perf_evlist__start_workload().
+                *
+                * For cancelling the workload without actuallin running it,
+                * the parent will just close workload.cork_fd, without writing
+                * anything, i.e. read will return zero and we just exit()
+                * here.
+                */
+               if (ret != 1) {
+                       if (ret == -1)
+                               perror("unable to read pipe");
+                       exit(ret);
+               }
 
                execvp(argv[0], (char **)argv);
 
@@ -1214,10 +1313,11 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
                                             "For your workloads it needs to be <= 1\nHint:\t");
                }
                printed += scnprintf(buf + printed, size - printed,
-                                    "For system wide tracing it needs to be set to -1");
+                                    "For system wide tracing it needs to be set to -1.\n");
 
                printed += scnprintf(buf + printed, size - printed,
-                                   ".\nHint:\tThe current value is %d.", value);
+                                   "Hint:\tTry: 'sudo sh -c \"echo -1 > /proc/sys/kernel/perf_event_paranoid\"'\n"
+                                   "Hint:\tThe current value is %d.", value);
                break;
        default:
                scnprintf(buf, size, "%s", emsg);
@@ -1243,3 +1343,19 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 
        list_splice(&move, &evlist->entries);
 }
+
+void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+                                    struct perf_evsel *tracking_evsel)
+{
+       struct perf_evsel *evsel;
+
+       if (tracking_evsel->tracking)
+               return;
+
+       evlist__for_each(evlist, evsel) {
+               if (evsel != tracking_evsel)
+                       evsel->tracking = false;
+       }
+
+       tracking_evsel->tracking = true;
+}