• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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