6 #include "thread_map.h"
11 #include <linux/bitops.h>
12 #include <linux/hash.h>
14 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
15 #define SID(e, x, y) xyarray__entry(e->id, x, y)
17 void perf_evsel__init(struct perf_evsel
*evsel
,
18 struct perf_event_attr
*attr
, int idx
)
22 INIT_LIST_HEAD(&evsel
->node
);
25 struct perf_evsel
*perf_evsel__new(struct perf_event_attr
*attr
, int idx
)
27 struct perf_evsel
*evsel
= zalloc(sizeof(*evsel
));
30 perf_evsel__init(evsel
, attr
, idx
);
35 int perf_evsel__alloc_fd(struct perf_evsel
*evsel
, int ncpus
, int nthreads
)
37 evsel
->fd
= xyarray__new(ncpus
, nthreads
, sizeof(int));
38 return evsel
->fd
!= NULL
? 0 : -ENOMEM
;
41 int perf_evsel__alloc_id(struct perf_evsel
*evsel
, int ncpus
, int nthreads
)
43 evsel
->id
= xyarray__new(ncpus
, nthreads
, sizeof(struct perf_sample_id
));
44 return evsel
->id
!= NULL
? 0 : -ENOMEM
;
47 int perf_evsel__alloc_counts(struct perf_evsel
*evsel
, int ncpus
)
49 evsel
->counts
= zalloc((sizeof(*evsel
->counts
) +
50 (ncpus
* sizeof(struct perf_counts_values
))));
51 return evsel
->counts
!= NULL
? 0 : -ENOMEM
;
54 void perf_evsel__free_fd(struct perf_evsel
*evsel
)
56 xyarray__delete(evsel
->fd
);
60 void perf_evsel__free_id(struct perf_evsel
*evsel
)
62 xyarray__delete(evsel
->id
);
66 void perf_evsel__close_fd(struct perf_evsel
*evsel
, int ncpus
, int nthreads
)
70 for (cpu
= 0; cpu
< ncpus
; cpu
++)
71 for (thread
= 0; thread
< nthreads
; ++thread
) {
72 close(FD(evsel
, cpu
, thread
));
73 FD(evsel
, cpu
, thread
) = -1;
77 void perf_evlist__munmap(struct perf_evlist
*evlist
, int ncpus
)
81 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
82 if (evlist
->mmap
[cpu
].base
!= NULL
) {
83 munmap(evlist
->mmap
[cpu
].base
, evlist
->mmap_len
);
84 evlist
->mmap
[cpu
].base
= NULL
;
89 int perf_evlist__alloc_mmap(struct perf_evlist
*evlist
, int ncpus
)
91 evlist
->mmap
= zalloc(ncpus
* sizeof(struct perf_mmap
));
92 return evlist
->mmap
!= NULL
? 0 : -ENOMEM
;
95 void perf_evsel__exit(struct perf_evsel
*evsel
)
97 assert(list_empty(&evsel
->node
));
98 xyarray__delete(evsel
->fd
);
99 xyarray__delete(evsel
->id
);
102 void perf_evsel__delete(struct perf_evsel
*evsel
)
104 perf_evsel__exit(evsel
);
108 int __perf_evsel__read_on_cpu(struct perf_evsel
*evsel
,
109 int cpu
, int thread
, bool scale
)
111 struct perf_counts_values count
;
112 size_t nv
= scale
? 3 : 1;
114 if (FD(evsel
, cpu
, thread
) < 0)
117 if (evsel
->counts
== NULL
&& perf_evsel__alloc_counts(evsel
, cpu
+ 1) < 0)
120 if (readn(FD(evsel
, cpu
, thread
), &count
, nv
* sizeof(u64
)) < 0)
126 else if (count
.run
< count
.ena
)
127 count
.val
= (u64
)((double)count
.val
* count
.ena
/ count
.run
+ 0.5);
129 count
.ena
= count
.run
= 0;
131 evsel
->counts
->cpu
[cpu
] = count
;
135 int __perf_evsel__read(struct perf_evsel
*evsel
,
136 int ncpus
, int nthreads
, bool scale
)
138 size_t nv
= scale
? 3 : 1;
140 struct perf_counts_values
*aggr
= &evsel
->counts
->aggr
, count
;
144 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
145 for (thread
= 0; thread
< nthreads
; thread
++) {
146 if (FD(evsel
, cpu
, thread
) < 0)
149 if (readn(FD(evsel
, cpu
, thread
),
150 &count
, nv
* sizeof(u64
)) < 0)
153 aggr
->val
+= count
.val
;
155 aggr
->ena
+= count
.ena
;
156 aggr
->run
+= count
.run
;
161 evsel
->counts
->scaled
= 0;
163 if (aggr
->run
== 0) {
164 evsel
->counts
->scaled
= -1;
169 if (aggr
->run
< aggr
->ena
) {
170 evsel
->counts
->scaled
= 1;
171 aggr
->val
= (u64
)((double)aggr
->val
* aggr
->ena
/ aggr
->run
+ 0.5);
174 aggr
->ena
= aggr
->run
= 0;
179 static int __perf_evsel__open(struct perf_evsel
*evsel
, struct cpu_map
*cpus
,
180 struct thread_map
*threads
, bool group
, bool inherit
)
184 if (evsel
->fd
== NULL
&&
185 perf_evsel__alloc_fd(evsel
, cpus
->nr
, threads
->nr
) < 0)
188 for (cpu
= 0; cpu
< cpus
->nr
; cpu
++) {
191 evsel
->attr
.inherit
= (cpus
->map
[cpu
] < 0) && inherit
;
193 for (thread
= 0; thread
< threads
->nr
; thread
++) {
194 FD(evsel
, cpu
, thread
) = sys_perf_event_open(&evsel
->attr
,
195 threads
->map
[thread
],
198 if (FD(evsel
, cpu
, thread
) < 0)
201 if (group
&& group_fd
== -1)
202 group_fd
= FD(evsel
, cpu
, thread
);
210 while (--thread
>= 0) {
211 close(FD(evsel
, cpu
, thread
));
212 FD(evsel
, cpu
, thread
) = -1;
214 thread
= threads
->nr
;
215 } while (--cpu
>= 0);
228 struct thread_map map
;
230 } empty_thread_map
= {
235 int perf_evsel__open(struct perf_evsel
*evsel
, struct cpu_map
*cpus
,
236 struct thread_map
*threads
, bool group
, bool inherit
)
239 /* Work around old compiler warnings about strict aliasing */
240 cpus
= &empty_cpu_map
.map
;
244 threads
= &empty_thread_map
.map
;
246 return __perf_evsel__open(evsel
, cpus
, threads
, group
, inherit
);
249 int perf_evsel__open_per_cpu(struct perf_evsel
*evsel
,
250 struct cpu_map
*cpus
, bool group
, bool inherit
)
252 return __perf_evsel__open(evsel
, cpus
, &empty_thread_map
.map
, group
, inherit
);
255 int perf_evsel__open_per_thread(struct perf_evsel
*evsel
,
256 struct thread_map
*threads
, bool group
, bool inherit
)
258 return __perf_evsel__open(evsel
, &empty_cpu_map
.map
, threads
, group
, inherit
);
261 static int __perf_evlist__mmap(struct perf_evlist
*evlist
, int cpu
, int prot
,
264 evlist
->mmap
[cpu
].prev
= 0;
265 evlist
->mmap
[cpu
].mask
= mask
;
266 evlist
->mmap
[cpu
].base
= mmap(NULL
, evlist
->mmap_len
, prot
,
268 if (evlist
->mmap
[cpu
].base
== MAP_FAILED
)
271 perf_evlist__add_pollfd(evlist
, fd
);
275 static int perf_evlist__id_hash(struct perf_evlist
*evlist
, struct perf_evsel
*evsel
,
276 int cpu
, int thread
, int fd
)
278 struct perf_sample_id
*sid
;
279 u64 read_data
[4] = { 0, };
280 int hash
, id_idx
= 1; /* The first entry is the counter value */
282 if (!(evsel
->attr
.read_format
& PERF_FORMAT_ID
) ||
283 read(fd
, &read_data
, sizeof(read_data
)) == -1)
286 if (evsel
->attr
.read_format
& PERF_FORMAT_TOTAL_TIME_ENABLED
)
288 if (evsel
->attr
.read_format
& PERF_FORMAT_TOTAL_TIME_RUNNING
)
291 sid
= SID(evsel
, cpu
, thread
);
292 sid
->id
= read_data
[id_idx
];
294 hash
= hash_64(sid
->id
, PERF_EVLIST__HLIST_BITS
);
295 hlist_add_head(&sid
->node
, &evlist
->heads
[hash
]);
299 /** perf_evlist__mmap - Create per cpu maps to receive events
301 * @evlist - list of events
302 * @cpus - cpu map being monitored
303 * @threads - threads map being monitored
304 * @pages - map length in pages
305 * @overwrite - overwrite older events?
307 * If overwrite is false the user needs to signal event consuption using:
309 * struct perf_mmap *m = &evlist->mmap[cpu];
310 * unsigned int head = perf_mmap__read_head(m);
312 * perf_mmap__write_tail(m, head)
314 int perf_evlist__mmap(struct perf_evlist
*evlist
, struct cpu_map
*cpus
,
315 struct thread_map
*threads
, int pages
, bool overwrite
)
317 unsigned int page_size
= sysconf(_SC_PAGE_SIZE
);
318 int mask
= pages
* page_size
- 1, cpu
;
319 struct perf_evsel
*first_evsel
, *evsel
;
320 int thread
, prot
= PROT_READ
| (overwrite
? 0 : PROT_WRITE
);
322 if (evlist
->mmap
== NULL
&&
323 perf_evlist__alloc_mmap(evlist
, cpus
->nr
) < 0)
326 if (evlist
->pollfd
== NULL
&&
327 perf_evlist__alloc_pollfd(evlist
, cpus
->nr
, threads
->nr
) < 0)
330 evlist
->overwrite
= overwrite
;
331 evlist
->mmap_len
= (pages
+ 1) * page_size
;
332 first_evsel
= list_entry(evlist
->entries
.next
, struct perf_evsel
, node
);
334 list_for_each_entry(evsel
, &evlist
->entries
, node
) {
335 if ((evsel
->attr
.read_format
& PERF_FORMAT_ID
) &&
337 perf_evsel__alloc_id(evsel
, cpus
->nr
, threads
->nr
) < 0)
340 for (cpu
= 0; cpu
< cpus
->nr
; cpu
++) {
341 for (thread
= 0; thread
< threads
->nr
; thread
++) {
342 int fd
= FD(evsel
, cpu
, thread
);
344 if (evsel
->idx
|| thread
) {
345 if (ioctl(fd
, PERF_EVENT_IOC_SET_OUTPUT
,
346 FD(first_evsel
, cpu
, 0)) != 0)
348 } else if (__perf_evlist__mmap(evlist
, cpu
, prot
, mask
, fd
) < 0)
351 if ((evsel
->attr
.read_format
& PERF_FORMAT_ID
) &&
352 perf_evlist__id_hash(evlist
, evsel
, cpu
, thread
, fd
) < 0)
361 for (cpu
= 0; cpu
< cpus
->nr
; cpu
++) {
362 if (evlist
->mmap
[cpu
].base
!= NULL
) {
363 munmap(evlist
->mmap
[cpu
].base
, evlist
->mmap_len
);
364 evlist
->mmap
[cpu
].base
= NULL
;
370 static int perf_event__parse_id_sample(const union perf_event
*event
, u64 type
,
371 struct perf_sample
*sample
)
373 const u64
*array
= event
->sample
.array
;
375 array
+= ((event
->header
.size
-
376 sizeof(event
->header
)) / sizeof(u64
)) - 1;
378 if (type
& PERF_SAMPLE_CPU
) {
379 u32
*p
= (u32
*)array
;
384 if (type
& PERF_SAMPLE_STREAM_ID
) {
385 sample
->stream_id
= *array
;
389 if (type
& PERF_SAMPLE_ID
) {
394 if (type
& PERF_SAMPLE_TIME
) {
395 sample
->time
= *array
;
399 if (type
& PERF_SAMPLE_TID
) {
400 u32
*p
= (u32
*)array
;
408 int perf_event__parse_sample(const union perf_event
*event
, u64 type
,
409 bool sample_id_all
, struct perf_sample
*data
)
413 data
->cpu
= data
->pid
= data
->tid
= -1;
414 data
->stream_id
= data
->id
= data
->time
= -1ULL;
416 if (event
->header
.type
!= PERF_RECORD_SAMPLE
) {
419 return perf_event__parse_id_sample(event
, type
, data
);
422 array
= event
->sample
.array
;
424 if (type
& PERF_SAMPLE_IP
) {
425 data
->ip
= event
->ip
.ip
;
429 if (type
& PERF_SAMPLE_TID
) {
430 u32
*p
= (u32
*)array
;
436 if (type
& PERF_SAMPLE_TIME
) {
441 if (type
& PERF_SAMPLE_ADDR
) {
447 if (type
& PERF_SAMPLE_ID
) {
452 if (type
& PERF_SAMPLE_STREAM_ID
) {
453 data
->stream_id
= *array
;
457 if (type
& PERF_SAMPLE_CPU
) {
458 u32
*p
= (u32
*)array
;
463 if (type
& PERF_SAMPLE_PERIOD
) {
464 data
->period
= *array
;
468 if (type
& PERF_SAMPLE_READ
) {
469 fprintf(stderr
, "PERF_SAMPLE_READ is unsuported for now\n");
473 if (type
& PERF_SAMPLE_CALLCHAIN
) {
474 data
->callchain
= (struct ip_callchain
*)array
;
475 array
+= 1 + data
->callchain
->nr
;
478 if (type
& PERF_SAMPLE_RAW
) {
479 u32
*p
= (u32
*)array
;