xref: /linux/tools/lib/perf/evsel.c (revision f4f346c3465949ebba80c6cc52cd8d2eeaa545fd)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <errno.h>
3 #include <unistd.h>
4 #include <sys/syscall.h>
5 #include <perf/evsel.h>
6 #include <perf/cpumap.h>
7 #include <perf/threadmap.h>
8 #include <linux/hash.h>
9 #include <linux/list.h>
10 #include <internal/evsel.h>
11 #include <linux/zalloc.h>
12 #include <stdlib.h>
13 #include <internal/xyarray.h>
14 #include <internal/cpumap.h>
15 #include <internal/mmap.h>
16 #include <internal/threadmap.h>
17 #include <internal/lib.h>
18 #include <linux/string.h>
19 #include <sys/ioctl.h>
20 #include <sys/mman.h>
21 #include <asm/bug.h>
22 
perf_evsel__init(struct perf_evsel * evsel,struct perf_event_attr * attr,int idx)23 void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
24 		      int idx)
25 {
26 	INIT_LIST_HEAD(&evsel->node);
27 	INIT_LIST_HEAD(&evsel->per_stream_periods);
28 	evsel->attr = *attr;
29 	evsel->idx  = idx;
30 	evsel->leader = evsel;
31 }
32 
perf_evsel__new(struct perf_event_attr * attr)33 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr)
34 {
35 	struct perf_evsel *evsel = zalloc(sizeof(*evsel));
36 
37 	if (evsel != NULL)
38 		perf_evsel__init(evsel, attr, 0);
39 
40 	return evsel;
41 }
42 
perf_evsel__exit(struct perf_evsel * evsel)43 void perf_evsel__exit(struct perf_evsel *evsel)
44 {
45 	assert(evsel->fd == NULL);  /* If not fds were not closed. */
46 	assert(evsel->mmap == NULL); /* If not munmap wasn't called. */
47 	assert(evsel->sample_id == NULL); /* If not free_id wasn't called. */
48 	perf_cpu_map__put(evsel->cpus);
49 	perf_cpu_map__put(evsel->pmu_cpus);
50 	perf_thread_map__put(evsel->threads);
51 }
52 
perf_evsel__delete(struct perf_evsel * evsel)53 void perf_evsel__delete(struct perf_evsel *evsel)
54 {
55 	perf_evsel__exit(evsel);
56 	free(evsel);
57 }
58 
59 #define FD(_evsel, _cpu_map_idx, _thread)				\
60 	((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
61 #define MMAP(_evsel, _cpu_map_idx, _thread)				\
62 	(_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
63 		      : NULL)
64 
perf_evsel__alloc_fd(struct perf_evsel * evsel,int ncpus,int nthreads)65 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
66 {
67 	evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
68 
69 	if (evsel->fd) {
70 		int idx, thread;
71 
72 		for (idx = 0; idx < ncpus; idx++) {
73 			for (thread = 0; thread < nthreads; thread++) {
74 				int *fd = FD(evsel, idx, thread);
75 
76 				if (fd)
77 					*fd = -1;
78 			}
79 		}
80 	}
81 
82 	return evsel->fd != NULL ? 0 : -ENOMEM;
83 }
84 
perf_evsel__alloc_mmap(struct perf_evsel * evsel,int ncpus,int nthreads)85 static int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads)
86 {
87 	evsel->mmap = xyarray__new(ncpus, nthreads, sizeof(struct perf_mmap));
88 
89 	return evsel->mmap != NULL ? 0 : -ENOMEM;
90 }
91 
92 static int
sys_perf_event_open(struct perf_event_attr * attr,pid_t pid,struct perf_cpu cpu,int group_fd,unsigned long flags)93 sys_perf_event_open(struct perf_event_attr *attr,
94 		    pid_t pid, struct perf_cpu cpu, int group_fd,
95 		    unsigned long flags)
96 {
97 	return syscall(__NR_perf_event_open, attr, pid, cpu.cpu, group_fd, flags);
98 }
99 
get_group_fd(struct perf_evsel * evsel,int cpu_map_idx,int thread,int * group_fd)100 static int get_group_fd(struct perf_evsel *evsel, int cpu_map_idx, int thread, int *group_fd)
101 {
102 	struct perf_evsel *leader = evsel->leader;
103 	int *fd;
104 
105 	if (evsel == leader) {
106 		*group_fd = -1;
107 		return 0;
108 	}
109 
110 	/*
111 	 * Leader must be already processed/open,
112 	 * if not it's a bug.
113 	 */
114 	if (!leader->fd)
115 		return -ENOTCONN;
116 
117 	fd = FD(leader, cpu_map_idx, thread);
118 	if (fd == NULL || *fd == -1)
119 		return -EBADF;
120 
121 	*group_fd = *fd;
122 
123 	return 0;
124 }
125 
perf_evsel__open(struct perf_evsel * evsel,struct perf_cpu_map * cpus,struct perf_thread_map * threads)126 int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
127 		     struct perf_thread_map *threads)
128 {
129 	struct perf_cpu cpu;
130 	int idx, thread, err = 0;
131 
132 	if (cpus == NULL) {
133 		static struct perf_cpu_map *empty_cpu_map;
134 
135 		if (empty_cpu_map == NULL) {
136 			empty_cpu_map = perf_cpu_map__new_any_cpu();
137 			if (empty_cpu_map == NULL)
138 				return -ENOMEM;
139 		}
140 
141 		cpus = empty_cpu_map;
142 	}
143 
144 	if (threads == NULL) {
145 		static struct perf_thread_map *empty_thread_map;
146 
147 		if (empty_thread_map == NULL) {
148 			empty_thread_map = perf_thread_map__new_dummy();
149 			if (empty_thread_map == NULL)
150 				return -ENOMEM;
151 		}
152 
153 		threads = empty_thread_map;
154 	}
155 
156 	if (evsel->fd == NULL &&
157 	    perf_evsel__alloc_fd(evsel, perf_cpu_map__nr(cpus), threads->nr) < 0)
158 		return -ENOMEM;
159 
160 	perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
161 		for (thread = 0; thread < threads->nr; thread++) {
162 			int fd, group_fd, *evsel_fd;
163 
164 			evsel_fd = FD(evsel, idx, thread);
165 			if (evsel_fd == NULL) {
166 				err = -EINVAL;
167 				goto out;
168 			}
169 
170 			err = get_group_fd(evsel, idx, thread, &group_fd);
171 			if (err < 0)
172 				goto out;
173 
174 			fd = sys_perf_event_open(&evsel->attr,
175 						 threads->map[thread].pid,
176 						 cpu, group_fd, 0);
177 
178 			if (fd < 0) {
179 				err = -errno;
180 				goto out;
181 			}
182 
183 			*evsel_fd = fd;
184 		}
185 	}
186 out:
187 	if (err)
188 		perf_evsel__close(evsel);
189 
190 	return err;
191 }
192 
perf_evsel__close_fd_cpu(struct perf_evsel * evsel,int cpu_map_idx)193 static void perf_evsel__close_fd_cpu(struct perf_evsel *evsel, int cpu_map_idx)
194 {
195 	int thread;
196 
197 	for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
198 		int *fd = FD(evsel, cpu_map_idx, thread);
199 
200 		if (fd && *fd >= 0) {
201 			close(*fd);
202 			*fd = -1;
203 		}
204 	}
205 }
206 
perf_evsel__close_fd(struct perf_evsel * evsel)207 void perf_evsel__close_fd(struct perf_evsel *evsel)
208 {
209 	for (int idx = 0; idx < xyarray__max_x(evsel->fd); idx++)
210 		perf_evsel__close_fd_cpu(evsel, idx);
211 }
212 
perf_evsel__free_fd(struct perf_evsel * evsel)213 void perf_evsel__free_fd(struct perf_evsel *evsel)
214 {
215 	xyarray__delete(evsel->fd);
216 	evsel->fd = NULL;
217 }
218 
perf_evsel__close(struct perf_evsel * evsel)219 void perf_evsel__close(struct perf_evsel *evsel)
220 {
221 	if (evsel->fd == NULL)
222 		return;
223 
224 	perf_evsel__close_fd(evsel);
225 	perf_evsel__free_fd(evsel);
226 }
227 
perf_evsel__close_cpu(struct perf_evsel * evsel,int cpu_map_idx)228 void perf_evsel__close_cpu(struct perf_evsel *evsel, int cpu_map_idx)
229 {
230 	if (evsel->fd == NULL)
231 		return;
232 
233 	perf_evsel__close_fd_cpu(evsel, cpu_map_idx);
234 }
235 
perf_evsel__munmap(struct perf_evsel * evsel)236 void perf_evsel__munmap(struct perf_evsel *evsel)
237 {
238 	int idx, thread;
239 
240 	if (evsel->fd == NULL || evsel->mmap == NULL)
241 		return;
242 
243 	for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
244 		for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
245 			int *fd = FD(evsel, idx, thread);
246 
247 			if (fd == NULL || *fd < 0)
248 				continue;
249 
250 			perf_mmap__munmap(MMAP(evsel, idx, thread));
251 		}
252 	}
253 
254 	xyarray__delete(evsel->mmap);
255 	evsel->mmap = NULL;
256 }
257 
perf_evsel__mmap(struct perf_evsel * evsel,int pages)258 int perf_evsel__mmap(struct perf_evsel *evsel, int pages)
259 {
260 	int ret, idx, thread;
261 	struct perf_mmap_param mp = {
262 		.prot = PROT_READ | PROT_WRITE,
263 		.mask = (pages * page_size) - 1,
264 	};
265 
266 	if (evsel->fd == NULL || evsel->mmap)
267 		return -EINVAL;
268 
269 	if (perf_evsel__alloc_mmap(evsel, xyarray__max_x(evsel->fd), xyarray__max_y(evsel->fd)) < 0)
270 		return -ENOMEM;
271 
272 	for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
273 		for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
274 			int *fd = FD(evsel, idx, thread);
275 			struct perf_mmap *map;
276 			struct perf_cpu cpu = perf_cpu_map__cpu(evsel->cpus, idx);
277 
278 			if (fd == NULL || *fd < 0)
279 				continue;
280 
281 			map = MMAP(evsel, idx, thread);
282 			perf_mmap__init(map, NULL, false, NULL);
283 
284 			ret = perf_mmap__mmap(map, &mp, *fd, cpu);
285 			if (ret) {
286 				perf_evsel__munmap(evsel);
287 				return ret;
288 			}
289 		}
290 	}
291 
292 	return 0;
293 }
294 
perf_evsel__mmap_base(struct perf_evsel * evsel,int cpu_map_idx,int thread)295 void *perf_evsel__mmap_base(struct perf_evsel *evsel, int cpu_map_idx, int thread)
296 {
297 	int *fd = FD(evsel, cpu_map_idx, thread);
298 
299 	if (fd == NULL || *fd < 0 || MMAP(evsel, cpu_map_idx, thread) == NULL)
300 		return NULL;
301 
302 	return MMAP(evsel, cpu_map_idx, thread)->base;
303 }
304 
perf_evsel__read_size(struct perf_evsel * evsel)305 int perf_evsel__read_size(struct perf_evsel *evsel)
306 {
307 	u64 read_format = evsel->attr.read_format;
308 	int entry = sizeof(u64); /* value */
309 	int size = 0;
310 	int nr = 1;
311 
312 	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
313 		size += sizeof(u64);
314 
315 	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
316 		size += sizeof(u64);
317 
318 	if (read_format & PERF_FORMAT_ID)
319 		entry += sizeof(u64);
320 
321 	if (read_format & PERF_FORMAT_LOST)
322 		entry += sizeof(u64);
323 
324 	if (read_format & PERF_FORMAT_GROUP) {
325 		nr = evsel->nr_members;
326 		size += sizeof(u64);
327 	}
328 
329 	size += entry * nr;
330 	return size;
331 }
332 
333 /* This only reads values for the leader */
perf_evsel__read_group(struct perf_evsel * evsel,int cpu_map_idx,int thread,struct perf_counts_values * count)334 static int perf_evsel__read_group(struct perf_evsel *evsel, int cpu_map_idx,
335 				  int thread, struct perf_counts_values *count)
336 {
337 	size_t size = perf_evsel__read_size(evsel);
338 	int *fd = FD(evsel, cpu_map_idx, thread);
339 	u64 read_format = evsel->attr.read_format;
340 	u64 *data;
341 	int idx = 1;
342 
343 	if (fd == NULL || *fd < 0)
344 		return -EINVAL;
345 
346 	data = calloc(1, size);
347 	if (data == NULL)
348 		return -ENOMEM;
349 
350 	if (readn(*fd, data, size) <= 0) {
351 		free(data);
352 		return -errno;
353 	}
354 
355 	/*
356 	 * This reads only the leader event intentionally since we don't have
357 	 * perf counts values for sibling events.
358 	 */
359 	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
360 		count->ena = data[idx++];
361 	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
362 		count->run = data[idx++];
363 
364 	/* value is always available */
365 	count->val = data[idx++];
366 	if (read_format & PERF_FORMAT_ID)
367 		count->id = data[idx++];
368 	if (read_format & PERF_FORMAT_LOST)
369 		count->lost = data[idx++];
370 
371 	free(data);
372 	return 0;
373 }
374 
375 /*
376  * The perf read format is very flexible.  It needs to set the proper
377  * values according to the read format.
378  */
perf_evsel__adjust_values(struct perf_evsel * evsel,u64 * buf,struct perf_counts_values * count)379 static void perf_evsel__adjust_values(struct perf_evsel *evsel, u64 *buf,
380 				      struct perf_counts_values *count)
381 {
382 	u64 read_format = evsel->attr.read_format;
383 	int n = 0;
384 
385 	count->val = buf[n++];
386 
387 	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
388 		count->ena = buf[n++];
389 
390 	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
391 		count->run = buf[n++];
392 
393 	if (read_format & PERF_FORMAT_ID)
394 		count->id = buf[n++];
395 
396 	if (read_format & PERF_FORMAT_LOST)
397 		count->lost = buf[n++];
398 }
399 
perf_evsel__read(struct perf_evsel * evsel,int cpu_map_idx,int thread,struct perf_counts_values * count)400 int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int thread,
401 		     struct perf_counts_values *count)
402 {
403 	size_t size = perf_evsel__read_size(evsel);
404 	int *fd = FD(evsel, cpu_map_idx, thread);
405 	u64 read_format = evsel->attr.read_format;
406 	struct perf_counts_values buf;
407 
408 	memset(count, 0, sizeof(*count));
409 
410 	if (fd == NULL || *fd < 0)
411 		return -EINVAL;
412 
413 	if (read_format & PERF_FORMAT_GROUP)
414 		return perf_evsel__read_group(evsel, cpu_map_idx, thread, count);
415 
416 	if (MMAP(evsel, cpu_map_idx, thread) &&
417 	    !(read_format & (PERF_FORMAT_ID | PERF_FORMAT_LOST)) &&
418 	    !perf_mmap__read_self(MMAP(evsel, cpu_map_idx, thread), count))
419 		return 0;
420 
421 	if (readn(*fd, buf.values, size) <= 0)
422 		return -errno;
423 
424 	perf_evsel__adjust_values(evsel, buf.values, count);
425 	return 0;
426 }
427 
perf_evsel__ioctl(struct perf_evsel * evsel,int ioc,void * arg,int cpu_map_idx,int thread)428 static int perf_evsel__ioctl(struct perf_evsel *evsel, int ioc, void *arg,
429 			     int cpu_map_idx, int thread)
430 {
431 	int *fd = FD(evsel, cpu_map_idx, thread);
432 
433 	if (fd == NULL || *fd < 0)
434 		return -1;
435 
436 	return ioctl(*fd, ioc, arg);
437 }
438 
perf_evsel__run_ioctl(struct perf_evsel * evsel,int ioc,void * arg,int cpu_map_idx)439 static int perf_evsel__run_ioctl(struct perf_evsel *evsel,
440 				 int ioc,  void *arg,
441 				 int cpu_map_idx)
442 {
443 	int thread;
444 
445 	for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
446 		int err = perf_evsel__ioctl(evsel, ioc, arg, cpu_map_idx, thread);
447 
448 		if (err)
449 			return err;
450 	}
451 
452 	return 0;
453 }
454 
perf_evsel__enable_cpu(struct perf_evsel * evsel,int cpu_map_idx)455 int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
456 {
457 	return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, cpu_map_idx);
458 }
459 
perf_evsel__enable_thread(struct perf_evsel * evsel,int thread)460 int perf_evsel__enable_thread(struct perf_evsel *evsel, int thread)
461 {
462 	struct perf_cpu cpu __maybe_unused;
463 	int idx;
464 	int err;
465 
466 	perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
467 		err = perf_evsel__ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, idx, thread);
468 		if (err)
469 			return err;
470 	}
471 
472 	return 0;
473 }
474 
perf_evsel__enable(struct perf_evsel * evsel)475 int perf_evsel__enable(struct perf_evsel *evsel)
476 {
477 	int i;
478 	int err = 0;
479 
480 	for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
481 		err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, i);
482 	return err;
483 }
484 
perf_evsel__disable_cpu(struct perf_evsel * evsel,int cpu_map_idx)485 int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
486 {
487 	return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, cpu_map_idx);
488 }
489 
perf_evsel__disable(struct perf_evsel * evsel)490 int perf_evsel__disable(struct perf_evsel *evsel)
491 {
492 	int i;
493 	int err = 0;
494 
495 	for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
496 		err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, i);
497 	return err;
498 }
499 
perf_evsel__apply_filter(struct perf_evsel * evsel,const char * filter)500 int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter)
501 {
502 	int err = 0, i;
503 
504 	for (i = 0; i < perf_cpu_map__nr(evsel->cpus) && !err; i++)
505 		err = perf_evsel__run_ioctl(evsel,
506 				     PERF_EVENT_IOC_SET_FILTER,
507 				     (void *)filter, i);
508 	return err;
509 }
510 
perf_evsel__cpus(struct perf_evsel * evsel)511 struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
512 {
513 	return evsel->cpus;
514 }
515 
perf_evsel__threads(struct perf_evsel * evsel)516 struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel)
517 {
518 	return evsel->threads;
519 }
520 
perf_evsel__attr(struct perf_evsel * evsel)521 struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel)
522 {
523 	return &evsel->attr;
524 }
525 
perf_evsel__alloc_id(struct perf_evsel * evsel,int ncpus,int nthreads)526 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
527 {
528 	if (ncpus == 0 || nthreads == 0)
529 		return 0;
530 
531 	evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
532 	if (evsel->sample_id == NULL)
533 		return -ENOMEM;
534 
535 	evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
536 	if (evsel->id == NULL) {
537 		xyarray__delete(evsel->sample_id);
538 		evsel->sample_id = NULL;
539 		return -ENOMEM;
540 	}
541 
542 	return 0;
543 }
544 
perf_evsel__free_id(struct perf_evsel * evsel)545 void perf_evsel__free_id(struct perf_evsel *evsel)
546 {
547 	struct perf_sample_id_period *pos, *n;
548 
549 	xyarray__delete(evsel->sample_id);
550 	evsel->sample_id = NULL;
551 	zfree(&evsel->id);
552 	evsel->ids = 0;
553 
554 	perf_evsel_for_each_per_thread_period_safe(evsel, n, pos) {
555 		list_del_init(&pos->node);
556 		free(pos);
557 	}
558 }
559 
perf_evsel__attr_has_per_thread_sample_period(struct perf_evsel * evsel)560 bool perf_evsel__attr_has_per_thread_sample_period(struct perf_evsel *evsel)
561 {
562 	return (evsel->attr.sample_type & PERF_SAMPLE_READ) &&
563 		(evsel->attr.sample_type & PERF_SAMPLE_TID) &&
564 		evsel->attr.inherit;
565 }
566 
perf_sample_id__get_period_storage(struct perf_sample_id * sid,u32 tid,bool per_thread)567 u64 *perf_sample_id__get_period_storage(struct perf_sample_id *sid, u32 tid, bool per_thread)
568 {
569 	struct hlist_head *head;
570 	struct perf_sample_id_period *res;
571 	int hash;
572 
573 	if (!per_thread)
574 		return &sid->period;
575 
576 	hash = hash_32(tid, PERF_SAMPLE_ID__HLIST_BITS);
577 	head = &sid->periods[hash];
578 
579 	hlist_for_each_entry(res, head, hnode)
580 		if (res->tid == tid)
581 			return &res->period;
582 
583 	if (sid->evsel == NULL)
584 		return NULL;
585 
586 	res = zalloc(sizeof(struct perf_sample_id_period));
587 	if (res == NULL)
588 		return NULL;
589 
590 	INIT_LIST_HEAD(&res->node);
591 	res->tid = tid;
592 
593 	list_add_tail(&res->node, &sid->evsel->per_stream_periods);
594 	hlist_add_head(&res->hnode, &sid->periods[hash]);
595 
596 	return &res->period;
597 }
598 
perf_counts_values__scale(struct perf_counts_values * count,bool scale,__s8 * pscaled)599 void perf_counts_values__scale(struct perf_counts_values *count,
600 			       bool scale, __s8 *pscaled)
601 {
602 	s8 scaled = 0;
603 
604 	if (scale) {
605 		if (count->run == 0) {
606 			scaled = -1;
607 			count->val = 0;
608 		} else if (count->run < count->ena) {
609 			scaled = 1;
610 			count->val = (u64)((double)count->val * count->ena / count->run);
611 		}
612 	}
613 
614 	if (pscaled)
615 		*pscaled = scaled;
616 }
617