Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.4-rc3 283 lines 6.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2#include <perf/evlist.h> 3#include <perf/evsel.h> 4#include <linux/bitops.h> 5#include <linux/list.h> 6#include <linux/hash.h> 7#include <sys/ioctl.h> 8#include <internal/evlist.h> 9#include <internal/evsel.h> 10#include <internal/xyarray.h> 11#include <linux/zalloc.h> 12#include <stdlib.h> 13#include <errno.h> 14#include <unistd.h> 15#include <fcntl.h> 16#include <signal.h> 17#include <poll.h> 18#include <perf/cpumap.h> 19#include <perf/threadmap.h> 20#include <api/fd/array.h> 21 22void perf_evlist__init(struct perf_evlist *evlist) 23{ 24 int i; 25 26 for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) 27 INIT_HLIST_HEAD(&evlist->heads[i]); 28 INIT_LIST_HEAD(&evlist->entries); 29 evlist->nr_entries = 0; 30} 31 32static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, 33 struct perf_evsel *evsel) 34{ 35 /* 36 * We already have cpus for evsel (via PMU sysfs) so 37 * keep it, if there's no target cpu list defined. 38 */ 39 if (!evsel->own_cpus || evlist->has_user_cpus) { 40 perf_cpu_map__put(evsel->cpus); 41 evsel->cpus = perf_cpu_map__get(evlist->cpus); 42 } else if (evsel->cpus != evsel->own_cpus) { 43 perf_cpu_map__put(evsel->cpus); 44 evsel->cpus = perf_cpu_map__get(evsel->own_cpus); 45 } 46 47 perf_thread_map__put(evsel->threads); 48 evsel->threads = perf_thread_map__get(evlist->threads); 49} 50 51static void perf_evlist__propagate_maps(struct perf_evlist *evlist) 52{ 53 struct perf_evsel *evsel; 54 55 perf_evlist__for_each_evsel(evlist, evsel) 56 __perf_evlist__propagate_maps(evlist, evsel); 57} 58 59void perf_evlist__add(struct perf_evlist *evlist, 60 struct perf_evsel *evsel) 61{ 62 list_add_tail(&evsel->node, &evlist->entries); 63 evlist->nr_entries += 1; 64 __perf_evlist__propagate_maps(evlist, evsel); 65} 66 67void perf_evlist__remove(struct perf_evlist *evlist, 68 struct perf_evsel *evsel) 69{ 70 list_del_init(&evsel->node); 71 evlist->nr_entries -= 1; 72} 73 74struct perf_evlist *perf_evlist__new(void) 75{ 76 struct perf_evlist *evlist = zalloc(sizeof(*evlist)); 77 78 if (evlist != NULL) 79 perf_evlist__init(evlist); 80 81 return evlist; 82} 83 84struct perf_evsel * 85perf_evlist__next(struct perf_evlist *evlist, struct perf_evsel *prev) 86{ 87 struct perf_evsel *next; 88 89 if (!prev) { 90 next = list_first_entry(&evlist->entries, 91 struct perf_evsel, 92 node); 93 } else { 94 next = list_next_entry(prev, node); 95 } 96 97 /* Empty list is noticed here so don't need checking on entry. */ 98 if (&next->node == &evlist->entries) 99 return NULL; 100 101 return next; 102} 103 104void perf_evlist__delete(struct perf_evlist *evlist) 105{ 106 free(evlist); 107} 108 109void perf_evlist__set_maps(struct perf_evlist *evlist, 110 struct perf_cpu_map *cpus, 111 struct perf_thread_map *threads) 112{ 113 /* 114 * Allow for the possibility that one or another of the maps isn't being 115 * changed i.e. don't put it. Note we are assuming the maps that are 116 * being applied are brand new and evlist is taking ownership of the 117 * original reference count of 1. If that is not the case it is up to 118 * the caller to increase the reference count. 119 */ 120 if (cpus != evlist->cpus) { 121 perf_cpu_map__put(evlist->cpus); 122 evlist->cpus = perf_cpu_map__get(cpus); 123 } 124 125 if (threads != evlist->threads) { 126 perf_thread_map__put(evlist->threads); 127 evlist->threads = perf_thread_map__get(threads); 128 } 129 130 perf_evlist__propagate_maps(evlist); 131} 132 133int perf_evlist__open(struct perf_evlist *evlist) 134{ 135 struct perf_evsel *evsel; 136 int err; 137 138 perf_evlist__for_each_entry(evlist, evsel) { 139 err = perf_evsel__open(evsel, evsel->cpus, evsel->threads); 140 if (err < 0) 141 goto out_err; 142 } 143 144 return 0; 145 146out_err: 147 perf_evlist__close(evlist); 148 return err; 149} 150 151void perf_evlist__close(struct perf_evlist *evlist) 152{ 153 struct perf_evsel *evsel; 154 155 perf_evlist__for_each_entry_reverse(evlist, evsel) 156 perf_evsel__close(evsel); 157} 158 159void perf_evlist__enable(struct perf_evlist *evlist) 160{ 161 struct perf_evsel *evsel; 162 163 perf_evlist__for_each_entry(evlist, evsel) 164 perf_evsel__enable(evsel); 165} 166 167void perf_evlist__disable(struct perf_evlist *evlist) 168{ 169 struct perf_evsel *evsel; 170 171 perf_evlist__for_each_entry(evlist, evsel) 172 perf_evsel__disable(evsel); 173} 174 175u64 perf_evlist__read_format(struct perf_evlist *evlist) 176{ 177 struct perf_evsel *first = perf_evlist__first(evlist); 178 179 return first->attr.read_format; 180} 181 182#define SID(e, x, y) xyarray__entry(e->sample_id, x, y) 183 184static void perf_evlist__id_hash(struct perf_evlist *evlist, 185 struct perf_evsel *evsel, 186 int cpu, int thread, u64 id) 187{ 188 int hash; 189 struct perf_sample_id *sid = SID(evsel, cpu, thread); 190 191 sid->id = id; 192 sid->evsel = evsel; 193 hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS); 194 hlist_add_head(&sid->node, &evlist->heads[hash]); 195} 196 197void perf_evlist__id_add(struct perf_evlist *evlist, 198 struct perf_evsel *evsel, 199 int cpu, int thread, u64 id) 200{ 201 perf_evlist__id_hash(evlist, evsel, cpu, thread, id); 202 evsel->id[evsel->ids++] = id; 203} 204 205int perf_evlist__id_add_fd(struct perf_evlist *evlist, 206 struct perf_evsel *evsel, 207 int cpu, int thread, int fd) 208{ 209 u64 read_data[4] = { 0, }; 210 int id_idx = 1; /* The first entry is the counter value */ 211 u64 id; 212 int ret; 213 214 ret = ioctl(fd, PERF_EVENT_IOC_ID, &id); 215 if (!ret) 216 goto add; 217 218 if (errno != ENOTTY) 219 return -1; 220 221 /* Legacy way to get event id.. All hail to old kernels! */ 222 223 /* 224 * This way does not work with group format read, so bail 225 * out in that case. 226 */ 227 if (perf_evlist__read_format(evlist) & PERF_FORMAT_GROUP) 228 return -1; 229 230 if (!(evsel->attr.read_format & PERF_FORMAT_ID) || 231 read(fd, &read_data, sizeof(read_data)) == -1) 232 return -1; 233 234 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 235 ++id_idx; 236 if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 237 ++id_idx; 238 239 id = read_data[id_idx]; 240 241add: 242 perf_evlist__id_add(evlist, evsel, cpu, thread, id); 243 return 0; 244} 245 246int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 247{ 248 int nr_cpus = perf_cpu_map__nr(evlist->cpus); 249 int nr_threads = perf_thread_map__nr(evlist->threads); 250 int nfds = 0; 251 struct perf_evsel *evsel; 252 253 perf_evlist__for_each_entry(evlist, evsel) { 254 if (evsel->system_wide) 255 nfds += nr_cpus; 256 else 257 nfds += nr_cpus * nr_threads; 258 } 259 260 if (fdarray__available_entries(&evlist->pollfd) < nfds && 261 fdarray__grow(&evlist->pollfd, nfds) < 0) 262 return -ENOMEM; 263 264 return 0; 265} 266 267int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, 268 void *ptr, short revent) 269{ 270 int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP); 271 272 if (pos >= 0) { 273 evlist->pollfd.priv[pos].ptr = ptr; 274 fcntl(fd, F_SETFL, O_NONBLOCK); 275 } 276 277 return pos; 278} 279 280int perf_evlist__poll(struct perf_evlist *evlist, int timeout) 281{ 282 return fdarray__poll(&evlist->pollfd, timeout); 283}