18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <perf/evlist.h> 38c2ecf20Sopenharmony_ci#include <perf/evsel.h> 48c2ecf20Sopenharmony_ci#include <linux/bitops.h> 58c2ecf20Sopenharmony_ci#include <linux/list.h> 68c2ecf20Sopenharmony_ci#include <linux/hash.h> 78c2ecf20Sopenharmony_ci#include <sys/ioctl.h> 88c2ecf20Sopenharmony_ci#include <internal/evlist.h> 98c2ecf20Sopenharmony_ci#include <internal/evsel.h> 108c2ecf20Sopenharmony_ci#include <internal/xyarray.h> 118c2ecf20Sopenharmony_ci#include <internal/mmap.h> 128c2ecf20Sopenharmony_ci#include <internal/cpumap.h> 138c2ecf20Sopenharmony_ci#include <internal/threadmap.h> 148c2ecf20Sopenharmony_ci#include <internal/lib.h> 158c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 168c2ecf20Sopenharmony_ci#include <stdlib.h> 178c2ecf20Sopenharmony_ci#include <errno.h> 188c2ecf20Sopenharmony_ci#include <unistd.h> 198c2ecf20Sopenharmony_ci#include <fcntl.h> 208c2ecf20Sopenharmony_ci#include <signal.h> 218c2ecf20Sopenharmony_ci#include <poll.h> 228c2ecf20Sopenharmony_ci#include <sys/mman.h> 238c2ecf20Sopenharmony_ci#include <perf/cpumap.h> 248c2ecf20Sopenharmony_ci#include <perf/threadmap.h> 258c2ecf20Sopenharmony_ci#include <api/fd/array.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_civoid perf_evlist__init(struct perf_evlist *evlist) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci int i; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) 328c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&evlist->heads[i]); 338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&evlist->entries); 348c2ecf20Sopenharmony_ci evlist->nr_entries = 0; 358c2ecf20Sopenharmony_ci fdarray__init(&evlist->pollfd, 64); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic void __perf_evlist__propagate_maps(struct perf_evlist *evlist, 398c2ecf20Sopenharmony_ci struct perf_evsel *evsel) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci /* 428c2ecf20Sopenharmony_ci * We already have cpus for evsel (via PMU sysfs) so 438c2ecf20Sopenharmony_ci * keep it, if there's no target cpu list defined. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci if (!evsel->own_cpus || evlist->has_user_cpus) { 468c2ecf20Sopenharmony_ci perf_cpu_map__put(evsel->cpus); 478c2ecf20Sopenharmony_ci evsel->cpus = perf_cpu_map__get(evlist->cpus); 488c2ecf20Sopenharmony_ci } else if (!evsel->system_wide && perf_cpu_map__empty(evlist->cpus)) { 498c2ecf20Sopenharmony_ci perf_cpu_map__put(evsel->cpus); 508c2ecf20Sopenharmony_ci evsel->cpus = perf_cpu_map__get(evlist->cpus); 518c2ecf20Sopenharmony_ci } else if (evsel->cpus != evsel->own_cpus) { 528c2ecf20Sopenharmony_ci perf_cpu_map__put(evsel->cpus); 538c2ecf20Sopenharmony_ci evsel->cpus = perf_cpu_map__get(evsel->own_cpus); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci perf_thread_map__put(evsel->threads); 578c2ecf20Sopenharmony_ci evsel->threads = perf_thread_map__get(evlist->threads); 588c2ecf20Sopenharmony_ci evlist->all_cpus = perf_cpu_map__merge(evlist->all_cpus, evsel->cpus); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic void perf_evlist__propagate_maps(struct perf_evlist *evlist) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct perf_evsel *evsel; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci perf_evlist__for_each_evsel(evlist, evsel) 668c2ecf20Sopenharmony_ci __perf_evlist__propagate_maps(evlist, evsel); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_civoid perf_evlist__add(struct perf_evlist *evlist, 708c2ecf20Sopenharmony_ci struct perf_evsel *evsel) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci list_add_tail(&evsel->node, &evlist->entries); 738c2ecf20Sopenharmony_ci evlist->nr_entries += 1; 748c2ecf20Sopenharmony_ci __perf_evlist__propagate_maps(evlist, evsel); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_civoid perf_evlist__remove(struct perf_evlist *evlist, 788c2ecf20Sopenharmony_ci struct perf_evsel *evsel) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci list_del_init(&evsel->node); 818c2ecf20Sopenharmony_ci evlist->nr_entries -= 1; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct perf_evlist *perf_evlist__new(void) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct perf_evlist *evlist = zalloc(sizeof(*evlist)); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (evlist != NULL) 898c2ecf20Sopenharmony_ci perf_evlist__init(evlist); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return evlist; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct perf_evsel * 958c2ecf20Sopenharmony_ciperf_evlist__next(struct perf_evlist *evlist, struct perf_evsel *prev) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct perf_evsel *next; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (!prev) { 1008c2ecf20Sopenharmony_ci next = list_first_entry(&evlist->entries, 1018c2ecf20Sopenharmony_ci struct perf_evsel, 1028c2ecf20Sopenharmony_ci node); 1038c2ecf20Sopenharmony_ci } else { 1048c2ecf20Sopenharmony_ci next = list_next_entry(prev, node); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* Empty list is noticed here so don't need checking on entry. */ 1088c2ecf20Sopenharmony_ci if (&next->node == &evlist->entries) 1098c2ecf20Sopenharmony_ci return NULL; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return next; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void perf_evlist__purge(struct perf_evlist *evlist) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct perf_evsel *pos, *n; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci perf_evlist__for_each_entry_safe(evlist, n, pos) { 1198c2ecf20Sopenharmony_ci list_del_init(&pos->node); 1208c2ecf20Sopenharmony_ci perf_evsel__delete(pos); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci evlist->nr_entries = 0; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_civoid perf_evlist__exit(struct perf_evlist *evlist) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci perf_cpu_map__put(evlist->cpus); 1298c2ecf20Sopenharmony_ci perf_cpu_map__put(evlist->all_cpus); 1308c2ecf20Sopenharmony_ci perf_thread_map__put(evlist->threads); 1318c2ecf20Sopenharmony_ci evlist->cpus = NULL; 1328c2ecf20Sopenharmony_ci evlist->all_cpus = NULL; 1338c2ecf20Sopenharmony_ci evlist->threads = NULL; 1348c2ecf20Sopenharmony_ci fdarray__exit(&evlist->pollfd); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_civoid perf_evlist__delete(struct perf_evlist *evlist) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci if (evlist == NULL) 1408c2ecf20Sopenharmony_ci return; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci perf_evlist__munmap(evlist); 1438c2ecf20Sopenharmony_ci perf_evlist__close(evlist); 1448c2ecf20Sopenharmony_ci perf_evlist__purge(evlist); 1458c2ecf20Sopenharmony_ci perf_evlist__exit(evlist); 1468c2ecf20Sopenharmony_ci free(evlist); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_civoid perf_evlist__set_maps(struct perf_evlist *evlist, 1508c2ecf20Sopenharmony_ci struct perf_cpu_map *cpus, 1518c2ecf20Sopenharmony_ci struct perf_thread_map *threads) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci /* 1548c2ecf20Sopenharmony_ci * Allow for the possibility that one or another of the maps isn't being 1558c2ecf20Sopenharmony_ci * changed i.e. don't put it. Note we are assuming the maps that are 1568c2ecf20Sopenharmony_ci * being applied are brand new and evlist is taking ownership of the 1578c2ecf20Sopenharmony_ci * original reference count of 1. If that is not the case it is up to 1588c2ecf20Sopenharmony_ci * the caller to increase the reference count. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci if (cpus != evlist->cpus) { 1618c2ecf20Sopenharmony_ci perf_cpu_map__put(evlist->cpus); 1628c2ecf20Sopenharmony_ci evlist->cpus = perf_cpu_map__get(cpus); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (threads != evlist->threads) { 1668c2ecf20Sopenharmony_ci perf_thread_map__put(evlist->threads); 1678c2ecf20Sopenharmony_ci evlist->threads = perf_thread_map__get(threads); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (!evlist->all_cpus && cpus) 1718c2ecf20Sopenharmony_ci evlist->all_cpus = perf_cpu_map__get(cpus); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci perf_evlist__propagate_maps(evlist); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ciint perf_evlist__open(struct perf_evlist *evlist) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct perf_evsel *evsel; 1798c2ecf20Sopenharmony_ci int err; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci perf_evlist__for_each_entry(evlist, evsel) { 1828c2ecf20Sopenharmony_ci err = perf_evsel__open(evsel, evsel->cpus, evsel->threads); 1838c2ecf20Sopenharmony_ci if (err < 0) 1848c2ecf20Sopenharmony_ci goto out_err; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ciout_err: 1908c2ecf20Sopenharmony_ci perf_evlist__close(evlist); 1918c2ecf20Sopenharmony_ci return err; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_civoid perf_evlist__close(struct perf_evlist *evlist) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct perf_evsel *evsel; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci perf_evlist__for_each_entry_reverse(evlist, evsel) 1998c2ecf20Sopenharmony_ci perf_evsel__close(evsel); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_civoid perf_evlist__enable(struct perf_evlist *evlist) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct perf_evsel *evsel; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci perf_evlist__for_each_entry(evlist, evsel) 2078c2ecf20Sopenharmony_ci perf_evsel__enable(evsel); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_civoid perf_evlist__disable(struct perf_evlist *evlist) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct perf_evsel *evsel; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci perf_evlist__for_each_entry(evlist, evsel) 2158c2ecf20Sopenharmony_ci perf_evsel__disable(evsel); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ciu64 perf_evlist__read_format(struct perf_evlist *evlist) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct perf_evsel *first = perf_evlist__first(evlist); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return first->attr.read_format; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci#define SID(e, x, y) xyarray__entry(e->sample_id, x, y) 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void perf_evlist__id_hash(struct perf_evlist *evlist, 2288c2ecf20Sopenharmony_ci struct perf_evsel *evsel, 2298c2ecf20Sopenharmony_ci int cpu, int thread, u64 id) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci int hash; 2328c2ecf20Sopenharmony_ci struct perf_sample_id *sid = SID(evsel, cpu, thread); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci sid->id = id; 2358c2ecf20Sopenharmony_ci sid->evsel = evsel; 2368c2ecf20Sopenharmony_ci hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS); 2378c2ecf20Sopenharmony_ci hlist_add_head(&sid->node, &evlist->heads[hash]); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_civoid perf_evlist__id_add(struct perf_evlist *evlist, 2418c2ecf20Sopenharmony_ci struct perf_evsel *evsel, 2428c2ecf20Sopenharmony_ci int cpu, int thread, u64 id) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci perf_evlist__id_hash(evlist, evsel, cpu, thread, id); 2458c2ecf20Sopenharmony_ci evsel->id[evsel->ids++] = id; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ciint perf_evlist__id_add_fd(struct perf_evlist *evlist, 2498c2ecf20Sopenharmony_ci struct perf_evsel *evsel, 2508c2ecf20Sopenharmony_ci int cpu, int thread, int fd) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci u64 read_data[4] = { 0, }; 2538c2ecf20Sopenharmony_ci int id_idx = 1; /* The first entry is the counter value */ 2548c2ecf20Sopenharmony_ci u64 id; 2558c2ecf20Sopenharmony_ci int ret; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci ret = ioctl(fd, PERF_EVENT_IOC_ID, &id); 2588c2ecf20Sopenharmony_ci if (!ret) 2598c2ecf20Sopenharmony_ci goto add; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (errno != ENOTTY) 2628c2ecf20Sopenharmony_ci return -1; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* Legacy way to get event id.. All hail to old kernels! */ 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* 2678c2ecf20Sopenharmony_ci * This way does not work with group format read, so bail 2688c2ecf20Sopenharmony_ci * out in that case. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci if (perf_evlist__read_format(evlist) & PERF_FORMAT_GROUP) 2718c2ecf20Sopenharmony_ci return -1; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (!(evsel->attr.read_format & PERF_FORMAT_ID) || 2748c2ecf20Sopenharmony_ci read(fd, &read_data, sizeof(read_data)) == -1) 2758c2ecf20Sopenharmony_ci return -1; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 2788c2ecf20Sopenharmony_ci ++id_idx; 2798c2ecf20Sopenharmony_ci if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 2808c2ecf20Sopenharmony_ci ++id_idx; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci id = read_data[id_idx]; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ciadd: 2858c2ecf20Sopenharmony_ci perf_evlist__id_add(evlist, evsel, cpu, thread, id); 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ciint perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci int nr_cpus = perf_cpu_map__nr(evlist->cpus); 2928c2ecf20Sopenharmony_ci int nr_threads = perf_thread_map__nr(evlist->threads); 2938c2ecf20Sopenharmony_ci int nfds = 0; 2948c2ecf20Sopenharmony_ci struct perf_evsel *evsel; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci perf_evlist__for_each_entry(evlist, evsel) { 2978c2ecf20Sopenharmony_ci if (evsel->system_wide) 2988c2ecf20Sopenharmony_ci nfds += nr_cpus; 2998c2ecf20Sopenharmony_ci else 3008c2ecf20Sopenharmony_ci nfds += nr_cpus * nr_threads; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (fdarray__available_entries(&evlist->pollfd) < nfds && 3048c2ecf20Sopenharmony_ci fdarray__grow(&evlist->pollfd, nfds) < 0) 3058c2ecf20Sopenharmony_ci return -ENOMEM; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ciint perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, 3118c2ecf20Sopenharmony_ci void *ptr, short revent, enum fdarray_flags flags) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP, flags); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (pos >= 0) { 3168c2ecf20Sopenharmony_ci evlist->pollfd.priv[pos].ptr = ptr; 3178c2ecf20Sopenharmony_ci fcntl(fd, F_SETFL, O_NONBLOCK); 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return pos; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic void perf_evlist__munmap_filtered(struct fdarray *fda, int fd, 3248c2ecf20Sopenharmony_ci void *arg __maybe_unused) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct perf_mmap *map = fda->priv[fd].ptr; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (map) 3298c2ecf20Sopenharmony_ci perf_mmap__put(map); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ciint perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci return fdarray__filter(&evlist->pollfd, revents_and_mask, 3358c2ecf20Sopenharmony_ci perf_evlist__munmap_filtered, NULL); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ciint perf_evlist__poll(struct perf_evlist *evlist, int timeout) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci return fdarray__poll(&evlist->pollfd, timeout); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic struct perf_mmap* perf_evlist__alloc_mmap(struct perf_evlist *evlist, bool overwrite) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci int i; 3468c2ecf20Sopenharmony_ci struct perf_mmap *map; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci map = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); 3498c2ecf20Sopenharmony_ci if (!map) 3508c2ecf20Sopenharmony_ci return NULL; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci for (i = 0; i < evlist->nr_mmaps; i++) { 3538c2ecf20Sopenharmony_ci struct perf_mmap *prev = i ? &map[i - 1] : NULL; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* 3568c2ecf20Sopenharmony_ci * When the perf_mmap() call is made we grab one refcount, plus 3578c2ecf20Sopenharmony_ci * one extra to let perf_mmap__consume() get the last 3588c2ecf20Sopenharmony_ci * events after all real references (perf_mmap__get()) are 3598c2ecf20Sopenharmony_ci * dropped. 3608c2ecf20Sopenharmony_ci * 3618c2ecf20Sopenharmony_ci * Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and 3628c2ecf20Sopenharmony_ci * thus does perf_mmap__get() on it. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ci perf_mmap__init(&map[i], prev, overwrite, NULL); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return map; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic void perf_evsel__set_sid_idx(struct perf_evsel *evsel, int idx, int cpu, int thread) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct perf_sample_id *sid = SID(evsel, cpu, thread); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci sid->idx = idx; 3758c2ecf20Sopenharmony_ci sid->cpu = perf_cpu_map__cpu(evsel->cpus, cpu); 3768c2ecf20Sopenharmony_ci sid->tid = perf_thread_map__pid(evsel->threads, thread); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic struct perf_mmap* 3808c2ecf20Sopenharmony_ciperf_evlist__mmap_cb_get(struct perf_evlist *evlist, bool overwrite, int idx) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct perf_mmap *maps; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci maps = overwrite ? evlist->mmap_ovw : evlist->mmap; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (!maps) { 3878c2ecf20Sopenharmony_ci maps = perf_evlist__alloc_mmap(evlist, overwrite); 3888c2ecf20Sopenharmony_ci if (!maps) 3898c2ecf20Sopenharmony_ci return NULL; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (overwrite) 3928c2ecf20Sopenharmony_ci evlist->mmap_ovw = maps; 3938c2ecf20Sopenharmony_ci else 3948c2ecf20Sopenharmony_ci evlist->mmap = maps; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return &maps[idx]; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci#define FD(e, x, y) (*(int *) xyarray__entry(e->fd, x, y)) 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic int 4038c2ecf20Sopenharmony_ciperf_evlist__mmap_cb_mmap(struct perf_mmap *map, struct perf_mmap_param *mp, 4048c2ecf20Sopenharmony_ci int output, int cpu) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci return perf_mmap__mmap(map, mp, output, cpu); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void perf_evlist__set_mmap_first(struct perf_evlist *evlist, struct perf_mmap *map, 4108c2ecf20Sopenharmony_ci bool overwrite) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci if (overwrite) 4138c2ecf20Sopenharmony_ci evlist->mmap_ovw_first = map; 4148c2ecf20Sopenharmony_ci else 4158c2ecf20Sopenharmony_ci evlist->mmap_first = map; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic int 4198c2ecf20Sopenharmony_cimmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops, 4208c2ecf20Sopenharmony_ci int idx, struct perf_mmap_param *mp, int cpu_idx, 4218c2ecf20Sopenharmony_ci int thread, int *_output, int *_output_overwrite) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci int evlist_cpu = perf_cpu_map__cpu(evlist->cpus, cpu_idx); 4248c2ecf20Sopenharmony_ci struct perf_evsel *evsel; 4258c2ecf20Sopenharmony_ci int revent; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci perf_evlist__for_each_entry(evlist, evsel) { 4288c2ecf20Sopenharmony_ci bool overwrite = evsel->attr.write_backward; 4298c2ecf20Sopenharmony_ci struct perf_mmap *map; 4308c2ecf20Sopenharmony_ci int *output, fd, cpu; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (evsel->system_wide && thread) 4338c2ecf20Sopenharmony_ci continue; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci cpu = perf_cpu_map__idx(evsel->cpus, evlist_cpu); 4368c2ecf20Sopenharmony_ci if (cpu == -1) 4378c2ecf20Sopenharmony_ci continue; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci map = ops->get(evlist, overwrite, idx); 4408c2ecf20Sopenharmony_ci if (map == NULL) 4418c2ecf20Sopenharmony_ci return -ENOMEM; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (overwrite) { 4448c2ecf20Sopenharmony_ci mp->prot = PROT_READ; 4458c2ecf20Sopenharmony_ci output = _output_overwrite; 4468c2ecf20Sopenharmony_ci } else { 4478c2ecf20Sopenharmony_ci mp->prot = PROT_READ | PROT_WRITE; 4488c2ecf20Sopenharmony_ci output = _output; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci fd = FD(evsel, cpu, thread); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (*output == -1) { 4548c2ecf20Sopenharmony_ci *output = fd; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* 4578c2ecf20Sopenharmony_ci * The last one will be done at perf_mmap__consume(), so that we 4588c2ecf20Sopenharmony_ci * make sure we don't prevent tools from consuming every last event in 4598c2ecf20Sopenharmony_ci * the ring buffer. 4608c2ecf20Sopenharmony_ci * 4618c2ecf20Sopenharmony_ci * I.e. we can get the POLLHUP meaning that the fd doesn't exist 4628c2ecf20Sopenharmony_ci * anymore, but the last events for it are still in the ring buffer, 4638c2ecf20Sopenharmony_ci * waiting to be consumed. 4648c2ecf20Sopenharmony_ci * 4658c2ecf20Sopenharmony_ci * Tools can chose to ignore this at their own discretion, but the 4668c2ecf20Sopenharmony_ci * evlist layer can't just drop it when filtering events in 4678c2ecf20Sopenharmony_ci * perf_evlist__filter_pollfd(). 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_ci refcount_set(&map->refcnt, 2); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (ops->mmap(map, mp, *output, evlist_cpu) < 0) 4728c2ecf20Sopenharmony_ci return -1; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (!idx) 4758c2ecf20Sopenharmony_ci perf_evlist__set_mmap_first(evlist, map, overwrite); 4768c2ecf20Sopenharmony_ci } else { 4778c2ecf20Sopenharmony_ci if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) 4788c2ecf20Sopenharmony_ci return -1; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci perf_mmap__get(map); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci revent = !overwrite ? POLLIN : 0; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (!evsel->system_wide && 4868c2ecf20Sopenharmony_ci perf_evlist__add_pollfd(evlist, fd, map, revent, fdarray_flag__default) < 0) { 4878c2ecf20Sopenharmony_ci perf_mmap__put(map); 4888c2ecf20Sopenharmony_ci return -1; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (evsel->attr.read_format & PERF_FORMAT_ID) { 4928c2ecf20Sopenharmony_ci if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread, 4938c2ecf20Sopenharmony_ci fd) < 0) 4948c2ecf20Sopenharmony_ci return -1; 4958c2ecf20Sopenharmony_ci perf_evsel__set_sid_idx(evsel, idx, cpu, thread); 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic int 5038c2ecf20Sopenharmony_cimmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops, 5048c2ecf20Sopenharmony_ci struct perf_mmap_param *mp) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci int thread; 5078c2ecf20Sopenharmony_ci int nr_threads = perf_thread_map__nr(evlist->threads); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci for (thread = 0; thread < nr_threads; thread++) { 5108c2ecf20Sopenharmony_ci int output = -1; 5118c2ecf20Sopenharmony_ci int output_overwrite = -1; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (ops->idx) 5148c2ecf20Sopenharmony_ci ops->idx(evlist, mp, thread, false); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (mmap_per_evsel(evlist, ops, thread, mp, 0, thread, 5178c2ecf20Sopenharmony_ci &output, &output_overwrite)) 5188c2ecf20Sopenharmony_ci goto out_unmap; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ciout_unmap: 5248c2ecf20Sopenharmony_ci perf_evlist__munmap(evlist); 5258c2ecf20Sopenharmony_ci return -1; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic int 5298c2ecf20Sopenharmony_cimmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops, 5308c2ecf20Sopenharmony_ci struct perf_mmap_param *mp) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci int nr_threads = perf_thread_map__nr(evlist->threads); 5338c2ecf20Sopenharmony_ci int nr_cpus = perf_cpu_map__nr(evlist->cpus); 5348c2ecf20Sopenharmony_ci int cpu, thread; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci for (cpu = 0; cpu < nr_cpus; cpu++) { 5378c2ecf20Sopenharmony_ci int output = -1; 5388c2ecf20Sopenharmony_ci int output_overwrite = -1; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (ops->idx) 5418c2ecf20Sopenharmony_ci ops->idx(evlist, mp, cpu, true); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci for (thread = 0; thread < nr_threads; thread++) { 5448c2ecf20Sopenharmony_ci if (mmap_per_evsel(evlist, ops, cpu, mp, cpu, 5458c2ecf20Sopenharmony_ci thread, &output, &output_overwrite)) 5468c2ecf20Sopenharmony_ci goto out_unmap; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ciout_unmap: 5538c2ecf20Sopenharmony_ci perf_evlist__munmap(evlist); 5548c2ecf20Sopenharmony_ci return -1; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic int perf_evlist__nr_mmaps(struct perf_evlist *evlist) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci int nr_mmaps; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci nr_mmaps = perf_cpu_map__nr(evlist->cpus); 5628c2ecf20Sopenharmony_ci if (perf_cpu_map__empty(evlist->cpus)) 5638c2ecf20Sopenharmony_ci nr_mmaps = perf_thread_map__nr(evlist->threads); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return nr_mmaps; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ciint perf_evlist__mmap_ops(struct perf_evlist *evlist, 5698c2ecf20Sopenharmony_ci struct perf_evlist_mmap_ops *ops, 5708c2ecf20Sopenharmony_ci struct perf_mmap_param *mp) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci struct perf_evsel *evsel; 5738c2ecf20Sopenharmony_ci const struct perf_cpu_map *cpus = evlist->cpus; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (!ops || !ops->get || !ops->mmap) 5768c2ecf20Sopenharmony_ci return -EINVAL; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci mp->mask = evlist->mmap_len - page_size - 1; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci evlist->nr_mmaps = perf_evlist__nr_mmaps(evlist); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci perf_evlist__for_each_entry(evlist, evsel) { 5838c2ecf20Sopenharmony_ci if ((evsel->attr.read_format & PERF_FORMAT_ID) && 5848c2ecf20Sopenharmony_ci evsel->sample_id == NULL && 5858c2ecf20Sopenharmony_ci perf_evsel__alloc_id(evsel, evsel->fd->max_x, evsel->fd->max_y) < 0) 5868c2ecf20Sopenharmony_ci return -ENOMEM; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0) 5908c2ecf20Sopenharmony_ci return -ENOMEM; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (perf_cpu_map__empty(cpus)) 5938c2ecf20Sopenharmony_ci return mmap_per_thread(evlist, ops, mp); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci return mmap_per_cpu(evlist, ops, mp); 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ciint perf_evlist__mmap(struct perf_evlist *evlist, int pages) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct perf_mmap_param mp; 6018c2ecf20Sopenharmony_ci struct perf_evlist_mmap_ops ops = { 6028c2ecf20Sopenharmony_ci .get = perf_evlist__mmap_cb_get, 6038c2ecf20Sopenharmony_ci .mmap = perf_evlist__mmap_cb_mmap, 6048c2ecf20Sopenharmony_ci }; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci evlist->mmap_len = (pages + 1) * page_size; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return perf_evlist__mmap_ops(evlist, &ops, &mp); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_civoid perf_evlist__munmap(struct perf_evlist *evlist) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci int i; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (evlist->mmap) { 6168c2ecf20Sopenharmony_ci for (i = 0; i < evlist->nr_mmaps; i++) 6178c2ecf20Sopenharmony_ci perf_mmap__munmap(&evlist->mmap[i]); 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (evlist->mmap_ovw) { 6218c2ecf20Sopenharmony_ci for (i = 0; i < evlist->nr_mmaps; i++) 6228c2ecf20Sopenharmony_ci perf_mmap__munmap(&evlist->mmap_ovw[i]); 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci zfree(&evlist->mmap); 6268c2ecf20Sopenharmony_ci zfree(&evlist->mmap_ovw); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistruct perf_mmap* 6308c2ecf20Sopenharmony_ciperf_evlist__next_mmap(struct perf_evlist *evlist, struct perf_mmap *map, 6318c2ecf20Sopenharmony_ci bool overwrite) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci if (map) 6348c2ecf20Sopenharmony_ci return map->next; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci return overwrite ? evlist->mmap_ovw_first : evlist->mmap_first; 6378c2ecf20Sopenharmony_ci} 638