1 // SPDX-License-Identifier: GPL-2.0
4 #include <sys/syscall.h>
5 #include <perf/evsel.h>
6 #include <perf/cpumap.h>
7 #include <perf/threadmap.h>
8 #include <linux/hash.h>
9 #include <linux/list.h>
10 #include <internal/evsel.h>
11 #include <linux/zalloc.h>
13 #include <internal/xyarray.h>
14 #include <internal/cpumap.h>
15 #include <internal/mmap.h>
16 #include <internal/threadmap.h>
17 #include <internal/lib.h>
18 #include <linux/string.h>
19 #include <sys/ioctl.h>
23 void perf_evsel__init(struct perf_evsel
*evsel
, struct perf_event_attr
*attr
,
26 INIT_LIST_HEAD(&evsel
->node
);
27 INIT_LIST_HEAD(&evsel
->per_stream_periods
);
30 evsel
->leader
= evsel
;
33 struct perf_evsel
*perf_evsel__new(struct perf_event_attr
*attr
)
35 struct perf_evsel
*evsel
= zalloc(sizeof(*evsel
));
38 perf_evsel__init(evsel
, attr
, 0);
43 void perf_evsel__delete(struct perf_evsel
*evsel
)
48 #define FD(_evsel, _cpu_map_idx, _thread) \
49 ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
50 #define MMAP(_evsel, _cpu_map_idx, _thread) \
51 (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
54 int perf_evsel__alloc_fd(struct perf_evsel
*evsel
, int ncpus
, int nthreads
)
56 evsel
->fd
= xyarray__new(ncpus
, nthreads
, sizeof(int));
61 for (idx
= 0; idx
< ncpus
; idx
++) {
62 for (thread
= 0; thread
< nthreads
; thread
++) {
63 int *fd
= FD(evsel
, idx
, thread
);
71 return evsel
->fd
!= NULL
? 0 : -ENOMEM
;
74 static int perf_evsel__alloc_mmap(struct perf_evsel
*evsel
, int ncpus
, int nthreads
)
76 evsel
->mmap
= xyarray__new(ncpus
, nthreads
, sizeof(struct perf_mmap
));
78 return evsel
->mmap
!= NULL
? 0 : -ENOMEM
;
82 sys_perf_event_open(struct perf_event_attr
*attr
,
83 pid_t pid
, struct perf_cpu cpu
, int group_fd
,
86 return syscall(__NR_perf_event_open
, attr
, pid
, cpu
.cpu
, group_fd
, flags
);
89 static int get_group_fd(struct perf_evsel
*evsel
, int cpu_map_idx
, int thread
, int *group_fd
)
91 struct perf_evsel
*leader
= evsel
->leader
;
94 if (evsel
== leader
) {
100 * Leader must be already processed/open,
106 fd
= FD(leader
, cpu_map_idx
, thread
);
107 if (fd
== NULL
|| *fd
== -1)
115 int perf_evsel__open(struct perf_evsel
*evsel
, struct perf_cpu_map
*cpus
,
116 struct perf_thread_map
*threads
)
119 int idx
, thread
, err
= 0;
122 static struct perf_cpu_map
*empty_cpu_map
;
124 if (empty_cpu_map
== NULL
) {
125 empty_cpu_map
= perf_cpu_map__new_any_cpu();
126 if (empty_cpu_map
== NULL
)
130 cpus
= empty_cpu_map
;
133 if (threads
== NULL
) {
134 static struct perf_thread_map
*empty_thread_map
;
136 if (empty_thread_map
== NULL
) {
137 empty_thread_map
= perf_thread_map__new_dummy();
138 if (empty_thread_map
== NULL
)
142 threads
= empty_thread_map
;
145 if (evsel
->fd
== NULL
&&
146 perf_evsel__alloc_fd(evsel
, perf_cpu_map__nr(cpus
), threads
->nr
) < 0)
149 perf_cpu_map__for_each_cpu(cpu
, idx
, cpus
) {
150 for (thread
= 0; thread
< threads
->nr
; thread
++) {
151 int fd
, group_fd
, *evsel_fd
;
153 evsel_fd
= FD(evsel
, idx
, thread
);
154 if (evsel_fd
== NULL
) {
159 err
= get_group_fd(evsel
, idx
, thread
, &group_fd
);
163 fd
= sys_perf_event_open(&evsel
->attr
,
164 threads
->map
[thread
].pid
,
177 perf_evsel__close(evsel
);
182 static void perf_evsel__close_fd_cpu(struct perf_evsel
*evsel
, int cpu_map_idx
)
186 for (thread
= 0; thread
< xyarray__max_y(evsel
->fd
); ++thread
) {
187 int *fd
= FD(evsel
, cpu_map_idx
, thread
);
189 if (fd
&& *fd
>= 0) {
196 void perf_evsel__close_fd(struct perf_evsel
*evsel
)
198 for (int idx
= 0; idx
< xyarray__max_x(evsel
->fd
); idx
++)
199 perf_evsel__close_fd_cpu(evsel
, idx
);
202 void perf_evsel__free_fd(struct perf_evsel
*evsel
)
204 xyarray__delete(evsel
->fd
);
208 void perf_evsel__close(struct perf_evsel
*evsel
)
210 if (evsel
->fd
== NULL
)
213 perf_evsel__close_fd(evsel
);
214 perf_evsel__free_fd(evsel
);
217 void perf_evsel__close_cpu(struct perf_evsel
*evsel
, int cpu_map_idx
)
219 if (evsel
->fd
== NULL
)
222 perf_evsel__close_fd_cpu(evsel
, cpu_map_idx
);
225 void perf_evsel__munmap(struct perf_evsel
*evsel
)
229 if (evsel
->fd
== NULL
|| evsel
->mmap
== NULL
)
232 for (idx
= 0; idx
< xyarray__max_x(evsel
->fd
); idx
++) {
233 for (thread
= 0; thread
< xyarray__max_y(evsel
->fd
); thread
++) {
234 int *fd
= FD(evsel
, idx
, thread
);
236 if (fd
== NULL
|| *fd
< 0)
239 perf_mmap__munmap(MMAP(evsel
, idx
, thread
));
243 xyarray__delete(evsel
->mmap
);
247 int perf_evsel__mmap(struct perf_evsel
*evsel
, int pages
)
249 int ret
, idx
, thread
;
250 struct perf_mmap_param mp
= {
251 .prot
= PROT_READ
| PROT_WRITE
,
252 .mask
= (pages
* page_size
) - 1,
255 if (evsel
->fd
== NULL
|| evsel
->mmap
)
258 if (perf_evsel__alloc_mmap(evsel
, xyarray__max_x(evsel
->fd
), xyarray__max_y(evsel
->fd
)) < 0)
261 for (idx
= 0; idx
< xyarray__max_x(evsel
->fd
); idx
++) {
262 for (thread
= 0; thread
< xyarray__max_y(evsel
->fd
); thread
++) {
263 int *fd
= FD(evsel
, idx
, thread
);
264 struct perf_mmap
*map
;
265 struct perf_cpu cpu
= perf_cpu_map__cpu(evsel
->cpus
, idx
);
267 if (fd
== NULL
|| *fd
< 0)
270 map
= MMAP(evsel
, idx
, thread
);
271 perf_mmap__init(map
, NULL
, false, NULL
);
273 ret
= perf_mmap__mmap(map
, &mp
, *fd
, cpu
);
275 perf_evsel__munmap(evsel
);
284 void *perf_evsel__mmap_base(struct perf_evsel
*evsel
, int cpu_map_idx
, int thread
)
286 int *fd
= FD(evsel
, cpu_map_idx
, thread
);
288 if (fd
== NULL
|| *fd
< 0 || MMAP(evsel
, cpu_map_idx
, thread
) == NULL
)
291 return MMAP(evsel
, cpu_map_idx
, thread
)->base
;
294 int perf_evsel__read_size(struct perf_evsel
*evsel
)
296 u64 read_format
= evsel
->attr
.read_format
;
297 int entry
= sizeof(u64
); /* value */
301 if (read_format
& PERF_FORMAT_TOTAL_TIME_ENABLED
)
304 if (read_format
& PERF_FORMAT_TOTAL_TIME_RUNNING
)
307 if (read_format
& PERF_FORMAT_ID
)
308 entry
+= sizeof(u64
);
310 if (read_format
& PERF_FORMAT_LOST
)
311 entry
+= sizeof(u64
);
313 if (read_format
& PERF_FORMAT_GROUP
) {
314 nr
= evsel
->nr_members
;
322 /* This only reads values for the leader */
323 static int perf_evsel__read_group(struct perf_evsel
*evsel
, int cpu_map_idx
,
324 int thread
, struct perf_counts_values
*count
)
326 size_t size
= perf_evsel__read_size(evsel
);
327 int *fd
= FD(evsel
, cpu_map_idx
, thread
);
328 u64 read_format
= evsel
->attr
.read_format
;
332 if (fd
== NULL
|| *fd
< 0)
335 data
= calloc(1, size
);
339 if (readn(*fd
, data
, size
) <= 0) {
345 * This reads only the leader event intentionally since we don't have
346 * perf counts values for sibling events.
348 if (read_format
& PERF_FORMAT_TOTAL_TIME_ENABLED
)
349 count
->ena
= data
[idx
++];
350 if (read_format
& PERF_FORMAT_TOTAL_TIME_RUNNING
)
351 count
->run
= data
[idx
++];
353 /* value is always available */
354 count
->val
= data
[idx
++];
355 if (read_format
& PERF_FORMAT_ID
)
356 count
->id
= data
[idx
++];
357 if (read_format
& PERF_FORMAT_LOST
)
358 count
->lost
= data
[idx
++];
365 * The perf read format is very flexible. It needs to set the proper
366 * values according to the read format.
368 static void perf_evsel__adjust_values(struct perf_evsel
*evsel
, u64
*buf
,
369 struct perf_counts_values
*count
)
371 u64 read_format
= evsel
->attr
.read_format
;
374 count
->val
= buf
[n
++];
376 if (read_format
& PERF_FORMAT_TOTAL_TIME_ENABLED
)
377 count
->ena
= buf
[n
++];
379 if (read_format
& PERF_FORMAT_TOTAL_TIME_RUNNING
)
380 count
->run
= buf
[n
++];
382 if (read_format
& PERF_FORMAT_ID
)
383 count
->id
= buf
[n
++];
385 if (read_format
& PERF_FORMAT_LOST
)
386 count
->lost
= buf
[n
++];
389 int perf_evsel__read(struct perf_evsel
*evsel
, int cpu_map_idx
, int thread
,
390 struct perf_counts_values
*count
)
392 size_t size
= perf_evsel__read_size(evsel
);
393 int *fd
= FD(evsel
, cpu_map_idx
, thread
);
394 u64 read_format
= evsel
->attr
.read_format
;
395 struct perf_counts_values buf
;
397 memset(count
, 0, sizeof(*count
));
399 if (fd
== NULL
|| *fd
< 0)
402 if (read_format
& PERF_FORMAT_GROUP
)
403 return perf_evsel__read_group(evsel
, cpu_map_idx
, thread
, count
);
405 if (MMAP(evsel
, cpu_map_idx
, thread
) &&
406 !(read_format
& (PERF_FORMAT_ID
| PERF_FORMAT_LOST
)) &&
407 !perf_mmap__read_self(MMAP(evsel
, cpu_map_idx
, thread
), count
))
410 if (readn(*fd
, buf
.values
, size
) <= 0)
413 perf_evsel__adjust_values(evsel
, buf
.values
, count
);
417 static int perf_evsel__ioctl(struct perf_evsel
*evsel
, int ioc
, void *arg
,
418 int cpu_map_idx
, int thread
)
420 int *fd
= FD(evsel
, cpu_map_idx
, thread
);
422 if (fd
== NULL
|| *fd
< 0)
425 return ioctl(*fd
, ioc
, arg
);
428 static int perf_evsel__run_ioctl(struct perf_evsel
*evsel
,
434 for (thread
= 0; thread
< xyarray__max_y(evsel
->fd
); thread
++) {
435 int err
= perf_evsel__ioctl(evsel
, ioc
, arg
, cpu_map_idx
, thread
);
444 int perf_evsel__enable_cpu(struct perf_evsel
*evsel
, int cpu_map_idx
)
446 return perf_evsel__run_ioctl(evsel
, PERF_EVENT_IOC_ENABLE
, NULL
, cpu_map_idx
);
449 int perf_evsel__enable_thread(struct perf_evsel
*evsel
, int thread
)
451 struct perf_cpu cpu __maybe_unused
;
455 perf_cpu_map__for_each_cpu(cpu
, idx
, evsel
->cpus
) {
456 err
= perf_evsel__ioctl(evsel
, PERF_EVENT_IOC_ENABLE
, NULL
, idx
, thread
);
464 int perf_evsel__enable(struct perf_evsel
*evsel
)
469 for (i
= 0; i
< xyarray__max_x(evsel
->fd
) && !err
; i
++)
470 err
= perf_evsel__run_ioctl(evsel
, PERF_EVENT_IOC_ENABLE
, NULL
, i
);
474 int perf_evsel__disable_cpu(struct perf_evsel
*evsel
, int cpu_map_idx
)
476 return perf_evsel__run_ioctl(evsel
, PERF_EVENT_IOC_DISABLE
, NULL
, cpu_map_idx
);
479 int perf_evsel__disable(struct perf_evsel
*evsel
)
484 for (i
= 0; i
< xyarray__max_x(evsel
->fd
) && !err
; i
++)
485 err
= perf_evsel__run_ioctl(evsel
, PERF_EVENT_IOC_DISABLE
, NULL
, i
);
489 int perf_evsel__apply_filter(struct perf_evsel
*evsel
, const char *filter
)
493 for (i
= 0; i
< perf_cpu_map__nr(evsel
->cpus
) && !err
; i
++)
494 err
= perf_evsel__run_ioctl(evsel
,
495 PERF_EVENT_IOC_SET_FILTER
,
500 struct perf_cpu_map
*perf_evsel__cpus(struct perf_evsel
*evsel
)
505 struct perf_thread_map
*perf_evsel__threads(struct perf_evsel
*evsel
)
507 return evsel
->threads
;
510 struct perf_event_attr
*perf_evsel__attr(struct perf_evsel
*evsel
)
515 int perf_evsel__alloc_id(struct perf_evsel
*evsel
, int ncpus
, int nthreads
)
517 if (ncpus
== 0 || nthreads
== 0)
520 evsel
->sample_id
= xyarray__new(ncpus
, nthreads
, sizeof(struct perf_sample_id
));
521 if (evsel
->sample_id
== NULL
)
524 evsel
->id
= zalloc(ncpus
* nthreads
* sizeof(u64
));
525 if (evsel
->id
== NULL
) {
526 xyarray__delete(evsel
->sample_id
);
527 evsel
->sample_id
= NULL
;
534 void perf_evsel__free_id(struct perf_evsel
*evsel
)
536 struct perf_sample_id_period
*pos
, *n
;
538 xyarray__delete(evsel
->sample_id
);
539 evsel
->sample_id
= NULL
;
543 perf_evsel_for_each_per_thread_period_safe(evsel
, n
, pos
) {
544 list_del_init(&pos
->node
);
549 bool perf_evsel__attr_has_per_thread_sample_period(struct perf_evsel
*evsel
)
551 return (evsel
->attr
.sample_type
& PERF_SAMPLE_READ
) &&
552 (evsel
->attr
.sample_type
& PERF_SAMPLE_TID
) &&
556 u64
*perf_sample_id__get_period_storage(struct perf_sample_id
*sid
, u32 tid
, bool per_thread
)
558 struct hlist_head
*head
;
559 struct perf_sample_id_period
*res
;
565 hash
= hash_32(tid
, PERF_SAMPLE_ID__HLIST_BITS
);
566 head
= &sid
->periods
[hash
];
568 hlist_for_each_entry(res
, head
, hnode
)
572 if (sid
->evsel
== NULL
)
575 res
= zalloc(sizeof(struct perf_sample_id_period
));
579 INIT_LIST_HEAD(&res
->node
);
582 list_add_tail(&res
->node
, &sid
->evsel
->per_stream_periods
);
583 hlist_add_head(&res
->hnode
, &sid
->periods
[hash
]);
588 void perf_counts_values__scale(struct perf_counts_values
*count
,
589 bool scale
, __s8
*pscaled
)
594 if (count
->run
== 0) {
597 } else if (count
->run
< count
->ena
) {
599 count
->val
= (u64
)((double)count
->val
* count
->ena
/ count
->run
);