1 /*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9 #include <poll.h>
10 #include "cpumap.h"
11 #include "thread_map.h"
12 #include "evlist.h"
13 #include "evsel.h"
14 #include "util.h"
15
16 #include <sys/mman.h>
17
18 /* ANDROID_CHANGE_BEGIN */
19 #if 0
20 #include <linux/bitops.h>
21 #include <linux/hash.h>
22 #else
23 #include "include/linux/bitops.h"
24 #include "include/linux/hash.h"
25 #endif
26 /* ANDROID_CHANGE_END */
27
28 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
29 #define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
30
perf_evlist__init(struct perf_evlist * evlist,struct cpu_map * cpus,struct thread_map * threads)31 void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
32 struct thread_map *threads)
33 {
34 int i;
35
36 for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
37 INIT_HLIST_HEAD(&evlist->heads[i]);
38 INIT_LIST_HEAD(&evlist->entries);
39 perf_evlist__set_maps(evlist, cpus, threads);
40 }
41
perf_evlist__new(struct cpu_map * cpus,struct thread_map * threads)42 struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
43 struct thread_map *threads)
44 {
45 struct perf_evlist *evlist = zalloc(sizeof(*evlist));
46
47 if (evlist != NULL)
48 perf_evlist__init(evlist, cpus, threads);
49
50 return evlist;
51 }
52
perf_evlist__purge(struct perf_evlist * evlist)53 static void perf_evlist__purge(struct perf_evlist *evlist)
54 {
55 struct perf_evsel *pos, *n;
56
57 list_for_each_entry_safe(pos, n, &evlist->entries, node) {
58 list_del_init(&pos->node);
59 perf_evsel__delete(pos);
60 }
61
62 evlist->nr_entries = 0;
63 }
64
perf_evlist__exit(struct perf_evlist * evlist)65 void perf_evlist__exit(struct perf_evlist *evlist)
66 {
67 free(evlist->mmap);
68 free(evlist->pollfd);
69 evlist->mmap = NULL;
70 evlist->pollfd = NULL;
71 }
72
perf_evlist__delete(struct perf_evlist * evlist)73 void perf_evlist__delete(struct perf_evlist *evlist)
74 {
75 perf_evlist__purge(evlist);
76 perf_evlist__exit(evlist);
77 free(evlist);
78 }
79
perf_evlist__add(struct perf_evlist * evlist,struct perf_evsel * entry)80 void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
81 {
82 list_add_tail(&entry->node, &evlist->entries);
83 ++evlist->nr_entries;
84 }
85
perf_evlist__add_default(struct perf_evlist * evlist)86 int perf_evlist__add_default(struct perf_evlist *evlist)
87 {
88 struct perf_event_attr attr = {
89 .type = PERF_TYPE_HARDWARE,
90 .config = PERF_COUNT_HW_CPU_CYCLES,
91 };
92 struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
93
94 if (evsel == NULL)
95 return -ENOMEM;
96
97 perf_evlist__add(evlist, evsel);
98 return 0;
99 }
100
perf_evlist__alloc_pollfd(struct perf_evlist * evlist)101 int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
102 {
103 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
104 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
105 return evlist->pollfd != NULL ? 0 : -ENOMEM;
106 }
107
perf_evlist__add_pollfd(struct perf_evlist * evlist,int fd)108 void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
109 {
110 fcntl(fd, F_SETFL, O_NONBLOCK);
111 evlist->pollfd[evlist->nr_fds].fd = fd;
112 evlist->pollfd[evlist->nr_fds].events = POLLIN;
113 evlist->nr_fds++;
114 }
115
perf_evlist__id_hash(struct perf_evlist * evlist,struct perf_evsel * evsel,int cpu,int thread,u64 id)116 static void perf_evlist__id_hash(struct perf_evlist *evlist,
117 struct perf_evsel *evsel,
118 int cpu, int thread, u64 id)
119 {
120 int hash;
121 struct perf_sample_id *sid = SID(evsel, cpu, thread);
122
123 sid->id = id;
124 sid->evsel = evsel;
125 hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
126 hlist_add_head(&sid->node, &evlist->heads[hash]);
127 }
128
perf_evlist__id_add(struct perf_evlist * evlist,struct perf_evsel * evsel,int cpu,int thread,u64 id)129 void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
130 int cpu, int thread, u64 id)
131 {
132 perf_evlist__id_hash(evlist, evsel, cpu, thread, id);
133 evsel->id[evsel->ids++] = id;
134 }
135
perf_evlist__id_add_fd(struct perf_evlist * evlist,struct perf_evsel * evsel,int cpu,int thread,int fd)136 static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
137 struct perf_evsel *evsel,
138 int cpu, int thread, int fd)
139 {
140 u64 read_data[4] = { 0, };
141 int id_idx = 1; /* The first entry is the counter value */
142
143 if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
144 read(fd, &read_data, sizeof(read_data)) == -1)
145 return -1;
146
147 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
148 ++id_idx;
149 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
150 ++id_idx;
151
152 perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]);
153 return 0;
154 }
155
perf_evlist__id2evsel(struct perf_evlist * evlist,u64 id)156 struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
157 {
158 struct hlist_head *head;
159 struct hlist_node *pos;
160 struct perf_sample_id *sid;
161 int hash;
162
163 if (evlist->nr_entries == 1)
164 return list_entry(evlist->entries.next, struct perf_evsel, node);
165
166 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
167 head = &evlist->heads[hash];
168
169 hlist_for_each_entry(sid, pos, head, node)
170 if (sid->id == id)
171 return sid->evsel;
172 return NULL;
173 }
174
perf_evlist__mmap_read(struct perf_evlist * evlist,int idx)175 union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
176 {
177 /* XXX Move this to perf.c, making it generally available */
178 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
179 struct perf_mmap *md = &evlist->mmap[idx];
180 unsigned int head = perf_mmap__read_head(md);
181 unsigned int old = md->prev;
182 unsigned char *data = md->base + page_size;
183 union perf_event *event = NULL;
184
185 if (evlist->overwrite) {
186 /*
187 * If we're further behind than half the buffer, there's a chance
188 * the writer will bite our tail and mess up the samples under us.
189 *
190 * If we somehow ended up ahead of the head, we got messed up.
191 *
192 * In either case, truncate and restart at head.
193 */
194 int diff = head - old;
195 if (diff > md->mask / 2 || diff < 0) {
196 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
197
198 /*
199 * head points to a known good entry, start there.
200 */
201 old = head;
202 }
203 }
204
205 if (old != head) {
206 size_t size;
207
208 event = (union perf_event *)&data[old & md->mask];
209 size = event->header.size;
210
211 /*
212 * Event straddles the mmap boundary -- header should always
213 * be inside due to u64 alignment of output.
214 */
215 if ((old & md->mask) + size != ((old + size) & md->mask)) {
216 unsigned int offset = old;
217 unsigned int len = min(sizeof(*event), size), cpy;
218 void *dst = &evlist->event_copy;
219
220 do {
221 cpy = min(md->mask + 1 - (offset & md->mask), len);
222 memcpy(dst, &data[offset & md->mask], cpy);
223 offset += cpy;
224 dst += cpy;
225 len -= cpy;
226 } while (len);
227
228 event = &evlist->event_copy;
229 }
230
231 old += size;
232 }
233
234 md->prev = old;
235
236 if (!evlist->overwrite)
237 perf_mmap__write_tail(md, old);
238
239 return event;
240 }
241
perf_evlist__munmap(struct perf_evlist * evlist)242 void perf_evlist__munmap(struct perf_evlist *evlist)
243 {
244 int i;
245
246 for (i = 0; i < evlist->nr_mmaps; i++) {
247 if (evlist->mmap[i].base != NULL) {
248 munmap(evlist->mmap[i].base, evlist->mmap_len);
249 evlist->mmap[i].base = NULL;
250 }
251 }
252
253 free(evlist->mmap);
254 evlist->mmap = NULL;
255 }
256
perf_evlist__alloc_mmap(struct perf_evlist * evlist)257 int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
258 {
259 evlist->nr_mmaps = evlist->cpus->nr;
260 if (evlist->cpus->map[0] == -1)
261 evlist->nr_mmaps = evlist->threads->nr;
262 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
263 return evlist->mmap != NULL ? 0 : -ENOMEM;
264 }
265
__perf_evlist__mmap(struct perf_evlist * evlist,int idx,int prot,int mask,int fd)266 static int __perf_evlist__mmap(struct perf_evlist *evlist,
267 int idx, int prot, int mask, int fd)
268 {
269 evlist->mmap[idx].prev = 0;
270 evlist->mmap[idx].mask = mask;
271 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
272 MAP_SHARED, fd, 0);
273 if (evlist->mmap[idx].base == MAP_FAILED)
274 return -1;
275
276 perf_evlist__add_pollfd(evlist, fd);
277 return 0;
278 }
279
perf_evlist__mmap_per_cpu(struct perf_evlist * evlist,int prot,int mask)280 static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask)
281 {
282 struct perf_evsel *evsel;
283 int cpu, thread;
284
285 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
286 int output = -1;
287
288 for (thread = 0; thread < evlist->threads->nr; thread++) {
289 list_for_each_entry(evsel, &evlist->entries, node) {
290 int fd = FD(evsel, cpu, thread);
291
292 if (output == -1) {
293 output = fd;
294 if (__perf_evlist__mmap(evlist, cpu,
295 prot, mask, output) < 0)
296 goto out_unmap;
297 } else {
298 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
299 goto out_unmap;
300 }
301
302 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
303 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
304 goto out_unmap;
305 }
306 }
307 }
308
309 return 0;
310
311 out_unmap:
312 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
313 if (evlist->mmap[cpu].base != NULL) {
314 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
315 evlist->mmap[cpu].base = NULL;
316 }
317 }
318 return -1;
319 }
320
perf_evlist__mmap_per_thread(struct perf_evlist * evlist,int prot,int mask)321 static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask)
322 {
323 struct perf_evsel *evsel;
324 int thread;
325
326 for (thread = 0; thread < evlist->threads->nr; thread++) {
327 int output = -1;
328
329 list_for_each_entry(evsel, &evlist->entries, node) {
330 int fd = FD(evsel, 0, thread);
331
332 if (output == -1) {
333 output = fd;
334 if (__perf_evlist__mmap(evlist, thread,
335 prot, mask, output) < 0)
336 goto out_unmap;
337 } else {
338 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
339 goto out_unmap;
340 }
341
342 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
343 perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0)
344 goto out_unmap;
345 }
346 }
347
348 return 0;
349
350 out_unmap:
351 for (thread = 0; thread < evlist->threads->nr; thread++) {
352 if (evlist->mmap[thread].base != NULL) {
353 munmap(evlist->mmap[thread].base, evlist->mmap_len);
354 evlist->mmap[thread].base = NULL;
355 }
356 }
357 return -1;
358 }
359
360 /** perf_evlist__mmap - Create per cpu maps to receive events
361 *
362 * @evlist - list of events
363 * @pages - map length in pages
364 * @overwrite - overwrite older events?
365 *
366 * If overwrite is false the user needs to signal event consuption using:
367 *
368 * struct perf_mmap *m = &evlist->mmap[cpu];
369 * unsigned int head = perf_mmap__read_head(m);
370 *
371 * perf_mmap__write_tail(m, head)
372 *
373 * Using perf_evlist__read_on_cpu does this automatically.
374 */
perf_evlist__mmap(struct perf_evlist * evlist,int pages,bool overwrite)375 int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
376 {
377 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
378 int mask = pages * page_size - 1;
379 struct perf_evsel *evsel;
380 const struct cpu_map *cpus = evlist->cpus;
381 const struct thread_map *threads = evlist->threads;
382 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
383
384 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
385 return -ENOMEM;
386
387 if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
388 return -ENOMEM;
389
390 evlist->overwrite = overwrite;
391 evlist->mmap_len = (pages + 1) * page_size;
392
393 list_for_each_entry(evsel, &evlist->entries, node) {
394 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
395 evsel->sample_id == NULL &&
396 perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
397 return -ENOMEM;
398 }
399
400 if (evlist->cpus->map[0] == -1)
401 return perf_evlist__mmap_per_thread(evlist, prot, mask);
402
403 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
404 }
405
perf_evlist__create_maps(struct perf_evlist * evlist,pid_t target_pid,pid_t target_tid,const char * cpu_list)406 int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
407 pid_t target_tid, const char *cpu_list)
408 {
409 evlist->threads = thread_map__new(target_pid, target_tid);
410
411 if (evlist->threads == NULL)
412 return -1;
413
414 if (cpu_list == NULL && target_tid != -1)
415 evlist->cpus = cpu_map__dummy_new();
416 else
417 evlist->cpus = cpu_map__new(cpu_list);
418
419 if (evlist->cpus == NULL)
420 goto out_delete_threads;
421
422 return 0;
423
424 out_delete_threads:
425 thread_map__delete(evlist->threads);
426 return -1;
427 }
428
perf_evlist__delete_maps(struct perf_evlist * evlist)429 void perf_evlist__delete_maps(struct perf_evlist *evlist)
430 {
431 cpu_map__delete(evlist->cpus);
432 thread_map__delete(evlist->threads);
433 evlist->cpus = NULL;
434 evlist->threads = NULL;
435 }
436
perf_evlist__set_filters(struct perf_evlist * evlist)437 int perf_evlist__set_filters(struct perf_evlist *evlist)
438 {
439 const struct thread_map *threads = evlist->threads;
440 const struct cpu_map *cpus = evlist->cpus;
441 struct perf_evsel *evsel;
442 char *filter;
443 int thread;
444 int cpu;
445 int err;
446 int fd;
447
448 list_for_each_entry(evsel, &evlist->entries, node) {
449 filter = evsel->filter;
450 if (!filter)
451 continue;
452 for (cpu = 0; cpu < cpus->nr; cpu++) {
453 for (thread = 0; thread < threads->nr; thread++) {
454 fd = FD(evsel, cpu, thread);
455 err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
456 if (err)
457 return err;
458 }
459 }
460 }
461
462 return 0;
463 }
464
perf_evlist__valid_sample_type(const struct perf_evlist * evlist)465 bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist)
466 {
467 struct perf_evsel *pos, *first;
468
469 pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
470
471 list_for_each_entry_continue(pos, &evlist->entries, node) {
472 if (first->attr.sample_type != pos->attr.sample_type)
473 return false;
474 }
475
476 return true;
477 }
478
perf_evlist__sample_type(const struct perf_evlist * evlist)479 u64 perf_evlist__sample_type(const struct perf_evlist *evlist)
480 {
481 struct perf_evsel *first;
482
483 first = list_entry(evlist->entries.next, struct perf_evsel, node);
484 return first->attr.sample_type;
485 }
486
perf_evlist__valid_sample_id_all(const struct perf_evlist * evlist)487 bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist)
488 {
489 struct perf_evsel *pos, *first;
490
491 pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
492
493 list_for_each_entry_continue(pos, &evlist->entries, node) {
494 if (first->attr.sample_id_all != pos->attr.sample_id_all)
495 return false;
496 }
497
498 return true;
499 }
500
perf_evlist__sample_id_all(const struct perf_evlist * evlist)501 bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
502 {
503 struct perf_evsel *first;
504
505 first = list_entry(evlist->entries.next, struct perf_evsel, node);
506 return first->attr.sample_id_all;
507 }
508