xref: /openbmc/linux/tools/lib/perf/evsel.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
13ce311afSJiri Olsa // SPDX-License-Identifier: GPL-2.0
23ce311afSJiri Olsa #include <errno.h>
33ce311afSJiri Olsa #include <unistd.h>
43ce311afSJiri Olsa #include <sys/syscall.h>
53ce311afSJiri Olsa #include <perf/evsel.h>
63ce311afSJiri Olsa #include <perf/cpumap.h>
73ce311afSJiri Olsa #include <perf/threadmap.h>
83ce311afSJiri Olsa #include <linux/list.h>
93ce311afSJiri Olsa #include <internal/evsel.h>
103ce311afSJiri Olsa #include <linux/zalloc.h>
113ce311afSJiri Olsa #include <stdlib.h>
123ce311afSJiri Olsa #include <internal/xyarray.h>
133ce311afSJiri Olsa #include <internal/cpumap.h>
146cd70754SRob Herring #include <internal/mmap.h>
153ce311afSJiri Olsa #include <internal/threadmap.h>
163ce311afSJiri Olsa #include <internal/lib.h>
173ce311afSJiri Olsa #include <linux/string.h>
183ce311afSJiri Olsa #include <sys/ioctl.h>
196cd70754SRob Herring #include <sys/mman.h>
203fd35de1SJiri Olsa #include <asm/bug.h>
213ce311afSJiri Olsa 
perf_evsel__init(struct perf_evsel * evsel,struct perf_event_attr * attr,int idx)2238fe0e01SJiri Olsa void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
2338fe0e01SJiri Olsa 		      int idx)
243ce311afSJiri Olsa {
253ce311afSJiri Olsa 	INIT_LIST_HEAD(&evsel->node);
263ce311afSJiri Olsa 	evsel->attr = *attr;
2738fe0e01SJiri Olsa 	evsel->idx  = idx;
28fba7c866SJiri Olsa 	evsel->leader = evsel;
293ce311afSJiri Olsa }
303ce311afSJiri Olsa 
perf_evsel__new(struct perf_event_attr * attr)313ce311afSJiri Olsa struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr)
323ce311afSJiri Olsa {
333ce311afSJiri Olsa 	struct perf_evsel *evsel = zalloc(sizeof(*evsel));
343ce311afSJiri Olsa 
353ce311afSJiri Olsa 	if (evsel != NULL)
3638fe0e01SJiri Olsa 		perf_evsel__init(evsel, attr, 0);
373ce311afSJiri Olsa 
383ce311afSJiri Olsa 	return evsel;
393ce311afSJiri Olsa }
403ce311afSJiri Olsa 
perf_evsel__delete(struct perf_evsel * evsel)413ce311afSJiri Olsa void perf_evsel__delete(struct perf_evsel *evsel)
423ce311afSJiri Olsa {
433ce311afSJiri Olsa 	free(evsel);
443ce311afSJiri Olsa }
453ce311afSJiri Olsa 
467e3d1784SIan Rogers #define FD(_evsel, _cpu_map_idx, _thread)				\
477e3d1784SIan Rogers 	((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
487e3d1784SIan Rogers #define MMAP(_evsel, _cpu_map_idx, _thread)				\
497e3d1784SIan Rogers 	(_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
507e3d1784SIan Rogers 		      : NULL)
513ce311afSJiri Olsa 
perf_evsel__alloc_fd(struct perf_evsel * evsel,int ncpus,int nthreads)523ce311afSJiri Olsa int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
533ce311afSJiri Olsa {
543ce311afSJiri Olsa 	evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
553ce311afSJiri Olsa 
563ce311afSJiri Olsa 	if (evsel->fd) {
577e3d1784SIan Rogers 		int idx, thread;
587e3d1784SIan Rogers 
597e3d1784SIan Rogers 		for (idx = 0; idx < ncpus; idx++) {
603ce311afSJiri Olsa 			for (thread = 0; thread < nthreads; thread++) {
617e3d1784SIan Rogers 				int *fd = FD(evsel, idx, thread);
62aba5daebSIan Rogers 
63aba5daebSIan Rogers 				if (fd)
64aba5daebSIan Rogers 					*fd = -1;
653ce311afSJiri Olsa 			}
663ce311afSJiri Olsa 		}
673ce311afSJiri Olsa 	}
683ce311afSJiri Olsa 
693ce311afSJiri Olsa 	return evsel->fd != NULL ? 0 : -ENOMEM;
703ce311afSJiri Olsa }
713ce311afSJiri Olsa 
perf_evsel__alloc_mmap(struct perf_evsel * evsel,int ncpus,int nthreads)726cd70754SRob Herring static int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads)
736cd70754SRob Herring {
746cd70754SRob Herring 	evsel->mmap = xyarray__new(ncpus, nthreads, sizeof(struct perf_mmap));
756cd70754SRob Herring 
766cd70754SRob Herring 	return evsel->mmap != NULL ? 0 : -ENOMEM;
776cd70754SRob Herring }
786cd70754SRob Herring 
793ce311afSJiri Olsa static int
sys_perf_event_open(struct perf_event_attr * attr,pid_t pid,struct perf_cpu cpu,int group_fd,unsigned long flags)803ce311afSJiri Olsa sys_perf_event_open(struct perf_event_attr *attr,
816d18804bSIan Rogers 		    pid_t pid, struct perf_cpu cpu, int group_fd,
823ce311afSJiri Olsa 		    unsigned long flags)
833ce311afSJiri Olsa {
846d18804bSIan Rogers 	return syscall(__NR_perf_event_open, attr, pid, cpu.cpu, group_fd, flags);
853ce311afSJiri Olsa }
863ce311afSJiri Olsa 
get_group_fd(struct perf_evsel * evsel,int cpu_map_idx,int thread,int * group_fd)877e3d1784SIan Rogers static int get_group_fd(struct perf_evsel *evsel, int cpu_map_idx, int thread, int *group_fd)
883fd35de1SJiri Olsa {
893fd35de1SJiri Olsa 	struct perf_evsel *leader = evsel->leader;
90aba5daebSIan Rogers 	int *fd;
913fd35de1SJiri Olsa 
92e2c18168SArnaldo Carvalho de Melo 	if (evsel == leader) {
93e2c18168SArnaldo Carvalho de Melo 		*group_fd = -1;
94e2c18168SArnaldo Carvalho de Melo 		return 0;
95e2c18168SArnaldo Carvalho de Melo 	}
963fd35de1SJiri Olsa 
973fd35de1SJiri Olsa 	/*
983fd35de1SJiri Olsa 	 * Leader must be already processed/open,
993fd35de1SJiri Olsa 	 * if not it's a bug.
1003fd35de1SJiri Olsa 	 */
101e2c18168SArnaldo Carvalho de Melo 	if (!leader->fd)
102e2c18168SArnaldo Carvalho de Melo 		return -ENOTCONN;
1033fd35de1SJiri Olsa 
1047e3d1784SIan Rogers 	fd = FD(leader, cpu_map_idx, thread);
105aba5daebSIan Rogers 	if (fd == NULL || *fd == -1)
106e2c18168SArnaldo Carvalho de Melo 		return -EBADF;
107e2c18168SArnaldo Carvalho de Melo 
108aba5daebSIan Rogers 	*group_fd = *fd;
109e2c18168SArnaldo Carvalho de Melo 
110e2c18168SArnaldo Carvalho de Melo 	return 0;
1113fd35de1SJiri Olsa }
1123fd35de1SJiri Olsa 
perf_evsel__open(struct perf_evsel * evsel,struct perf_cpu_map * cpus,struct perf_thread_map * threads)1133ce311afSJiri Olsa int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
1143ce311afSJiri Olsa 		     struct perf_thread_map *threads)
1153ce311afSJiri Olsa {
1166d18804bSIan Rogers 	struct perf_cpu cpu;
1176d18804bSIan Rogers 	int idx, thread, err = 0;
1183ce311afSJiri Olsa 
1193ce311afSJiri Olsa 	if (cpus == NULL) {
1203ce311afSJiri Olsa 		static struct perf_cpu_map *empty_cpu_map;
1213ce311afSJiri Olsa 
1223ce311afSJiri Olsa 		if (empty_cpu_map == NULL) {
1233ce311afSJiri Olsa 			empty_cpu_map = perf_cpu_map__dummy_new();
1243ce311afSJiri Olsa 			if (empty_cpu_map == NULL)
1253ce311afSJiri Olsa 				return -ENOMEM;
1263ce311afSJiri Olsa 		}
1273ce311afSJiri Olsa 
1283ce311afSJiri Olsa 		cpus = empty_cpu_map;
1293ce311afSJiri Olsa 	}
1303ce311afSJiri Olsa 
1313ce311afSJiri Olsa 	if (threads == NULL) {
1323ce311afSJiri Olsa 		static struct perf_thread_map *empty_thread_map;
1333ce311afSJiri Olsa 
1343ce311afSJiri Olsa 		if (empty_thread_map == NULL) {
1353ce311afSJiri Olsa 			empty_thread_map = perf_thread_map__new_dummy();
1363ce311afSJiri Olsa 			if (empty_thread_map == NULL)
1373ce311afSJiri Olsa 				return -ENOMEM;
1383ce311afSJiri Olsa 		}
1393ce311afSJiri Olsa 
1403ce311afSJiri Olsa 		threads = empty_thread_map;
1413ce311afSJiri Olsa 	}
1423ce311afSJiri Olsa 
1433ce311afSJiri Olsa 	if (evsel->fd == NULL &&
14444028699SIan Rogers 	    perf_evsel__alloc_fd(evsel, perf_cpu_map__nr(cpus), threads->nr) < 0)
1453ce311afSJiri Olsa 		return -ENOMEM;
1463ce311afSJiri Olsa 
1477e3d1784SIan Rogers 	perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
1483ce311afSJiri Olsa 		for (thread = 0; thread < threads->nr; thread++) {
149aba5daebSIan Rogers 			int fd, group_fd, *evsel_fd;
150aba5daebSIan Rogers 
1517e3d1784SIan Rogers 			evsel_fd = FD(evsel, idx, thread);
15294725994SIan Rogers 			if (evsel_fd == NULL) {
15394725994SIan Rogers 				err = -EINVAL;
15494725994SIan Rogers 				goto out;
15594725994SIan Rogers 			}
1563fd35de1SJiri Olsa 
1577e3d1784SIan Rogers 			err = get_group_fd(evsel, idx, thread, &group_fd);
158e2c18168SArnaldo Carvalho de Melo 			if (err < 0)
15994725994SIan Rogers 				goto out;
1603ce311afSJiri Olsa 
1613ce311afSJiri Olsa 			fd = sys_perf_event_open(&evsel->attr,
1623ce311afSJiri Olsa 						 threads->map[thread].pid,
1637e3d1784SIan Rogers 						 cpu, group_fd, 0);
1643ce311afSJiri Olsa 
16594725994SIan Rogers 			if (fd < 0) {
16694725994SIan Rogers 				err = -errno;
16794725994SIan Rogers 				goto out;
16894725994SIan Rogers 			}
1693ce311afSJiri Olsa 
170aba5daebSIan Rogers 			*evsel_fd = fd;
1713ce311afSJiri Olsa 		}
1723ce311afSJiri Olsa 	}
17394725994SIan Rogers out:
17494725994SIan Rogers 	if (err)
17594725994SIan Rogers 		perf_evsel__close(evsel);
1763ce311afSJiri Olsa 
1773ce311afSJiri Olsa 	return err;
1783ce311afSJiri Olsa }
1793ce311afSJiri Olsa 
perf_evsel__close_fd_cpu(struct perf_evsel * evsel,int cpu_map_idx)1807e3d1784SIan Rogers static void perf_evsel__close_fd_cpu(struct perf_evsel *evsel, int cpu_map_idx)
1813ce311afSJiri Olsa {
1823ce311afSJiri Olsa 	int thread;
1833ce311afSJiri Olsa 
1843ce311afSJiri Olsa 	for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
1857e3d1784SIan Rogers 		int *fd = FD(evsel, cpu_map_idx, thread);
186aba5daebSIan Rogers 
187aba5daebSIan Rogers 		if (fd && *fd >= 0) {
188aba5daebSIan Rogers 			close(*fd);
189aba5daebSIan Rogers 			*fd = -1;
190aba5daebSIan Rogers 		}
1913ce311afSJiri Olsa 	}
1923ce311afSJiri Olsa }
1933ce311afSJiri Olsa 
perf_evsel__close_fd(struct perf_evsel * evsel)1943ce311afSJiri Olsa void perf_evsel__close_fd(struct perf_evsel *evsel)
1953ce311afSJiri Olsa {
1967e3d1784SIan Rogers 	for (int idx = 0; idx < xyarray__max_x(evsel->fd); idx++)
1977e3d1784SIan Rogers 		perf_evsel__close_fd_cpu(evsel, idx);
1983ce311afSJiri Olsa }
1993ce311afSJiri Olsa 
perf_evsel__free_fd(struct perf_evsel * evsel)2003ce311afSJiri Olsa void perf_evsel__free_fd(struct perf_evsel *evsel)
2013ce311afSJiri Olsa {
2023ce311afSJiri Olsa 	xyarray__delete(evsel->fd);
2033ce311afSJiri Olsa 	evsel->fd = NULL;
2043ce311afSJiri Olsa }
2053ce311afSJiri Olsa 
perf_evsel__close(struct perf_evsel * evsel)2063ce311afSJiri Olsa void perf_evsel__close(struct perf_evsel *evsel)
2073ce311afSJiri Olsa {
2083ce311afSJiri Olsa 	if (evsel->fd == NULL)
2093ce311afSJiri Olsa 		return;
2103ce311afSJiri Olsa 
2113ce311afSJiri Olsa 	perf_evsel__close_fd(evsel);
2123ce311afSJiri Olsa 	perf_evsel__free_fd(evsel);
2133ce311afSJiri Olsa }
2143ce311afSJiri Olsa 
perf_evsel__close_cpu(struct perf_evsel * evsel,int cpu_map_idx)2157e3d1784SIan Rogers void perf_evsel__close_cpu(struct perf_evsel *evsel, int cpu_map_idx)
2163ce311afSJiri Olsa {
2173ce311afSJiri Olsa 	if (evsel->fd == NULL)
2183ce311afSJiri Olsa 		return;
2193ce311afSJiri Olsa 
2207e3d1784SIan Rogers 	perf_evsel__close_fd_cpu(evsel, cpu_map_idx);
2213ce311afSJiri Olsa }
2223ce311afSJiri Olsa 
perf_evsel__munmap(struct perf_evsel * evsel)2236cd70754SRob Herring void perf_evsel__munmap(struct perf_evsel *evsel)
2246cd70754SRob Herring {
2257e3d1784SIan Rogers 	int idx, thread;
2266cd70754SRob Herring 
2276cd70754SRob Herring 	if (evsel->fd == NULL || evsel->mmap == NULL)
2286cd70754SRob Herring 		return;
2296cd70754SRob Herring 
2307e3d1784SIan Rogers 	for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
2316cd70754SRob Herring 		for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
2327e3d1784SIan Rogers 			int *fd = FD(evsel, idx, thread);
2336cd70754SRob Herring 
234aba5daebSIan Rogers 			if (fd == NULL || *fd < 0)
2356cd70754SRob Herring 				continue;
2366cd70754SRob Herring 
2377e3d1784SIan Rogers 			perf_mmap__munmap(MMAP(evsel, idx, thread));
2386cd70754SRob Herring 		}
2396cd70754SRob Herring 	}
2406cd70754SRob Herring 
2416cd70754SRob Herring 	xyarray__delete(evsel->mmap);
2426cd70754SRob Herring 	evsel->mmap = NULL;
2436cd70754SRob Herring }
2446cd70754SRob Herring 
perf_evsel__mmap(struct perf_evsel * evsel,int pages)2456cd70754SRob Herring int perf_evsel__mmap(struct perf_evsel *evsel, int pages)
2466cd70754SRob Herring {
2477e3d1784SIan Rogers 	int ret, idx, thread;
2486cd70754SRob Herring 	struct perf_mmap_param mp = {
2496cd70754SRob Herring 		.prot = PROT_READ | PROT_WRITE,
2506cd70754SRob Herring 		.mask = (pages * page_size) - 1,
2516cd70754SRob Herring 	};
2526cd70754SRob Herring 
2536cd70754SRob Herring 	if (evsel->fd == NULL || evsel->mmap)
2546cd70754SRob Herring 		return -EINVAL;
2556cd70754SRob Herring 
2566cd70754SRob Herring 	if (perf_evsel__alloc_mmap(evsel, xyarray__max_x(evsel->fd), xyarray__max_y(evsel->fd)) < 0)
2576cd70754SRob Herring 		return -ENOMEM;
2586cd70754SRob Herring 
2597e3d1784SIan Rogers 	for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
2606cd70754SRob Herring 		for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
2617e3d1784SIan Rogers 			int *fd = FD(evsel, idx, thread);
262aba5daebSIan Rogers 			struct perf_mmap *map;
2636d18804bSIan Rogers 			struct perf_cpu cpu = perf_cpu_map__cpu(evsel->cpus, idx);
2646cd70754SRob Herring 
265aba5daebSIan Rogers 			if (fd == NULL || *fd < 0)
2666cd70754SRob Herring 				continue;
2676cd70754SRob Herring 
2687e3d1784SIan Rogers 			map = MMAP(evsel, idx, thread);
2696cd70754SRob Herring 			perf_mmap__init(map, NULL, false, NULL);
2706cd70754SRob Herring 
27147ffe806SIan Rogers 			ret = perf_mmap__mmap(map, &mp, *fd, cpu);
2726cd70754SRob Herring 			if (ret) {
2736cd70754SRob Herring 				perf_evsel__munmap(evsel);
2746cd70754SRob Herring 				return ret;
2756cd70754SRob Herring 			}
2766cd70754SRob Herring 		}
2776cd70754SRob Herring 	}
2786cd70754SRob Herring 
2796cd70754SRob Herring 	return 0;
2806cd70754SRob Herring }
2816cd70754SRob Herring 
perf_evsel__mmap_base(struct perf_evsel * evsel,int cpu_map_idx,int thread)2827e3d1784SIan Rogers void *perf_evsel__mmap_base(struct perf_evsel *evsel, int cpu_map_idx, int thread)
2836cd70754SRob Herring {
2847e3d1784SIan Rogers 	int *fd = FD(evsel, cpu_map_idx, thread);
285aba5daebSIan Rogers 
2867e3d1784SIan Rogers 	if (fd == NULL || *fd < 0 || MMAP(evsel, cpu_map_idx, thread) == NULL)
2876cd70754SRob Herring 		return NULL;
2886cd70754SRob Herring 
2897e3d1784SIan Rogers 	return MMAP(evsel, cpu_map_idx, thread)->base;
2906cd70754SRob Herring }
2916cd70754SRob Herring 
perf_evsel__read_size(struct perf_evsel * evsel)2923ce311afSJiri Olsa int perf_evsel__read_size(struct perf_evsel *evsel)
2933ce311afSJiri Olsa {
2943ce311afSJiri Olsa 	u64 read_format = evsel->attr.read_format;
2953ce311afSJiri Olsa 	int entry = sizeof(u64); /* value */
2963ce311afSJiri Olsa 	int size = 0;
2973ce311afSJiri Olsa 	int nr = 1;
2983ce311afSJiri Olsa 
2993ce311afSJiri Olsa 	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
3003ce311afSJiri Olsa 		size += sizeof(u64);
3013ce311afSJiri Olsa 
3023ce311afSJiri Olsa 	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
3033ce311afSJiri Olsa 		size += sizeof(u64);
3043ce311afSJiri Olsa 
3053ce311afSJiri Olsa 	if (read_format & PERF_FORMAT_ID)
3063ce311afSJiri Olsa 		entry += sizeof(u64);
3073ce311afSJiri Olsa 
308*89e3106fSNamhyung Kim 	if (read_format & PERF_FORMAT_LOST)
309*89e3106fSNamhyung Kim 		entry += sizeof(u64);
310*89e3106fSNamhyung Kim 
3113ce311afSJiri Olsa 	if (read_format & PERF_FORMAT_GROUP) {
3123ce311afSJiri Olsa 		nr = evsel->nr_members;
3133ce311afSJiri Olsa 		size += sizeof(u64);
3143ce311afSJiri Olsa 	}
3153ce311afSJiri Olsa 
3163ce311afSJiri Olsa 	size += entry * nr;
3173ce311afSJiri Olsa 	return size;
3183ce311afSJiri Olsa }
3193ce311afSJiri Olsa 
320*89e3106fSNamhyung Kim /* 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)321*89e3106fSNamhyung Kim static int perf_evsel__read_group(struct perf_evsel *evsel, int cpu_map_idx,
322*89e3106fSNamhyung Kim 				  int thread, struct perf_counts_values *count)
323*89e3106fSNamhyung Kim {
324*89e3106fSNamhyung Kim 	size_t size = perf_evsel__read_size(evsel);
325*89e3106fSNamhyung Kim 	int *fd = FD(evsel, cpu_map_idx, thread);
326*89e3106fSNamhyung Kim 	u64 read_format = evsel->attr.read_format;
327*89e3106fSNamhyung Kim 	u64 *data;
328*89e3106fSNamhyung Kim 	int idx = 1;
329*89e3106fSNamhyung Kim 
330*89e3106fSNamhyung Kim 	if (fd == NULL || *fd < 0)
331*89e3106fSNamhyung Kim 		return -EINVAL;
332*89e3106fSNamhyung Kim 
333*89e3106fSNamhyung Kim 	data = calloc(1, size);
334*89e3106fSNamhyung Kim 	if (data == NULL)
335*89e3106fSNamhyung Kim 		return -ENOMEM;
336*89e3106fSNamhyung Kim 
337*89e3106fSNamhyung Kim 	if (readn(*fd, data, size) <= 0) {
338*89e3106fSNamhyung Kim 		free(data);
339*89e3106fSNamhyung Kim 		return -errno;
340*89e3106fSNamhyung Kim 	}
341*89e3106fSNamhyung Kim 
342*89e3106fSNamhyung Kim 	/*
343*89e3106fSNamhyung Kim 	 * This reads only the leader event intentionally since we don't have
344*89e3106fSNamhyung Kim 	 * perf counts values for sibling events.
345*89e3106fSNamhyung Kim 	 */
346*89e3106fSNamhyung Kim 	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
347*89e3106fSNamhyung Kim 		count->ena = data[idx++];
348*89e3106fSNamhyung Kim 	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
349*89e3106fSNamhyung Kim 		count->run = data[idx++];
350*89e3106fSNamhyung Kim 
351*89e3106fSNamhyung Kim 	/* value is always available */
352*89e3106fSNamhyung Kim 	count->val = data[idx++];
353*89e3106fSNamhyung Kim 	if (read_format & PERF_FORMAT_ID)
354*89e3106fSNamhyung Kim 		count->id = data[idx++];
355*89e3106fSNamhyung Kim 	if (read_format & PERF_FORMAT_LOST)
356*89e3106fSNamhyung Kim 		count->lost = data[idx++];
357*89e3106fSNamhyung Kim 
358*89e3106fSNamhyung Kim 	free(data);
359*89e3106fSNamhyung Kim 	return 0;
360*89e3106fSNamhyung Kim }
361*89e3106fSNamhyung Kim 
362*89e3106fSNamhyung Kim /*
363*89e3106fSNamhyung Kim  * The perf read format is very flexible.  It needs to set the proper
364*89e3106fSNamhyung Kim  * values according to the read format.
365*89e3106fSNamhyung Kim  */
perf_evsel__adjust_values(struct perf_evsel * evsel,u64 * buf,struct perf_counts_values * count)366*89e3106fSNamhyung Kim static void perf_evsel__adjust_values(struct perf_evsel *evsel, u64 *buf,
367*89e3106fSNamhyung Kim 				      struct perf_counts_values *count)
368*89e3106fSNamhyung Kim {
369*89e3106fSNamhyung Kim 	u64 read_format = evsel->attr.read_format;
370*89e3106fSNamhyung Kim 	int n = 0;
371*89e3106fSNamhyung Kim 
372*89e3106fSNamhyung Kim 	count->val = buf[n++];
373*89e3106fSNamhyung Kim 
374*89e3106fSNamhyung Kim 	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
375*89e3106fSNamhyung Kim 		count->ena = buf[n++];
376*89e3106fSNamhyung Kim 
377*89e3106fSNamhyung Kim 	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
378*89e3106fSNamhyung Kim 		count->run = buf[n++];
379*89e3106fSNamhyung Kim 
380*89e3106fSNamhyung Kim 	if (read_format & PERF_FORMAT_ID)
381*89e3106fSNamhyung Kim 		count->id = buf[n++];
382*89e3106fSNamhyung Kim 
383*89e3106fSNamhyung Kim 	if (read_format & PERF_FORMAT_LOST)
384*89e3106fSNamhyung Kim 		count->lost = buf[n++];
385*89e3106fSNamhyung Kim }
386*89e3106fSNamhyung Kim 
perf_evsel__read(struct perf_evsel * evsel,int cpu_map_idx,int thread,struct perf_counts_values * count)3877e3d1784SIan Rogers int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int thread,
3883ce311afSJiri Olsa 		     struct perf_counts_values *count)
3893ce311afSJiri Olsa {
3903ce311afSJiri Olsa 	size_t size = perf_evsel__read_size(evsel);
3917e3d1784SIan Rogers 	int *fd = FD(evsel, cpu_map_idx, thread);
392*89e3106fSNamhyung Kim 	u64 read_format = evsel->attr.read_format;
393*89e3106fSNamhyung Kim 	struct perf_counts_values buf;
3943ce311afSJiri Olsa 
3953ce311afSJiri Olsa 	memset(count, 0, sizeof(*count));
3963ce311afSJiri Olsa 
397aba5daebSIan Rogers 	if (fd == NULL || *fd < 0)
3983ce311afSJiri Olsa 		return -EINVAL;
3993ce311afSJiri Olsa 
400*89e3106fSNamhyung Kim 	if (read_format & PERF_FORMAT_GROUP)
401*89e3106fSNamhyung Kim 		return perf_evsel__read_group(evsel, cpu_map_idx, thread, count);
402*89e3106fSNamhyung Kim 
4037e3d1784SIan Rogers 	if (MMAP(evsel, cpu_map_idx, thread) &&
404*89e3106fSNamhyung Kim 	    !(read_format & (PERF_FORMAT_ID | PERF_FORMAT_LOST)) &&
4057e3d1784SIan Rogers 	    !perf_mmap__read_self(MMAP(evsel, cpu_map_idx, thread), count))
40647d01e7bSRob Herring 		return 0;
40747d01e7bSRob Herring 
408*89e3106fSNamhyung Kim 	if (readn(*fd, buf.values, size) <= 0)
4093ce311afSJiri Olsa 		return -errno;
4103ce311afSJiri Olsa 
411*89e3106fSNamhyung Kim 	perf_evsel__adjust_values(evsel, buf.values, count);
4123ce311afSJiri Olsa 	return 0;
4133ce311afSJiri Olsa }
4143ce311afSJiri Olsa 
perf_evsel__ioctl(struct perf_evsel * evsel,int ioc,void * arg,int cpu_map_idx,int thread)4154bbac9a1SAdrian Hunter static int perf_evsel__ioctl(struct perf_evsel *evsel, int ioc, void *arg,
4164bbac9a1SAdrian Hunter 			     int cpu_map_idx, int thread)
4174bbac9a1SAdrian Hunter {
4184bbac9a1SAdrian Hunter 	int *fd = FD(evsel, cpu_map_idx, thread);
4194bbac9a1SAdrian Hunter 
4204bbac9a1SAdrian Hunter 	if (fd == NULL || *fd < 0)
4214bbac9a1SAdrian Hunter 		return -1;
4224bbac9a1SAdrian Hunter 
4234bbac9a1SAdrian Hunter 	return ioctl(*fd, ioc, arg);
4244bbac9a1SAdrian Hunter }
4254bbac9a1SAdrian Hunter 
perf_evsel__run_ioctl(struct perf_evsel * evsel,int ioc,void * arg,int cpu_map_idx)4263ce311afSJiri Olsa static int perf_evsel__run_ioctl(struct perf_evsel *evsel,
4273ce311afSJiri Olsa 				 int ioc,  void *arg,
4287e3d1784SIan Rogers 				 int cpu_map_idx)
4293ce311afSJiri Olsa {
4303ce311afSJiri Olsa 	int thread;
4313ce311afSJiri Olsa 
4323ce311afSJiri Olsa 	for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
4334bbac9a1SAdrian Hunter 		int err = perf_evsel__ioctl(evsel, ioc, arg, cpu_map_idx, thread);
4343ce311afSJiri Olsa 
4353ce311afSJiri Olsa 		if (err)
4363ce311afSJiri Olsa 			return err;
4373ce311afSJiri Olsa 	}
4383ce311afSJiri Olsa 
4393ce311afSJiri Olsa 	return 0;
4403ce311afSJiri Olsa }
4413ce311afSJiri Olsa 
perf_evsel__enable_cpu(struct perf_evsel * evsel,int cpu_map_idx)4427e3d1784SIan Rogers int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
4433ce311afSJiri Olsa {
4447e3d1784SIan Rogers 	return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, cpu_map_idx);
4453ce311afSJiri Olsa }
4463ce311afSJiri Olsa 
perf_evsel__enable_thread(struct perf_evsel * evsel,int thread)44700632610SAdrian Hunter int perf_evsel__enable_thread(struct perf_evsel *evsel, int thread)
44800632610SAdrian Hunter {
44900632610SAdrian Hunter 	struct perf_cpu cpu __maybe_unused;
45000632610SAdrian Hunter 	int idx;
45100632610SAdrian Hunter 	int err;
45200632610SAdrian Hunter 
45300632610SAdrian Hunter 	perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
45400632610SAdrian Hunter 		err = perf_evsel__ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, idx, thread);
45500632610SAdrian Hunter 		if (err)
45600632610SAdrian Hunter 			return err;
45700632610SAdrian Hunter 	}
45800632610SAdrian Hunter 
45900632610SAdrian Hunter 	return 0;
46000632610SAdrian Hunter }
46100632610SAdrian Hunter 
perf_evsel__enable(struct perf_evsel * evsel)4623ce311afSJiri Olsa int perf_evsel__enable(struct perf_evsel *evsel)
4633ce311afSJiri Olsa {
4643ce311afSJiri Olsa 	int i;
4653ce311afSJiri Olsa 	int err = 0;
4663ce311afSJiri Olsa 
4673ce311afSJiri Olsa 	for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
4683ce311afSJiri Olsa 		err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, i);
4693ce311afSJiri Olsa 	return err;
4703ce311afSJiri Olsa }
4713ce311afSJiri Olsa 
perf_evsel__disable_cpu(struct perf_evsel * evsel,int cpu_map_idx)4727e3d1784SIan Rogers int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
4733ce311afSJiri Olsa {
4747e3d1784SIan Rogers 	return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, cpu_map_idx);
4753ce311afSJiri Olsa }
4763ce311afSJiri Olsa 
perf_evsel__disable(struct perf_evsel * evsel)4773ce311afSJiri Olsa int perf_evsel__disable(struct perf_evsel *evsel)
4783ce311afSJiri Olsa {
4793ce311afSJiri Olsa 	int i;
4803ce311afSJiri Olsa 	int err = 0;
4813ce311afSJiri Olsa 
4823ce311afSJiri Olsa 	for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
4833ce311afSJiri Olsa 		err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, i);
4843ce311afSJiri Olsa 	return err;
4853ce311afSJiri Olsa }
4863ce311afSJiri Olsa 
perf_evsel__apply_filter(struct perf_evsel * evsel,const char * filter)4873ce311afSJiri Olsa int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter)
4883ce311afSJiri Olsa {
4893ce311afSJiri Olsa 	int err = 0, i;
4903ce311afSJiri Olsa 
49144028699SIan Rogers 	for (i = 0; i < perf_cpu_map__nr(evsel->cpus) && !err; i++)
4923ce311afSJiri Olsa 		err = perf_evsel__run_ioctl(evsel,
4933ce311afSJiri Olsa 				     PERF_EVENT_IOC_SET_FILTER,
4943ce311afSJiri Olsa 				     (void *)filter, i);
4953ce311afSJiri Olsa 	return err;
4963ce311afSJiri Olsa }
4973ce311afSJiri Olsa 
perf_evsel__cpus(struct perf_evsel * evsel)4983ce311afSJiri Olsa struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
4993ce311afSJiri Olsa {
5003ce311afSJiri Olsa 	return evsel->cpus;
5013ce311afSJiri Olsa }
5023ce311afSJiri Olsa 
perf_evsel__threads(struct perf_evsel * evsel)5033ce311afSJiri Olsa struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel)
5043ce311afSJiri Olsa {
5053ce311afSJiri Olsa 	return evsel->threads;
5063ce311afSJiri Olsa }
5073ce311afSJiri Olsa 
perf_evsel__attr(struct perf_evsel * evsel)5083ce311afSJiri Olsa struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel)
5093ce311afSJiri Olsa {
5103ce311afSJiri Olsa 	return &evsel->attr;
5113ce311afSJiri Olsa }
5123ce311afSJiri Olsa 
perf_evsel__alloc_id(struct perf_evsel * evsel,int ncpus,int nthreads)5133ce311afSJiri Olsa int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
5143ce311afSJiri Olsa {
5153ce311afSJiri Olsa 	if (ncpus == 0 || nthreads == 0)
5163ce311afSJiri Olsa 		return 0;
5173ce311afSJiri Olsa 
5183ce311afSJiri Olsa 	evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
5193ce311afSJiri Olsa 	if (evsel->sample_id == NULL)
5203ce311afSJiri Olsa 		return -ENOMEM;
5213ce311afSJiri Olsa 
5223ce311afSJiri Olsa 	evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
5233ce311afSJiri Olsa 	if (evsel->id == NULL) {
5243ce311afSJiri Olsa 		xyarray__delete(evsel->sample_id);
5253ce311afSJiri Olsa 		evsel->sample_id = NULL;
5263ce311afSJiri Olsa 		return -ENOMEM;
5273ce311afSJiri Olsa 	}
5283ce311afSJiri Olsa 
5293ce311afSJiri Olsa 	return 0;
5303ce311afSJiri Olsa }
5313ce311afSJiri Olsa 
perf_evsel__free_id(struct perf_evsel * evsel)5323ce311afSJiri Olsa void perf_evsel__free_id(struct perf_evsel *evsel)
5333ce311afSJiri Olsa {
5343ce311afSJiri Olsa 	xyarray__delete(evsel->sample_id);
5353ce311afSJiri Olsa 	evsel->sample_id = NULL;
5363ce311afSJiri Olsa 	zfree(&evsel->id);
5373ce311afSJiri Olsa 	evsel->ids = 0;
5383ce311afSJiri Olsa }
5399a5b2d1aSShunsuke Nakamura 
perf_counts_values__scale(struct perf_counts_values * count,bool scale,__s8 * pscaled)5409a5b2d1aSShunsuke Nakamura void perf_counts_values__scale(struct perf_counts_values *count,
5419a5b2d1aSShunsuke Nakamura 			       bool scale, __s8 *pscaled)
5429a5b2d1aSShunsuke Nakamura {
5439a5b2d1aSShunsuke Nakamura 	s8 scaled = 0;
5449a5b2d1aSShunsuke Nakamura 
5459a5b2d1aSShunsuke Nakamura 	if (scale) {
5469a5b2d1aSShunsuke Nakamura 		if (count->run == 0) {
5479a5b2d1aSShunsuke Nakamura 			scaled = -1;
5489a5b2d1aSShunsuke Nakamura 			count->val = 0;
5499a5b2d1aSShunsuke Nakamura 		} else if (count->run < count->ena) {
5509a5b2d1aSShunsuke Nakamura 			scaled = 1;
5519a5b2d1aSShunsuke Nakamura 			count->val = (u64)((double)count->val * count->ena / count->run);
5529a5b2d1aSShunsuke Nakamura 		}
5539a5b2d1aSShunsuke Nakamura 	}
5549a5b2d1aSShunsuke Nakamura 
5559a5b2d1aSShunsuke Nakamura 	if (pscaled)
5569a5b2d1aSShunsuke Nakamura 		*pscaled = scaled;
5579a5b2d1aSShunsuke Nakamura }
558