[PATCH V2 5/6] perf,tools: open/mmap event uses event's cpu map
From: Kan Liang
Date: Wed Apr 15 2015 - 11:08:56 EST
From: Kan Liang <kan.liang@xxxxxxxxx>
In perf_evlist__mmap, leader's fd has to be mmaped before member's fd.
So evlist__for_each must be the outermost of the loop.
Since different event's cpu list could vary, we cannot rely on the index
to get group leader's fd. In get_group_fd, the cpu id is used to get
correct fd.
Signed-off-by: Kan Liang <kan.liang@xxxxxxxxx>
---
tools/perf/util/evlist.c | 104 +++++++++++++++++++++++++++--------------------
tools/perf/util/evsel.c | 28 +++++++++----
2 files changed, 80 insertions(+), 52 deletions(-)
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 16319b4..637fcf4 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -834,51 +834,48 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
return 0;
}
-static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
- struct mmap_params *mp, int cpu,
- int thread, int *output)
+static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist,
+ struct perf_evsel *evsel,
+ int idx, struct mmap_params *mp,
+ int cpu, int thread, int *output)
{
- struct perf_evsel *evsel;
+ int fd;
- evlist__for_each(evlist, evsel) {
- int fd;
+ if (evsel->system_wide && thread)
+ return 0;
- if (evsel->system_wide && thread)
- continue;
+ fd = FD(evsel, cpu, thread);
- fd = FD(evsel, cpu, thread);
+ if (*output == -1) {
+ *output = fd;
+ if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0)
+ return -1;
+ } else {
+ if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
+ return -1;
- if (*output == -1) {
- *output = fd;
- if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0)
- return -1;
- } else {
- if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
- return -1;
+ perf_evlist__mmap_get(evlist, idx);
+ }
- perf_evlist__mmap_get(evlist, idx);
- }
+ /*
+ * The system_wide flag causes a selected event to be opened
+ * always without a pid. Consequently it will never get a
+ * POLLHUP, but it is used for tracking in combination with
+ * other events, so it should not need to be polled anyway.
+ * Therefore don't add it for polling.
+ */
+ if (!evsel->system_wide &&
+ __perf_evlist__add_pollfd(evlist, fd, idx) < 0) {
+ perf_evlist__mmap_put(evlist, idx);
+ return -1;
+ }
- /*
- * The system_wide flag causes a selected event to be opened
- * always without a pid. Consequently it will never get a
- * POLLHUP, but it is used for tracking in combination with
- * other events, so it should not need to be polled anyway.
- * Therefore don't add it for polling.
- */
- if (!evsel->system_wide &&
- __perf_evlist__add_pollfd(evlist, fd, idx) < 0) {
- perf_evlist__mmap_put(evlist, idx);
+ if (evsel->attr.read_format & PERF_FORMAT_ID) {
+ if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread,
+ fd) < 0)
return -1;
- }
-
- if (evsel->attr.read_format & PERF_FORMAT_ID) {
- if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread,
- fd) < 0)
- return -1;
- perf_evlist__set_sid_idx(evlist, evsel, idx, cpu,
- thread);
- }
+ perf_evlist__set_sid_idx(evlist, evsel, idx, cpu,
+ thread);
}
return 0;
@@ -890,23 +887,37 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,
int cpu, thread;
int nr_cpus = cpu_map__nr(evlist->cpus);
int nr_threads = thread_map__nr(evlist->threads);
+ int *output = malloc(nr_cpus * sizeof(int));
+ int evlist_cpu;
+ struct perf_evsel *evsel;
pr_debug2("perf event ring buffer mmapped per cpu\n");
- for (cpu = 0; cpu < nr_cpus; cpu++) {
- int output = -1;
- for (thread = 0; thread < nr_threads; thread++) {
- if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu,
- thread, &output))
+ for (cpu = 0; cpu < nr_cpus; cpu++)
+ output[cpu] = -1;
+
+ evlist__for_each(evlist, evsel) {
+ for (cpu = 0; cpu < cpu_map__nr(evsel->cpus); cpu++) {
+ evlist_cpu = perf_evsel__get_cpumap_index(evsel->cpus->map[cpu], evlist->cpus);
+ if (evlist_cpu < 0)
goto out_unmap;
+
+ for (thread = 0; thread < nr_threads; thread++) {
+ if (perf_evlist__mmap_per_evsel(evlist, evsel, evlist_cpu,
+ mp, cpu, thread,
+ &output[evlist_cpu]))
+ goto out_unmap;
+ }
}
}
+ free(output);
return 0;
out_unmap:
for (cpu = 0; cpu < nr_cpus; cpu++)
__perf_evlist__munmap(evlist, cpu);
+ free(output);
return -1;
}
@@ -915,14 +926,17 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,
{
int thread;
int nr_threads = thread_map__nr(evlist->threads);
+ struct perf_evsel *evsel;
pr_debug2("perf event ring buffer mmapped per thread\n");
for (thread = 0; thread < nr_threads; thread++) {
int output = -1;
- if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread,
- &output))
- goto out_unmap;
+ evlist__for_each(evlist, evsel) {
+ if (perf_evlist__mmap_per_evsel(evlist, evsel, thread,
+ mp, 0, thread, &output))
+ goto out_unmap;
+ }
}
return 0;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index e177f43..44a663c 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1008,7 +1008,7 @@ int perf_evsel__get_cpumap_index(int cpu, struct cpu_map *evsel_cpus)
static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
{
struct perf_evsel *leader = evsel->leader;
- int fd;
+ int fd, leader_cpu;
if (perf_evsel__is_group_leader(evsel))
return -1;
@@ -1019,7 +1019,15 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
*/
BUG_ON(!leader->fd);
- fd = FD(leader, cpu, thread);
+ if (cpu < 0)
+ fd = FD(leader, 0, thread);
+ else {
+ leader_cpu = perf_evsel__get_cpumap_index(cpu, leader->cpus);
+ if (leader_cpu >= 0)
+ fd = FD(leader, leader_cpu, thread);
+ else
+ return -1;
+ }
BUG_ON(fd == -1);
return fd;
@@ -1151,15 +1159,21 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
int cpu, thread, nthreads;
unsigned long flags = PERF_FLAG_FD_CLOEXEC;
int pid = -1, err;
+ struct cpu_map *cpumap;
enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
+ if (evsel->cpus)
+ cpumap = evsel->cpus;
+ else
+ cpumap = cpus;
+
if (evsel->system_wide)
nthreads = 1;
else
nthreads = threads->nr;
if (evsel->fd == NULL &&
- perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0)
+ perf_evsel__alloc_fd(evsel, cpumap->nr, nthreads) < 0)
return -ENOMEM;
if (evsel->cgrp) {
@@ -1191,7 +1205,7 @@ retry_sample_id:
fprintf(stderr, "%.60s\n", graph_dotted_line);
}
- for (cpu = 0; cpu < cpus->nr; cpu++) {
+ for (cpu = 0; cpu < cpumap->nr; cpu++) {
for (thread = 0; thread < nthreads; thread++) {
int group_fd;
@@ -1199,14 +1213,14 @@ retry_sample_id:
if (!evsel->cgrp && !evsel->system_wide)
pid = threads->map[thread];
- group_fd = get_group_fd(evsel, cpu, thread);
+ group_fd = get_group_fd(evsel, cpumap->map[cpu], thread);
retry_open:
pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx\n",
- pid, cpus->map[cpu], group_fd, flags);
+ pid, cpumap->map[cpu], group_fd, flags);
FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
pid,
- cpus->map[cpu],
+ cpumap->map[cpu],
group_fd, flags);
if (FD(evsel, cpu, thread) < 0) {
err = -errno;
--
1.8.3.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/