evlist.c revision e6817ec1d8ab31fc7b01906e305f848542df6413
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
31void 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
42struct 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
53static 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
65void 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
73void perf_evlist__delete(struct perf_evlist *evlist)
74{
75	perf_evlist__purge(evlist);
76	perf_evlist__exit(evlist);
77	free(evlist);
78}
79
80void 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
86int 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
101int 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
108void 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
116static 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
129void 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
136static 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
156struct 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
175union 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
242void 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
257int 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
266static 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
280static 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
311out_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
321static 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
350out_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 */
375int 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
406int 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
424out_delete_threads:
425	thread_map__delete(evlist->threads);
426	return -1;
427}
428
429void 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
437int 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
465bool 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
479u64 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
487bool 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
501bool 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