aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-01-12 19:39:13 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-01-22 16:56:29 -0500
commit70db7533caef02350ec8d6852e589491bca3a951 (patch)
tree463dadbec60d585cb8c1de84b230378010d5c8b5 /tools
parent115d2d8963a426670ac3ce983fc4c4e001703943 (diff)
perf evlist: Move the mmap array from perf_evsel
Adopting the new model used in 'perf record', where we don't have a map per thread per cpu, instead we have an mmap per cpu, established on the first fd for that cpu and ask the kernel using the PERF_EVENT_IOC_SET_OUTPUT ioctl to send events for the other fds on that cpu for the one with the mmap. The methods moved from perf_evsel to perf_evlist, but for easing review they were modified in place, in evsel.c, the next patch will move the migrated methods to evlist.c. With this 'perf top' now uses the same mmap model used by 'perf record' and the next patches will make 'perf record' use these new routines, establishing a common codebase for both tools. Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/builtin-top.c56
-rw-r--r--tools/perf/util/evlist.c27
-rw-r--r--tools/perf/util/evlist.h9
-rw-r--r--tools/perf/util/evsel.c160
-rw-r--r--tools/perf/util/evsel.h26
5 files changed, 201 insertions, 77 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 7d723ad0bfa9..df85c1f9417b 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -78,7 +78,7 @@ static struct cpu_map *cpus;
78static int realtime_prio = 0; 78static int realtime_prio = 0;
79static bool group = false; 79static bool group = false;
80static unsigned int page_size; 80static unsigned int page_size;
81static unsigned int mmap_pages = 16; 81static unsigned int mmap_pages = 128;
82static int freq = 1000; /* 1 KHz */ 82static int freq = 1000; /* 1 KHz */
83 83
84static int delay_secs = 2; 84static int delay_secs = 2;
@@ -991,8 +991,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)
991 991
992static void event__process_sample(const event_t *self, 992static void event__process_sample(const event_t *self,
993 struct sample_data *sample, 993 struct sample_data *sample,
994 struct perf_session *session, 994 struct perf_session *session)
995 struct perf_evsel *evsel)
996{ 995{
997 u64 ip = self->ip.ip; 996 u64 ip = self->ip.ip;
998 struct sym_entry *syme; 997 struct sym_entry *syme;
@@ -1085,8 +1084,12 @@ static void event__process_sample(const event_t *self,
1085 1084
1086 syme = symbol__priv(al.sym); 1085 syme = symbol__priv(al.sym);
1087 if (!syme->skip) { 1086 if (!syme->skip) {
1088 syme->count[evsel->idx]++; 1087 struct perf_evsel *evsel;
1088
1089 syme->origin = origin; 1089 syme->origin = origin;
1090 evsel = perf_evlist__id2evsel(evsel_list, sample->id);
1091 assert(evsel != NULL);
1092 syme->count[evsel->idx]++;
1090 record_precise_ip(syme, evsel->idx, ip); 1093 record_precise_ip(syme, evsel->idx, ip);
1091 pthread_mutex_lock(&active_symbols_lock); 1094 pthread_mutex_lock(&active_symbols_lock);
1092 if (list_empty(&syme->node) || !syme->node.next) 1095 if (list_empty(&syme->node) || !syme->node.next)
@@ -1095,11 +1098,9 @@ static void event__process_sample(const event_t *self,
1095 } 1098 }
1096} 1099}
1097 1100
1098static void perf_session__mmap_read_counter(struct perf_session *self, 1101static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu)
1099 struct perf_evsel *evsel,
1100 int cpu, int thread_idx)
1101{ 1102{
1102 struct perf_mmap *md = xyarray__entry(evsel->mmap, cpu, thread_idx); 1103 struct perf_mmap *md = &evsel_list->mmap[cpu];
1103 unsigned int head = perf_mmap__read_head(md); 1104 unsigned int head = perf_mmap__read_head(md);
1104 unsigned int old = md->prev; 1105 unsigned int old = md->prev;
1105 unsigned char *data = md->base + page_size; 1106 unsigned char *data = md->base + page_size;
@@ -1153,7 +1154,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self,
1153 1154
1154 event__parse_sample(event, self, &sample); 1155 event__parse_sample(event, self, &sample);
1155 if (event->header.type == PERF_RECORD_SAMPLE) 1156 if (event->header.type == PERF_RECORD_SAMPLE)
1156 event__process_sample(event, &sample, self, evsel); 1157 event__process_sample(event, &sample, self);
1157 else 1158 else
1158 event__process(event, &sample, self); 1159 event__process(event, &sample, self);
1159 old += size; 1160 old += size;
@@ -1164,19 +1165,10 @@ static void perf_session__mmap_read_counter(struct perf_session *self,
1164 1165
1165static void perf_session__mmap_read(struct perf_session *self) 1166static void perf_session__mmap_read(struct perf_session *self)
1166{ 1167{
1167 struct perf_evsel *counter; 1168 int i;
1168 int i, thread_index; 1169
1169 1170 for (i = 0; i < cpus->nr; i++)
1170 for (i = 0; i < cpus->nr; i++) { 1171 perf_session__mmap_read_cpu(self, i);
1171 list_for_each_entry(counter, &evsel_list->entries, node) {
1172 for (thread_index = 0;
1173 thread_index < threads->nr;
1174 thread_index++) {
1175 perf_session__mmap_read_counter(self,
1176 counter, i, thread_index);
1177 }
1178 }
1179 }
1180} 1172}
1181 1173
1182static void start_counters(struct perf_evlist *evlist) 1174static void start_counters(struct perf_evlist *evlist)
@@ -1194,6 +1186,11 @@ static void start_counters(struct perf_evlist *evlist)
1194 attr->sample_freq = freq; 1186 attr->sample_freq = freq;
1195 } 1187 }
1196 1188
1189 if (evlist->nr_entries > 1) {
1190 attr->sample_type |= PERF_SAMPLE_ID;
1191 attr->read_format |= PERF_FORMAT_ID;
1192 }
1193
1197 attr->mmap = 1; 1194 attr->mmap = 1;
1198try_again: 1195try_again:
1199 if (perf_evsel__open(counter, cpus, threads, group, inherit) < 0) { 1196 if (perf_evsel__open(counter, cpus, threads, group, inherit) < 0) {
@@ -1225,15 +1222,16 @@ try_again:
1225 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 1222 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
1226 exit(-1); 1223 exit(-1);
1227 } 1224 }
1228
1229 if (perf_evsel__mmap(counter, cpus, threads, mmap_pages, evlist) < 0)
1230 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1231 } 1225 }
1226
1227 if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, true) < 0)
1228 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1232} 1229}
1233 1230
1234static int __cmd_top(void) 1231static int __cmd_top(void)
1235{ 1232{
1236 pthread_t thread; 1233 pthread_t thread;
1234 struct perf_evsel *first;
1237 int ret; 1235 int ret;
1238 /* 1236 /*
1239 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 1237 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
@@ -1249,6 +1247,8 @@ static int __cmd_top(void)
1249 event__synthesize_threads(event__process, session); 1247 event__synthesize_threads(event__process, session);
1250 1248
1251 start_counters(evsel_list); 1249 start_counters(evsel_list);
1250 first = list_entry(evsel_list->entries.next, struct perf_evsel, node);
1251 perf_session__set_sample_type(session, first->attr.sample_type);
1252 1252
1253 /* Wait for a minimal set of events before starting the snapshot */ 1253 /* Wait for a minimal set of events before starting the snapshot */
1254 poll(evsel_list->pollfd, evsel_list->nr_fds, 100); 1254 poll(evsel_list->pollfd, evsel_list->nr_fds, 100);
@@ -1394,8 +1394,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1394 usage_with_options(top_usage, options); 1394 usage_with_options(top_usage, options);
1395 1395
1396 list_for_each_entry(pos, &evsel_list->entries, node) { 1396 list_for_each_entry(pos, &evsel_list->entries, node) {
1397 if (perf_evsel__alloc_mmap(pos, cpus->nr, threads->nr) < 0 || 1397 if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
1398 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
1399 goto out_free_fd; 1398 goto out_free_fd;
1400 /* 1399 /*
1401 * Fill in the ones not specifically initialized via -c: 1400 * Fill in the ones not specifically initialized via -c:
@@ -1406,7 +1405,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1406 pos->attr.sample_period = default_interval; 1405 pos->attr.sample_period = default_interval;
1407 } 1406 }
1408 1407
1409 if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0) 1408 if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0 ||
1409 perf_evlist__alloc_mmap(evsel_list, cpus->nr) < 0)
1410 goto out_free_fd; 1410 goto out_free_fd;
1411 1411
1412 sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node); 1412 sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 6d4129214ee8..deb82a4fc312 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -3,11 +3,18 @@
3#include "evsel.h" 3#include "evsel.h"
4#include "util.h" 4#include "util.h"
5 5
6#include <linux/bitops.h>
7#include <linux/hash.h>
8
6struct perf_evlist *perf_evlist__new(void) 9struct perf_evlist *perf_evlist__new(void)
7{ 10{
8 struct perf_evlist *evlist = zalloc(sizeof(*evlist)); 11 struct perf_evlist *evlist = zalloc(sizeof(*evlist));
9 12
10 if (evlist != NULL) { 13 if (evlist != NULL) {
14 int i;
15
16 for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
17 INIT_HLIST_HEAD(&evlist->heads[i]);
11 INIT_LIST_HEAD(&evlist->entries); 18 INIT_LIST_HEAD(&evlist->entries);
12 } 19 }
13 20
@@ -29,6 +36,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
29void perf_evlist__delete(struct perf_evlist *evlist) 36void perf_evlist__delete(struct perf_evlist *evlist)
30{ 37{
31 perf_evlist__purge(evlist); 38 perf_evlist__purge(evlist);
39 free(evlist->mmap);
32 free(evlist->pollfd); 40 free(evlist->pollfd);
33 free(evlist); 41 free(evlist);
34} 42}
@@ -68,3 +76,22 @@ void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
68 evlist->pollfd[evlist->nr_fds].events = POLLIN; 76 evlist->pollfd[evlist->nr_fds].events = POLLIN;
69 evlist->nr_fds++; 77 evlist->nr_fds++;
70} 78}
79
80struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
81{
82 struct hlist_head *head;
83 struct hlist_node *pos;
84 struct perf_sample_id *sid;
85 int hash;
86
87 if (evlist->nr_entries == 1)
88 return list_entry(evlist->entries.next, struct perf_evsel, node);
89
90 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
91 head = &evlist->heads[hash];
92
93 hlist_for_each_entry(sid, pos, head, node)
94 if (sid->id == id)
95 return sid->evsel;
96 return NULL;
97}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 16bbfcba8ca8..dbfcc79bb995 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -2,13 +2,20 @@
2#define __PERF_EVLIST_H 1 2#define __PERF_EVLIST_H 1
3 3
4#include <linux/list.h> 4#include <linux/list.h>
5#include "../perf.h"
5 6
6struct pollfd; 7struct pollfd;
7 8
9#define PERF_EVLIST__HLIST_BITS 8
10#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
11
8struct perf_evlist { 12struct perf_evlist {
9 struct list_head entries; 13 struct list_head entries;
14 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
10 int nr_entries; 15 int nr_entries;
11 int nr_fds; 16 int nr_fds;
17 int mmap_len;
18 struct perf_mmap *mmap;
12 struct pollfd *pollfd; 19 struct pollfd *pollfd;
13}; 20};
14 21
@@ -23,4 +30,6 @@ int perf_evlist__add_default(struct perf_evlist *evlist);
23int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads); 30int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads);
24void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); 31void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
25 32
33struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
34
26#endif /* __PERF_EVLIST_H */ 35#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index f5006958f8da..ee490356c817 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -8,7 +8,11 @@
8#include <unistd.h> 8#include <unistd.h>
9#include <sys/mman.h> 9#include <sys/mman.h>
10 10
11#include <linux/bitops.h>
12#include <linux/hash.h>
13
11#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 14#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
15#define SID(e, x, y) xyarray__entry(e->id, x, y)
12 16
13struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 17struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
14{ 18{
@@ -29,6 +33,12 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
29 return evsel->fd != NULL ? 0 : -ENOMEM; 33 return evsel->fd != NULL ? 0 : -ENOMEM;
30} 34}
31 35
36int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
37{
38 evsel->id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
39 return evsel->id != NULL ? 0 : -ENOMEM;
40}
41
32int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 42int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
33{ 43{
34 evsel->counts = zalloc((sizeof(*evsel->counts) + 44 evsel->counts = zalloc((sizeof(*evsel->counts) +
@@ -42,6 +52,12 @@ void perf_evsel__free_fd(struct perf_evsel *evsel)
42 evsel->fd = NULL; 52 evsel->fd = NULL;
43} 53}
44 54
55void perf_evsel__free_id(struct perf_evsel *evsel)
56{
57 xyarray__delete(evsel->id);
58 evsel->id = NULL;
59}
60
45void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 61void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
46{ 62{
47 int cpu, thread; 63 int cpu, thread;
@@ -53,32 +69,29 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
53 } 69 }
54} 70}
55 71
56void perf_evsel__munmap(struct perf_evsel *evsel, int ncpus, int nthreads) 72void perf_evlist__munmap(struct perf_evlist *evlist, int ncpus)
57{ 73{
58 struct perf_mmap *mm; 74 int cpu;
59 int cpu, thread;
60 75
61 for (cpu = 0; cpu < ncpus; cpu++) 76 for (cpu = 0; cpu < ncpus; cpu++) {
62 for (thread = 0; thread < nthreads; ++thread) { 77 if (evlist->mmap[cpu].base != NULL) {
63 mm = xyarray__entry(evsel->mmap, cpu, thread); 78 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
64 if (mm->base != NULL) { 79 evlist->mmap[cpu].base = NULL;
65 munmap(mm->base, evsel->mmap_len);
66 mm->base = NULL;
67 }
68 } 80 }
81 }
69} 82}
70 83
71int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads) 84int perf_evlist__alloc_mmap(struct perf_evlist *evlist, int ncpus)
72{ 85{
73 evsel->mmap = xyarray__new(ncpus, nthreads, sizeof(struct perf_mmap)); 86 evlist->mmap = zalloc(ncpus * sizeof(struct perf_mmap));
74 return evsel->mmap != NULL ? 0 : -ENOMEM; 87 return evlist->mmap != NULL ? 0 : -ENOMEM;
75} 88}
76 89
77void perf_evsel__delete(struct perf_evsel *evsel) 90void perf_evsel__delete(struct perf_evsel *evsel)
78{ 91{
79 assert(list_empty(&evsel->node)); 92 assert(list_empty(&evsel->node));
80 xyarray__delete(evsel->fd); 93 xyarray__delete(evsel->fd);
81 xyarray__delete(evsel->mmap); 94 xyarray__delete(evsel->id);
82 free(evsel); 95 free(evsel);
83} 96}
84 97
@@ -235,47 +248,110 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel,
235 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit); 248 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit);
236} 249}
237 250
238int perf_evsel__mmap(struct perf_evsel *evsel, struct cpu_map *cpus, 251static int __perf_evlist__mmap(struct perf_evlist *evlist, int cpu, int prot,
239 struct thread_map *threads, int pages, 252 int mask, int fd)
240 struct perf_evlist *evlist) 253{
254 evlist->mmap[cpu].prev = 0;
255 evlist->mmap[cpu].mask = mask;
256 evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot,
257 MAP_SHARED, fd, 0);
258 if (evlist->mmap[cpu].base == MAP_FAILED)
259 return -1;
260
261 perf_evlist__add_pollfd(evlist, fd);
262 return 0;
263}
264
265static int perf_evlist__id_hash(struct perf_evlist *evlist, struct perf_evsel *evsel,
266 int cpu, int thread, int fd)
267{
268 struct perf_sample_id *sid;
269 u64 read_data[4] = { 0, };
270 int hash, id_idx = 1; /* The first entry is the counter value */
271
272 if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
273 read(fd, &read_data, sizeof(read_data)) == -1)
274 return -1;
275
276 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
277 ++id_idx;
278 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
279 ++id_idx;
280
281 sid = SID(evsel, cpu, thread);
282 sid->id = read_data[id_idx];
283 sid->evsel = evsel;
284 hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
285 hlist_add_head(&sid->node, &evlist->heads[hash]);
286 return 0;
287}
288
289/** perf_evlist__mmap - Create per cpu maps to receive events
290 *
291 * @evlist - list of events
292 * @cpus - cpu map being monitored
293 * @threads - threads map being monitored
294 * @pages - map length in pages
295 * @overwrite - overwrite older events?
296 *
297 * If overwrite is false the user needs to signal event consuption using:
298 *
299 * struct perf_mmap *m = &evlist->mmap[cpu];
300 * unsigned int head = perf_mmap__read_head(m);
301 *
302 * perf_mmap__write_tail(m, head)
303 */
304int perf_evlist__mmap(struct perf_evlist *evlist, struct cpu_map *cpus,
305 struct thread_map *threads, int pages, bool overwrite)
241{ 306{
242 unsigned int page_size = sysconf(_SC_PAGE_SIZE); 307 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
243 int mask = pages * page_size - 1, cpu; 308 int mask = pages * page_size - 1, cpu;
244 struct perf_mmap *mm; 309 struct perf_evsel *first_evsel, *evsel;
245 int thread; 310 int thread, prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
246 311
247 if (evsel->mmap == NULL && 312 if (evlist->mmap == NULL &&
248 perf_evsel__alloc_mmap(evsel, cpus->nr, threads->nr) < 0) 313 perf_evlist__alloc_mmap(evlist, cpus->nr) < 0)
249 return -ENOMEM; 314 return -ENOMEM;
250 315
251 evsel->mmap_len = (pages + 1) * page_size; 316 if (evlist->pollfd == NULL &&
317 perf_evlist__alloc_pollfd(evlist, cpus->nr, threads->nr) < 0)
318 return -ENOMEM;
252 319
253 for (cpu = 0; cpu < cpus->nr; cpu++) { 320 evlist->mmap_len = (pages + 1) * page_size;
254 for (thread = 0; thread < threads->nr; thread++) { 321 first_evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
255 mm = xyarray__entry(evsel->mmap, cpu, thread); 322
256 mm->prev = 0; 323 list_for_each_entry(evsel, &evlist->entries, node) {
257 mm->mask = mask; 324 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
258 mm->base = mmap(NULL, evsel->mmap_len, PROT_READ, 325 evsel->id == NULL &&
259 MAP_SHARED, FD(evsel, cpu, thread), 0); 326 perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
260 if (mm->base == MAP_FAILED) 327 return -ENOMEM;
261 goto out_unmap; 328
262 329 for (cpu = 0; cpu < cpus->nr; cpu++) {
263 if (evlist != NULL) 330 for (thread = 0; thread < threads->nr; thread++) {
264 perf_evlist__add_pollfd(evlist, FD(evsel, cpu, thread)); 331 int fd = FD(evsel, cpu, thread);
332
333 if (evsel->idx || thread) {
334 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT,
335 FD(first_evsel, cpu, 0)) != 0)
336 goto out_unmap;
337 } else if (__perf_evlist__mmap(evlist, cpu, prot, mask, fd) < 0)
338 goto out_unmap;
339
340 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
341 perf_evlist__id_hash(evlist, evsel, cpu, thread, fd) < 0)
342 goto out_unmap;
343 }
265 } 344 }
266 } 345 }
267 346
268 return 0; 347 return 0;
269 348
270out_unmap: 349out_unmap:
271 do { 350 for (cpu = 0; cpu < cpus->nr; cpu++) {
272 while (--thread >= 0) { 351 if (evlist->mmap[cpu].base != NULL) {
273 mm = xyarray__entry(evsel->mmap, cpu, thread); 352 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
274 munmap(mm->base, evsel->mmap_len); 353 evlist->mmap[cpu].base = NULL;
275 mm->base = NULL;
276 } 354 }
277 thread = threads->nr; 355 }
278 } while (--cpu >= 0);
279
280 return -1; 356 return -1;
281} 357}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index c8fbef299436..667ee4e2e35e 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -24,14 +24,25 @@ struct perf_counts {
24 struct perf_counts_values cpu[]; 24 struct perf_counts_values cpu[];
25}; 25};
26 26
27struct perf_evsel;
28
29/*
30 * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are
31 * more than one entry in the evlist.
32 */
33struct perf_sample_id {
34 struct hlist_node node;
35 u64 id;
36 struct perf_evsel *evsel;
37};
38
27struct perf_evsel { 39struct perf_evsel {
28 struct list_head node; 40 struct list_head node;
29 struct perf_event_attr attr; 41 struct perf_event_attr attr;
30 char *filter; 42 char *filter;
31 struct xyarray *fd; 43 struct xyarray *fd;
32 struct xyarray *mmap; 44 struct xyarray *id;
33 struct perf_counts *counts; 45 struct perf_counts *counts;
34 size_t mmap_len;
35 int idx; 46 int idx;
36 void *priv; 47 void *priv;
37}; 48};
@@ -44,9 +55,11 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
44void perf_evsel__delete(struct perf_evsel *evsel); 55void perf_evsel__delete(struct perf_evsel *evsel);
45 56
46int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 57int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
58int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
47int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 59int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
48int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads); 60int perf_evlist__alloc_mmap(struct perf_evlist *evlist, int ncpus);
49void perf_evsel__free_fd(struct perf_evsel *evsel); 61void perf_evsel__free_fd(struct perf_evsel *evsel);
62void perf_evsel__free_id(struct perf_evsel *evsel);
50void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 63void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
51 64
52int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 65int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
@@ -55,10 +68,9 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel,
55 struct thread_map *threads, bool group, bool inherit); 68 struct thread_map *threads, bool group, bool inherit);
56int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 69int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
57 struct thread_map *threads, bool group, bool inherit); 70 struct thread_map *threads, bool group, bool inherit);
58int perf_evsel__mmap(struct perf_evsel *evsel, struct cpu_map *cpus, 71int perf_evlist__mmap(struct perf_evlist *evlist, struct cpu_map *cpus,
59 struct thread_map *threads, int pages, 72 struct thread_map *threads, int pages, bool overwrite);
60 struct perf_evlist *evlist); 73void perf_evlist__munmap(struct perf_evlist *evlist, int ncpus);
61void perf_evsel__munmap(struct perf_evsel *evsel, int ncpus, int nthreads);
62 74
63#define perf_evsel__match(evsel, t, c) \ 75#define perf_evsel__match(evsel, t, c) \
64 (evsel->attr.type == PERF_TYPE_##t && \ 76 (evsel->attr.type == PERF_TYPE_##t && \