aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-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
4 files changed, 173 insertions, 49 deletions
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 && \