]> Git Repo - linux.git/blob - tools/perf/lib/evlist.c
net: dsa: sja1105: Implement state machine for TAS with PTP clock source
[linux.git] / tools / perf / lib / evlist.c
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
22 void 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
32 static 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
51 static 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
59 void 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
67 void 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
74 struct 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
84 struct perf_evsel *
85 perf_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
104 void perf_evlist__delete(struct perf_evlist *evlist)
105 {
106         free(evlist);
107 }
108
109 void 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
133 int 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
146 out_err:
147         perf_evlist__close(evlist);
148         return err;
149 }
150
151 void 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
159 void 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
167 void 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
175 u64 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
184 static 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
197 void 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
205 int 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
241 add:
242         perf_evlist__id_add(evlist, evsel, cpu, thread, id);
243         return 0;
244 }
245
246 int 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
267 int 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
280 int perf_evlist__poll(struct perf_evlist *evlist, int timeout)
281 {
282         return fdarray__poll(&evlist->pollfd, timeout);
283 }
This page took 0.047169 seconds and 4 git commands to generate.