2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
7 * Released under the GPL v2. (and only v2, not any later version)
14 #include "thread_map.h"
16 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
18 void perf_evsel__init(struct perf_evsel
*evsel
,
19 struct perf_event_attr
*attr
, int idx
)
23 INIT_LIST_HEAD(&evsel
->node
);
26 struct perf_evsel
*perf_evsel__new(struct perf_event_attr
*attr
, int idx
)
28 struct perf_evsel
*evsel
= zalloc(sizeof(*evsel
));
31 perf_evsel__init(evsel
, attr
, idx
);
36 int perf_evsel__alloc_fd(struct perf_evsel
*evsel
, int ncpus
, int nthreads
)
38 evsel
->fd
= xyarray__new(ncpus
, nthreads
, sizeof(int));
39 return evsel
->fd
!= NULL
? 0 : -ENOMEM
;
42 int perf_evsel__alloc_id(struct perf_evsel
*evsel
, int ncpus
, int nthreads
)
44 evsel
->id
= xyarray__new(ncpus
, nthreads
, sizeof(struct perf_sample_id
));
45 return evsel
->id
!= NULL
? 0 : -ENOMEM
;
48 int perf_evsel__alloc_counts(struct perf_evsel
*evsel
, int ncpus
)
50 evsel
->counts
= zalloc((sizeof(*evsel
->counts
) +
51 (ncpus
* sizeof(struct perf_counts_values
))));
52 return evsel
->counts
!= NULL
? 0 : -ENOMEM
;
55 void perf_evsel__free_fd(struct perf_evsel
*evsel
)
57 xyarray__delete(evsel
->fd
);
61 void perf_evsel__free_id(struct perf_evsel
*evsel
)
63 xyarray__delete(evsel
->id
);
67 void perf_evsel__close_fd(struct perf_evsel
*evsel
, int ncpus
, int nthreads
)
71 for (cpu
= 0; cpu
< ncpus
; cpu
++)
72 for (thread
= 0; thread
< nthreads
; ++thread
) {
73 close(FD(evsel
, cpu
, thread
));
74 FD(evsel
, cpu
, thread
) = -1;
78 void perf_evsel__exit(struct perf_evsel
*evsel
)
80 assert(list_empty(&evsel
->node
));
81 xyarray__delete(evsel
->fd
);
82 xyarray__delete(evsel
->id
);
85 void perf_evsel__delete(struct perf_evsel
*evsel
)
87 perf_evsel__exit(evsel
);
88 close_cgroup(evsel
->cgrp
);
93 int __perf_evsel__read_on_cpu(struct perf_evsel
*evsel
,
94 int cpu
, int thread
, bool scale
)
96 struct perf_counts_values count
;
97 size_t nv
= scale
? 3 : 1;
99 if (FD(evsel
, cpu
, thread
) < 0)
102 if (evsel
->counts
== NULL
&& perf_evsel__alloc_counts(evsel
, cpu
+ 1) < 0)
105 if (readn(FD(evsel
, cpu
, thread
), &count
, nv
* sizeof(u64
)) < 0)
111 else if (count
.run
< count
.ena
)
112 count
.val
= (u64
)((double)count
.val
* count
.ena
/ count
.run
+ 0.5);
114 count
.ena
= count
.run
= 0;
116 evsel
->counts
->cpu
[cpu
] = count
;
120 int __perf_evsel__read(struct perf_evsel
*evsel
,
121 int ncpus
, int nthreads
, bool scale
)
123 size_t nv
= scale
? 3 : 1;
125 struct perf_counts_values
*aggr
= &evsel
->counts
->aggr
, count
;
127 aggr
->val
= aggr
->ena
= aggr
->run
= 0;
129 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
130 for (thread
= 0; thread
< nthreads
; thread
++) {
131 if (FD(evsel
, cpu
, thread
) < 0)
134 if (readn(FD(evsel
, cpu
, thread
),
135 &count
, nv
* sizeof(u64
)) < 0)
138 aggr
->val
+= count
.val
;
140 aggr
->ena
+= count
.ena
;
141 aggr
->run
+= count
.run
;
146 evsel
->counts
->scaled
= 0;
148 if (aggr
->run
== 0) {
149 evsel
->counts
->scaled
= -1;
154 if (aggr
->run
< aggr
->ena
) {
155 evsel
->counts
->scaled
= 1;
156 aggr
->val
= (u64
)((double)aggr
->val
* aggr
->ena
/ aggr
->run
+ 0.5);
159 aggr
->ena
= aggr
->run
= 0;
164 static int __perf_evsel__open(struct perf_evsel
*evsel
, struct cpu_map
*cpus
,
165 struct thread_map
*threads
, bool group
, bool inherit
)
168 unsigned long flags
= 0;
171 if (evsel
->fd
== NULL
&&
172 perf_evsel__alloc_fd(evsel
, cpus
->nr
, threads
->nr
) < 0)
176 flags
= PERF_FLAG_PID_CGROUP
;
177 pid
= evsel
->cgrp
->fd
;
180 for (cpu
= 0; cpu
< cpus
->nr
; cpu
++) {
183 * Don't allow mmap() of inherited per-task counters. This
184 * would create a performance issue due to all children writing
185 * to the same buffer.
188 * Proper fix is not to pass 'inherit' to perf_evsel__open*,
189 * but a 'flags' parameter, with 'group' folded there as well,
190 * then introduce a PERF_O_{MMAP,GROUP,INHERIT} enum, and if
191 * O_MMAP is set, emit a warning if cpu < 0 and O_INHERIT is
192 * set. Lets go for the minimal fix first tho.
194 evsel
->attr
.inherit
= (cpus
->map
[cpu
] >= 0) && inherit
;
196 for (thread
= 0; thread
< threads
->nr
; thread
++) {
199 pid
= threads
->map
[thread
];
201 FD(evsel
, cpu
, thread
) = sys_perf_event_open(&evsel
->attr
,
205 if (FD(evsel
, cpu
, thread
) < 0)
208 if (group
&& group_fd
== -1)
209 group_fd
= FD(evsel
, cpu
, thread
);
217 while (--thread
>= 0) {
218 close(FD(evsel
, cpu
, thread
));
219 FD(evsel
, cpu
, thread
) = -1;
221 thread
= threads
->nr
;
222 } while (--cpu
>= 0);
235 struct thread_map map
;
237 } empty_thread_map
= {
242 int perf_evsel__open(struct perf_evsel
*evsel
, struct cpu_map
*cpus
,
243 struct thread_map
*threads
, bool group
, bool inherit
)
246 /* Work around old compiler warnings about strict aliasing */
247 cpus
= &empty_cpu_map
.map
;
251 threads
= &empty_thread_map
.map
;
253 return __perf_evsel__open(evsel
, cpus
, threads
, group
, inherit
);
256 int perf_evsel__open_per_cpu(struct perf_evsel
*evsel
,
257 struct cpu_map
*cpus
, bool group
, bool inherit
)
259 return __perf_evsel__open(evsel
, cpus
, &empty_thread_map
.map
, group
, inherit
);
262 int perf_evsel__open_per_thread(struct perf_evsel
*evsel
,
263 struct thread_map
*threads
, bool group
, bool inherit
)
265 return __perf_evsel__open(evsel
, &empty_cpu_map
.map
, threads
, group
, inherit
);
268 static int perf_event__parse_id_sample(const union perf_event
*event
, u64 type
,
269 struct perf_sample
*sample
)
271 const u64
*array
= event
->sample
.array
;
273 array
+= ((event
->header
.size
-
274 sizeof(event
->header
)) / sizeof(u64
)) - 1;
276 if (type
& PERF_SAMPLE_CPU
) {
277 u32
*p
= (u32
*)array
;
282 if (type
& PERF_SAMPLE_STREAM_ID
) {
283 sample
->stream_id
= *array
;
287 if (type
& PERF_SAMPLE_ID
) {
292 if (type
& PERF_SAMPLE_TIME
) {
293 sample
->time
= *array
;
297 if (type
& PERF_SAMPLE_TID
) {
298 u32
*p
= (u32
*)array
;
306 int perf_event__parse_sample(const union perf_event
*event
, u64 type
,
307 bool sample_id_all
, struct perf_sample
*data
)
311 data
->cpu
= data
->pid
= data
->tid
= -1;
312 data
->stream_id
= data
->id
= data
->time
= -1ULL;
314 if (event
->header
.type
!= PERF_RECORD_SAMPLE
) {
317 return perf_event__parse_id_sample(event
, type
, data
);
320 array
= event
->sample
.array
;
322 if (type
& PERF_SAMPLE_IP
) {
323 data
->ip
= event
->ip
.ip
;
327 if (type
& PERF_SAMPLE_TID
) {
328 u32
*p
= (u32
*)array
;
334 if (type
& PERF_SAMPLE_TIME
) {
339 if (type
& PERF_SAMPLE_ADDR
) {
345 if (type
& PERF_SAMPLE_ID
) {
350 if (type
& PERF_SAMPLE_STREAM_ID
) {
351 data
->stream_id
= *array
;
355 if (type
& PERF_SAMPLE_CPU
) {
356 u32
*p
= (u32
*)array
;
361 if (type
& PERF_SAMPLE_PERIOD
) {
362 data
->period
= *array
;
366 if (type
& PERF_SAMPLE_READ
) {
367 fprintf(stderr
, "PERF_SAMPLE_READ is unsuported for now\n");
371 if (type
& PERF_SAMPLE_CALLCHAIN
) {
372 data
->callchain
= (struct ip_callchain
*)array
;
373 array
+= 1 + data
->callchain
->nr
;
376 if (type
& PERF_SAMPLE_RAW
) {
377 u32
*p
= (u32
*)array
;
This page took 0.064566 seconds and 5 git commands to generate.