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