perf evlist: Pass struct perf_target to perf_evlist__prepare_workload()
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / tools / perf / util / evlist.c
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 "util.h"
10 #include <lk/debugfs.h>
11 #include <poll.h>
12 #include "cpumap.h"
13 #include "thread_map.h"
14 #include "target.h"
15 #include "evlist.h"
16 #include "evsel.h"
17 #include <unistd.h>
18
19 #include "parse-events.h"
20
21 #include <sys/mman.h>
22
23 #include <linux/bitops.h>
24 #include <linux/hash.h>
25
26 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
27 #define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
28
29 void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
30 struct thread_map *threads)
31 {
32 int i;
33
34 for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
35 INIT_HLIST_HEAD(&evlist->heads[i]);
36 INIT_LIST_HEAD(&evlist->entries);
37 perf_evlist__set_maps(evlist, cpus, threads);
38 evlist->workload.pid = -1;
39 }
40
41 struct perf_evlist *perf_evlist__new(void)
42 {
43 struct perf_evlist *evlist = zalloc(sizeof(*evlist));
44
45 if (evlist != NULL)
46 perf_evlist__init(evlist, NULL, NULL);
47
48 return evlist;
49 }
50
51 void perf_evlist__config(struct perf_evlist *evlist,
52 struct perf_record_opts *opts)
53 {
54 struct perf_evsel *evsel;
55 /*
56 * Set the evsel leader links before we configure attributes,
57 * since some might depend on this info.
58 */
59 if (opts->group)
60 perf_evlist__set_leader(evlist);
61
62 if (evlist->cpus->map[0] < 0)
63 opts->no_inherit = true;
64
65 list_for_each_entry(evsel, &evlist->entries, node) {
66 perf_evsel__config(evsel, opts);
67
68 if (evlist->nr_entries > 1)
69 perf_evsel__set_sample_id(evsel);
70 }
71 }
72
73 static void perf_evlist__purge(struct perf_evlist *evlist)
74 {
75 struct perf_evsel *pos, *n;
76
77 list_for_each_entry_safe(pos, n, &evlist->entries, node) {
78 list_del_init(&pos->node);
79 perf_evsel__delete(pos);
80 }
81
82 evlist->nr_entries = 0;
83 }
84
85 void perf_evlist__exit(struct perf_evlist *evlist)
86 {
87 free(evlist->mmap);
88 free(evlist->pollfd);
89 evlist->mmap = NULL;
90 evlist->pollfd = NULL;
91 }
92
93 void perf_evlist__delete(struct perf_evlist *evlist)
94 {
95 perf_evlist__purge(evlist);
96 perf_evlist__exit(evlist);
97 free(evlist);
98 }
99
100 void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
101 {
102 list_add_tail(&entry->node, &evlist->entries);
103 ++evlist->nr_entries;
104 }
105
106 void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
107 struct list_head *list,
108 int nr_entries)
109 {
110 list_splice_tail(list, &evlist->entries);
111 evlist->nr_entries += nr_entries;
112 }
113
114 void __perf_evlist__set_leader(struct list_head *list)
115 {
116 struct perf_evsel *evsel, *leader;
117
118 leader = list_entry(list->next, struct perf_evsel, node);
119 evsel = list_entry(list->prev, struct perf_evsel, node);
120
121 leader->nr_members = evsel->idx - leader->idx + 1;
122
123 list_for_each_entry(evsel, list, node) {
124 evsel->leader = leader;
125 }
126 }
127
128 void perf_evlist__set_leader(struct perf_evlist *evlist)
129 {
130 if (evlist->nr_entries) {
131 evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0;
132 __perf_evlist__set_leader(&evlist->entries);
133 }
134 }
135
136 int perf_evlist__add_default(struct perf_evlist *evlist)
137 {
138 struct perf_event_attr attr = {
139 .type = PERF_TYPE_HARDWARE,
140 .config = PERF_COUNT_HW_CPU_CYCLES,
141 };
142 struct perf_evsel *evsel;
143
144 event_attr_init(&attr);
145
146 evsel = perf_evsel__new(&attr, 0);
147 if (evsel == NULL)
148 goto error;
149
150 /* use strdup() because free(evsel) assumes name is allocated */
151 evsel->name = strdup("cycles");
152 if (!evsel->name)
153 goto error_free;
154
155 perf_evlist__add(evlist, evsel);
156 return 0;
157 error_free:
158 perf_evsel__delete(evsel);
159 error:
160 return -ENOMEM;
161 }
162
163 static int perf_evlist__add_attrs(struct perf_evlist *evlist,
164 struct perf_event_attr *attrs, size_t nr_attrs)
165 {
166 struct perf_evsel *evsel, *n;
167 LIST_HEAD(head);
168 size_t i;
169
170 for (i = 0; i < nr_attrs; i++) {
171 evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i);
172 if (evsel == NULL)
173 goto out_delete_partial_list;
174 list_add_tail(&evsel->node, &head);
175 }
176
177 perf_evlist__splice_list_tail(evlist, &head, nr_attrs);
178
179 return 0;
180
181 out_delete_partial_list:
182 list_for_each_entry_safe(evsel, n, &head, node)
183 perf_evsel__delete(evsel);
184 return -1;
185 }
186
187 int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
188 struct perf_event_attr *attrs, size_t nr_attrs)
189 {
190 size_t i;
191
192 for (i = 0; i < nr_attrs; i++)
193 event_attr_init(attrs + i);
194
195 return perf_evlist__add_attrs(evlist, attrs, nr_attrs);
196 }
197
198 struct perf_evsel *
199 perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
200 {
201 struct perf_evsel *evsel;
202
203 list_for_each_entry(evsel, &evlist->entries, node) {
204 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
205 (int)evsel->attr.config == id)
206 return evsel;
207 }
208
209 return NULL;
210 }
211
212 int perf_evlist__add_newtp(struct perf_evlist *evlist,
213 const char *sys, const char *name, void *handler)
214 {
215 struct perf_evsel *evsel;
216
217 evsel = perf_evsel__newtp(sys, name, evlist->nr_entries);
218 if (evsel == NULL)
219 return -1;
220
221 evsel->handler.func = handler;
222 perf_evlist__add(evlist, evsel);
223 return 0;
224 }
225
226 void perf_evlist__disable(struct perf_evlist *evlist)
227 {
228 int cpu, thread;
229 struct perf_evsel *pos;
230 int nr_cpus = cpu_map__nr(evlist->cpus);
231 int nr_threads = thread_map__nr(evlist->threads);
232
233 for (cpu = 0; cpu < nr_cpus; cpu++) {
234 list_for_each_entry(pos, &evlist->entries, node) {
235 if (!perf_evsel__is_group_leader(pos))
236 continue;
237 for (thread = 0; thread < nr_threads; thread++)
238 ioctl(FD(pos, cpu, thread),
239 PERF_EVENT_IOC_DISABLE, 0);
240 }
241 }
242 }
243
244 void perf_evlist__enable(struct perf_evlist *evlist)
245 {
246 int cpu, thread;
247 struct perf_evsel *pos;
248 int nr_cpus = cpu_map__nr(evlist->cpus);
249 int nr_threads = thread_map__nr(evlist->threads);
250
251 for (cpu = 0; cpu < nr_cpus; cpu++) {
252 list_for_each_entry(pos, &evlist->entries, node) {
253 if (!perf_evsel__is_group_leader(pos))
254 continue;
255 for (thread = 0; thread < nr_threads; thread++)
256 ioctl(FD(pos, cpu, thread),
257 PERF_EVENT_IOC_ENABLE, 0);
258 }
259 }
260 }
261
262 static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
263 {
264 int nr_cpus = cpu_map__nr(evlist->cpus);
265 int nr_threads = thread_map__nr(evlist->threads);
266 int nfds = nr_cpus * nr_threads * evlist->nr_entries;
267 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
268 return evlist->pollfd != NULL ? 0 : -ENOMEM;
269 }
270
271 void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
272 {
273 fcntl(fd, F_SETFL, O_NONBLOCK);
274 evlist->pollfd[evlist->nr_fds].fd = fd;
275 evlist->pollfd[evlist->nr_fds].events = POLLIN;
276 evlist->nr_fds++;
277 }
278
279 static void perf_evlist__id_hash(struct perf_evlist *evlist,
280 struct perf_evsel *evsel,
281 int cpu, int thread, u64 id)
282 {
283 int hash;
284 struct perf_sample_id *sid = SID(evsel, cpu, thread);
285
286 sid->id = id;
287 sid->evsel = evsel;
288 hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
289 hlist_add_head(&sid->node, &evlist->heads[hash]);
290 }
291
292 void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
293 int cpu, int thread, u64 id)
294 {
295 perf_evlist__id_hash(evlist, evsel, cpu, thread, id);
296 evsel->id[evsel->ids++] = id;
297 }
298
299 static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
300 struct perf_evsel *evsel,
301 int cpu, int thread, int fd)
302 {
303 u64 read_data[4] = { 0, };
304 int id_idx = 1; /* The first entry is the counter value */
305
306 if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
307 read(fd, &read_data, sizeof(read_data)) == -1)
308 return -1;
309
310 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
311 ++id_idx;
312 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
313 ++id_idx;
314
315 perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]);
316 return 0;
317 }
318
319 struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
320 {
321 struct hlist_head *head;
322 struct hlist_node *pos;
323 struct perf_sample_id *sid;
324 int hash;
325
326 if (evlist->nr_entries == 1)
327 return perf_evlist__first(evlist);
328
329 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
330 head = &evlist->heads[hash];
331
332 hlist_for_each_entry(sid, pos, head, node)
333 if (sid->id == id)
334 return sid->evsel;
335
336 if (!perf_evlist__sample_id_all(evlist))
337 return perf_evlist__first(evlist);
338
339 return NULL;
340 }
341
342 union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
343 {
344 struct perf_mmap *md = &evlist->mmap[idx];
345 unsigned int head = perf_mmap__read_head(md);
346 unsigned int old = md->prev;
347 unsigned char *data = md->base + page_size;
348 union perf_event *event = NULL;
349
350 if (evlist->overwrite) {
351 /*
352 * If we're further behind than half the buffer, there's a chance
353 * the writer will bite our tail and mess up the samples under us.
354 *
355 * If we somehow ended up ahead of the head, we got messed up.
356 *
357 * In either case, truncate and restart at head.
358 */
359 int diff = head - old;
360 if (diff > md->mask / 2 || diff < 0) {
361 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
362
363 /*
364 * head points to a known good entry, start there.
365 */
366 old = head;
367 }
368 }
369
370 if (old != head) {
371 size_t size;
372
373 event = (union perf_event *)&data[old & md->mask];
374 size = event->header.size;
375
376 /*
377 * Event straddles the mmap boundary -- header should always
378 * be inside due to u64 alignment of output.
379 */
380 if ((old & md->mask) + size != ((old + size) & md->mask)) {
381 unsigned int offset = old;
382 unsigned int len = min(sizeof(*event), size), cpy;
383 void *dst = &md->event_copy;
384
385 do {
386 cpy = min(md->mask + 1 - (offset & md->mask), len);
387 memcpy(dst, &data[offset & md->mask], cpy);
388 offset += cpy;
389 dst += cpy;
390 len -= cpy;
391 } while (len);
392
393 event = &md->event_copy;
394 }
395
396 old += size;
397 }
398
399 md->prev = old;
400
401 if (!evlist->overwrite)
402 perf_mmap__write_tail(md, old);
403
404 return event;
405 }
406
407 void perf_evlist__munmap(struct perf_evlist *evlist)
408 {
409 int i;
410
411 for (i = 0; i < evlist->nr_mmaps; i++) {
412 if (evlist->mmap[i].base != NULL) {
413 munmap(evlist->mmap[i].base, evlist->mmap_len);
414 evlist->mmap[i].base = NULL;
415 }
416 }
417
418 free(evlist->mmap);
419 evlist->mmap = NULL;
420 }
421
422 static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
423 {
424 evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
425 if (cpu_map__all(evlist->cpus))
426 evlist->nr_mmaps = thread_map__nr(evlist->threads);
427 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
428 return evlist->mmap != NULL ? 0 : -ENOMEM;
429 }
430
431 static int __perf_evlist__mmap(struct perf_evlist *evlist,
432 int idx, int prot, int mask, int fd)
433 {
434 evlist->mmap[idx].prev = 0;
435 evlist->mmap[idx].mask = mask;
436 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
437 MAP_SHARED, fd, 0);
438 if (evlist->mmap[idx].base == MAP_FAILED) {
439 evlist->mmap[idx].base = NULL;
440 return -1;
441 }
442
443 perf_evlist__add_pollfd(evlist, fd);
444 return 0;
445 }
446
447 static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask)
448 {
449 struct perf_evsel *evsel;
450 int cpu, thread;
451 int nr_cpus = cpu_map__nr(evlist->cpus);
452 int nr_threads = thread_map__nr(evlist->threads);
453
454 for (cpu = 0; cpu < nr_cpus; cpu++) {
455 int output = -1;
456
457 for (thread = 0; thread < nr_threads; thread++) {
458 list_for_each_entry(evsel, &evlist->entries, node) {
459 int fd = FD(evsel, cpu, thread);
460
461 if (output == -1) {
462 output = fd;
463 if (__perf_evlist__mmap(evlist, cpu,
464 prot, mask, output) < 0)
465 goto out_unmap;
466 } else {
467 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
468 goto out_unmap;
469 }
470
471 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
472 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
473 goto out_unmap;
474 }
475 }
476 }
477
478 return 0;
479
480 out_unmap:
481 for (cpu = 0; cpu < nr_cpus; cpu++) {
482 if (evlist->mmap[cpu].base != NULL) {
483 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
484 evlist->mmap[cpu].base = NULL;
485 }
486 }
487 return -1;
488 }
489
490 static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask)
491 {
492 struct perf_evsel *evsel;
493 int thread;
494 int nr_threads = thread_map__nr(evlist->threads);
495
496 for (thread = 0; thread < nr_threads; thread++) {
497 int output = -1;
498
499 list_for_each_entry(evsel, &evlist->entries, node) {
500 int fd = FD(evsel, 0, thread);
501
502 if (output == -1) {
503 output = fd;
504 if (__perf_evlist__mmap(evlist, thread,
505 prot, mask, output) < 0)
506 goto out_unmap;
507 } else {
508 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
509 goto out_unmap;
510 }
511
512 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
513 perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0)
514 goto out_unmap;
515 }
516 }
517
518 return 0;
519
520 out_unmap:
521 for (thread = 0; thread < nr_threads; thread++) {
522 if (evlist->mmap[thread].base != NULL) {
523 munmap(evlist->mmap[thread].base, evlist->mmap_len);
524 evlist->mmap[thread].base = NULL;
525 }
526 }
527 return -1;
528 }
529
530 /** perf_evlist__mmap - Create per cpu maps to receive events
531 *
532 * @evlist - list of events
533 * @pages - map length in pages
534 * @overwrite - overwrite older events?
535 *
536 * If overwrite is false the user needs to signal event consuption using:
537 *
538 * struct perf_mmap *m = &evlist->mmap[cpu];
539 * unsigned int head = perf_mmap__read_head(m);
540 *
541 * perf_mmap__write_tail(m, head)
542 *
543 * Using perf_evlist__read_on_cpu does this automatically.
544 */
545 int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
546 bool overwrite)
547 {
548 struct perf_evsel *evsel;
549 const struct cpu_map *cpus = evlist->cpus;
550 const struct thread_map *threads = evlist->threads;
551 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask;
552
553 /* 512 kiB: default amount of unprivileged mlocked memory */
554 if (pages == UINT_MAX)
555 pages = (512 * 1024) / page_size;
556 else if (!is_power_of_2(pages))
557 return -EINVAL;
558
559 mask = pages * page_size - 1;
560
561 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
562 return -ENOMEM;
563
564 if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
565 return -ENOMEM;
566
567 evlist->overwrite = overwrite;
568 evlist->mmap_len = (pages + 1) * page_size;
569
570 list_for_each_entry(evsel, &evlist->entries, node) {
571 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
572 evsel->sample_id == NULL &&
573 perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0)
574 return -ENOMEM;
575 }
576
577 if (cpu_map__all(cpus))
578 return perf_evlist__mmap_per_thread(evlist, prot, mask);
579
580 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
581 }
582
583 int perf_evlist__create_maps(struct perf_evlist *evlist,
584 struct perf_target *target)
585 {
586 evlist->threads = thread_map__new_str(target->pid, target->tid,
587 target->uid);
588
589 if (evlist->threads == NULL)
590 return -1;
591
592 if (perf_target__has_task(target))
593 evlist->cpus = cpu_map__dummy_new();
594 else if (!perf_target__has_cpu(target) && !target->uses_mmap)
595 evlist->cpus = cpu_map__dummy_new();
596 else
597 evlist->cpus = cpu_map__new(target->cpu_list);
598
599 if (evlist->cpus == NULL)
600 goto out_delete_threads;
601
602 return 0;
603
604 out_delete_threads:
605 thread_map__delete(evlist->threads);
606 return -1;
607 }
608
609 void perf_evlist__delete_maps(struct perf_evlist *evlist)
610 {
611 cpu_map__delete(evlist->cpus);
612 thread_map__delete(evlist->threads);
613 evlist->cpus = NULL;
614 evlist->threads = NULL;
615 }
616
617 int perf_evlist__apply_filters(struct perf_evlist *evlist)
618 {
619 struct perf_evsel *evsel;
620 int err = 0;
621 const int ncpus = cpu_map__nr(evlist->cpus),
622 nthreads = thread_map__nr(evlist->threads);
623
624 list_for_each_entry(evsel, &evlist->entries, node) {
625 if (evsel->filter == NULL)
626 continue;
627
628 err = perf_evsel__set_filter(evsel, ncpus, nthreads, evsel->filter);
629 if (err)
630 break;
631 }
632
633 return err;
634 }
635
636 int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
637 {
638 struct perf_evsel *evsel;
639 int err = 0;
640 const int ncpus = cpu_map__nr(evlist->cpus),
641 nthreads = thread_map__nr(evlist->threads);
642
643 list_for_each_entry(evsel, &evlist->entries, node) {
644 err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter);
645 if (err)
646 break;
647 }
648
649 return err;
650 }
651
652 bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
653 {
654 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
655
656 list_for_each_entry_continue(pos, &evlist->entries, node) {
657 if (first->attr.sample_type != pos->attr.sample_type)
658 return false;
659 }
660
661 return true;
662 }
663
664 u64 perf_evlist__sample_type(struct perf_evlist *evlist)
665 {
666 struct perf_evsel *first = perf_evlist__first(evlist);
667 return first->attr.sample_type;
668 }
669
670 u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist)
671 {
672 struct perf_evsel *first = perf_evlist__first(evlist);
673 struct perf_sample *data;
674 u64 sample_type;
675 u16 size = 0;
676
677 if (!first->attr.sample_id_all)
678 goto out;
679
680 sample_type = first->attr.sample_type;
681
682 if (sample_type & PERF_SAMPLE_TID)
683 size += sizeof(data->tid) * 2;
684
685 if (sample_type & PERF_SAMPLE_TIME)
686 size += sizeof(data->time);
687
688 if (sample_type & PERF_SAMPLE_ID)
689 size += sizeof(data->id);
690
691 if (sample_type & PERF_SAMPLE_STREAM_ID)
692 size += sizeof(data->stream_id);
693
694 if (sample_type & PERF_SAMPLE_CPU)
695 size += sizeof(data->cpu) * 2;
696 out:
697 return size;
698 }
699
700 bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist)
701 {
702 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
703
704 list_for_each_entry_continue(pos, &evlist->entries, node) {
705 if (first->attr.sample_id_all != pos->attr.sample_id_all)
706 return false;
707 }
708
709 return true;
710 }
711
712 bool perf_evlist__sample_id_all(struct perf_evlist *evlist)
713 {
714 struct perf_evsel *first = perf_evlist__first(evlist);
715 return first->attr.sample_id_all;
716 }
717
718 void perf_evlist__set_selected(struct perf_evlist *evlist,
719 struct perf_evsel *evsel)
720 {
721 evlist->selected = evsel;
722 }
723
724 int perf_evlist__open(struct perf_evlist *evlist)
725 {
726 struct perf_evsel *evsel;
727 int err, ncpus, nthreads;
728
729 list_for_each_entry(evsel, &evlist->entries, node) {
730 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
731 if (err < 0)
732 goto out_err;
733 }
734
735 return 0;
736 out_err:
737 ncpus = cpu_map__nr(evlist->cpus);
738 nthreads = thread_map__nr(evlist->threads);
739
740 list_for_each_entry_reverse(evsel, &evlist->entries, node)
741 perf_evsel__close(evsel, ncpus, nthreads);
742
743 errno = -err;
744 return err;
745 }
746
747 int perf_evlist__prepare_workload(struct perf_evlist *evlist,
748 struct perf_target *target,
749 struct perf_record_opts *opts,
750 const char *argv[])
751 {
752 int child_ready_pipe[2], go_pipe[2];
753 char bf;
754
755 if (pipe(child_ready_pipe) < 0) {
756 perror("failed to create 'ready' pipe");
757 return -1;
758 }
759
760 if (pipe(go_pipe) < 0) {
761 perror("failed to create 'go' pipe");
762 goto out_close_ready_pipe;
763 }
764
765 evlist->workload.pid = fork();
766 if (evlist->workload.pid < 0) {
767 perror("failed to fork");
768 goto out_close_pipes;
769 }
770
771 if (!evlist->workload.pid) {
772 if (opts->pipe_output)
773 dup2(2, 1);
774
775 close(child_ready_pipe[0]);
776 close(go_pipe[1]);
777 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
778
779 /*
780 * Do a dummy execvp to get the PLT entry resolved,
781 * so we avoid the resolver overhead on the real
782 * execvp call.
783 */
784 execvp("", (char **)argv);
785
786 /*
787 * Tell the parent we're ready to go
788 */
789 close(child_ready_pipe[1]);
790
791 /*
792 * Wait until the parent tells us to go.
793 */
794 if (read(go_pipe[0], &bf, 1) == -1)
795 perror("unable to read pipe");
796
797 execvp(argv[0], (char **)argv);
798
799 perror(argv[0]);
800 kill(getppid(), SIGUSR1);
801 exit(-1);
802 }
803
804 if (perf_target__none(target))
805 evlist->threads->map[0] = evlist->workload.pid;
806
807 close(child_ready_pipe[1]);
808 close(go_pipe[0]);
809 /*
810 * wait for child to settle
811 */
812 if (read(child_ready_pipe[0], &bf, 1) == -1) {
813 perror("unable to read pipe");
814 goto out_close_pipes;
815 }
816
817 evlist->workload.cork_fd = go_pipe[1];
818 close(child_ready_pipe[0]);
819 return 0;
820
821 out_close_pipes:
822 close(go_pipe[0]);
823 close(go_pipe[1]);
824 out_close_ready_pipe:
825 close(child_ready_pipe[0]);
826 close(child_ready_pipe[1]);
827 return -1;
828 }
829
830 int perf_evlist__start_workload(struct perf_evlist *evlist)
831 {
832 if (evlist->workload.cork_fd > 0) {
833 /*
834 * Remove the cork, let it rip!
835 */
836 return close(evlist->workload.cork_fd);
837 }
838
839 return 0;
840 }
841
842 int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
843 struct perf_sample *sample)
844 {
845 struct perf_evsel *evsel = perf_evlist__first(evlist);
846 return perf_evsel__parse_sample(evsel, event, sample);
847 }
848
849 size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
850 {
851 struct perf_evsel *evsel;
852 size_t printed = 0;
853
854 list_for_each_entry(evsel, &evlist->entries, node) {
855 printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "",
856 perf_evsel__name(evsel));
857 }
858
859 return printed + fprintf(fp, "\n");;
860 }