diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/evlist.c | 27 | ||||
-rw-r--r-- | tools/perf/util/evlist.h | 9 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 160 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 26 |
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 | |||
6 | struct perf_evlist *perf_evlist__new(void) | 9 | struct 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) | |||
29 | void perf_evlist__delete(struct perf_evlist *evlist) | 36 | void 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 | |||
80 | struct 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 | ||
6 | struct pollfd; | 7 | struct pollfd; |
7 | 8 | ||
9 | #define PERF_EVLIST__HLIST_BITS 8 | ||
10 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) | ||
11 | |||
8 | struct perf_evlist { | 12 | struct 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); | |||
23 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads); | 30 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads); |
24 | void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); | 31 | void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); |
25 | 32 | ||
33 | struct 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 | ||
13 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) | 17 | struct 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 | ||
36 | int 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 | |||
32 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) | 42 | int 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 | ||
55 | void perf_evsel__free_id(struct perf_evsel *evsel) | ||
56 | { | ||
57 | xyarray__delete(evsel->id); | ||
58 | evsel->id = NULL; | ||
59 | } | ||
60 | |||
45 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 61 | void 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 | ||
56 | void perf_evsel__munmap(struct perf_evsel *evsel, int ncpus, int nthreads) | 72 | void 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 | ||
71 | int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads) | 84 | int 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 | ||
77 | void perf_evsel__delete(struct perf_evsel *evsel) | 90 | void 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 | ||
238 | int perf_evsel__mmap(struct perf_evsel *evsel, struct cpu_map *cpus, | 251 | static 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 | |||
265 | static 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 | */ | ||
304 | int 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 | ||
270 | out_unmap: | 349 | out_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 | ||
27 | struct 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 | */ | ||
33 | struct perf_sample_id { | ||
34 | struct hlist_node node; | ||
35 | u64 id; | ||
36 | struct perf_evsel *evsel; | ||
37 | }; | ||
38 | |||
27 | struct perf_evsel { | 39 | struct 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); | |||
44 | void perf_evsel__delete(struct perf_evsel *evsel); | 55 | void perf_evsel__delete(struct perf_evsel *evsel); |
45 | 56 | ||
46 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 57 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
58 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); | ||
47 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); | 59 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); |
48 | int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads); | 60 | int perf_evlist__alloc_mmap(struct perf_evlist *evlist, int ncpus); |
49 | void perf_evsel__free_fd(struct perf_evsel *evsel); | 61 | void perf_evsel__free_fd(struct perf_evsel *evsel); |
62 | void perf_evsel__free_id(struct perf_evsel *evsel); | ||
50 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 63 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
51 | 64 | ||
52 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 65 | int 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); |
56 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 69 | int 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); |
58 | int perf_evsel__mmap(struct perf_evsel *evsel, struct cpu_map *cpus, | 71 | int 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); | 73 | void perf_evlist__munmap(struct perf_evlist *evlist, int ncpus); |
61 | void 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 && \ |