diff options
Diffstat (limited to 'tools/perf/util/evsel.c')
-rw-r--r-- | tools/perf/util/evsel.c | 223 |
1 files changed, 203 insertions, 20 deletions
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f5cfed60af98..d6fd59beb860 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -1,20 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | ||
3 | * | ||
4 | * Parts came from builtin-{top,stat,record}.c, see those files for further | ||
5 | * copyright notes. | ||
6 | * | ||
7 | * Released under the GPL v2. (and only v2, not any later version) | ||
8 | */ | ||
9 | |||
1 | #include "evsel.h" | 10 | #include "evsel.h" |
2 | #include "../perf.h" | 11 | #include "evlist.h" |
3 | #include "util.h" | 12 | #include "util.h" |
4 | #include "cpumap.h" | 13 | #include "cpumap.h" |
5 | #include "thread.h" | 14 | #include "thread_map.h" |
6 | 15 | ||
7 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 16 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
8 | 17 | ||
18 | void perf_evsel__init(struct perf_evsel *evsel, | ||
19 | struct perf_event_attr *attr, int idx) | ||
20 | { | ||
21 | evsel->idx = idx; | ||
22 | evsel->attr = *attr; | ||
23 | INIT_LIST_HEAD(&evsel->node); | ||
24 | } | ||
25 | |||
9 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) | 26 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) |
10 | { | 27 | { |
11 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); | 28 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); |
12 | 29 | ||
13 | if (evsel != NULL) { | 30 | if (evsel != NULL) |
14 | evsel->idx = idx; | 31 | perf_evsel__init(evsel, attr, idx); |
15 | evsel->attr = *attr; | ||
16 | INIT_LIST_HEAD(&evsel->node); | ||
17 | } | ||
18 | 32 | ||
19 | return evsel; | 33 | return evsel; |
20 | } | 34 | } |
@@ -25,6 +39,22 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
25 | return evsel->fd != NULL ? 0 : -ENOMEM; | 39 | return evsel->fd != NULL ? 0 : -ENOMEM; |
26 | } | 40 | } |
27 | 41 | ||
42 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) | ||
43 | { | ||
44 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); | ||
45 | if (evsel->sample_id == NULL) | ||
46 | return -ENOMEM; | ||
47 | |||
48 | evsel->id = zalloc(ncpus * nthreads * sizeof(u64)); | ||
49 | if (evsel->id == NULL) { | ||
50 | xyarray__delete(evsel->sample_id); | ||
51 | evsel->sample_id = NULL; | ||
52 | return -ENOMEM; | ||
53 | } | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
28 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) | 58 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) |
29 | { | 59 | { |
30 | evsel->counts = zalloc((sizeof(*evsel->counts) + | 60 | evsel->counts = zalloc((sizeof(*evsel->counts) + |
@@ -38,6 +68,14 @@ void perf_evsel__free_fd(struct perf_evsel *evsel) | |||
38 | evsel->fd = NULL; | 68 | evsel->fd = NULL; |
39 | } | 69 | } |
40 | 70 | ||
71 | void perf_evsel__free_id(struct perf_evsel *evsel) | ||
72 | { | ||
73 | xyarray__delete(evsel->sample_id); | ||
74 | evsel->sample_id = NULL; | ||
75 | free(evsel->id); | ||
76 | evsel->id = NULL; | ||
77 | } | ||
78 | |||
41 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 79 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
42 | { | 80 | { |
43 | int cpu, thread; | 81 | int cpu, thread; |
@@ -49,10 +87,19 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
49 | } | 87 | } |
50 | } | 88 | } |
51 | 89 | ||
52 | void perf_evsel__delete(struct perf_evsel *evsel) | 90 | void perf_evsel__exit(struct perf_evsel *evsel) |
53 | { | 91 | { |
54 | assert(list_empty(&evsel->node)); | 92 | assert(list_empty(&evsel->node)); |
55 | xyarray__delete(evsel->fd); | 93 | xyarray__delete(evsel->fd); |
94 | xyarray__delete(evsel->sample_id); | ||
95 | free(evsel->id); | ||
96 | } | ||
97 | |||
98 | void perf_evsel__delete(struct perf_evsel *evsel) | ||
99 | { | ||
100 | perf_evsel__exit(evsel); | ||
101 | close_cgroup(evsel->cgrp); | ||
102 | free(evsel->name); | ||
56 | free(evsel); | 103 | free(evsel); |
57 | } | 104 | } |
58 | 105 | ||
@@ -90,7 +137,7 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
90 | int cpu, thread; | 137 | int cpu, thread; |
91 | struct perf_counts_values *aggr = &evsel->counts->aggr, count; | 138 | struct perf_counts_values *aggr = &evsel->counts->aggr, count; |
92 | 139 | ||
93 | aggr->val = 0; | 140 | aggr->val = aggr->ena = aggr->run = 0; |
94 | 141 | ||
95 | for (cpu = 0; cpu < ncpus; cpu++) { | 142 | for (cpu = 0; cpu < ncpus; cpu++) { |
96 | for (thread = 0; thread < nthreads; thread++) { | 143 | for (thread = 0; thread < nthreads; thread++) { |
@@ -128,21 +175,38 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
128 | } | 175 | } |
129 | 176 | ||
130 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 177 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
131 | struct thread_map *threads) | 178 | struct thread_map *threads, bool group) |
132 | { | 179 | { |
133 | int cpu, thread; | 180 | int cpu, thread; |
181 | unsigned long flags = 0; | ||
182 | int pid = -1; | ||
134 | 183 | ||
135 | if (evsel->fd == NULL && | 184 | if (evsel->fd == NULL && |
136 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) | 185 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) |
137 | return -1; | 186 | return -1; |
138 | 187 | ||
188 | if (evsel->cgrp) { | ||
189 | flags = PERF_FLAG_PID_CGROUP; | ||
190 | pid = evsel->cgrp->fd; | ||
191 | } | ||
192 | |||
139 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 193 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
194 | int group_fd = -1; | ||
195 | |||
140 | for (thread = 0; thread < threads->nr; thread++) { | 196 | for (thread = 0; thread < threads->nr; thread++) { |
197 | |||
198 | if (!evsel->cgrp) | ||
199 | pid = threads->map[thread]; | ||
200 | |||
141 | FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, | 201 | FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, |
142 | threads->map[thread], | 202 | pid, |
143 | cpus->map[cpu], -1, 0); | 203 | cpus->map[cpu], |
204 | group_fd, flags); | ||
144 | if (FD(evsel, cpu, thread) < 0) | 205 | if (FD(evsel, cpu, thread) < 0) |
145 | goto out_close; | 206 | goto out_close; |
207 | |||
208 | if (group && group_fd == -1) | ||
209 | group_fd = FD(evsel, cpu, thread); | ||
146 | } | 210 | } |
147 | } | 211 | } |
148 | 212 | ||
@@ -175,10 +239,9 @@ static struct { | |||
175 | .threads = { -1, }, | 239 | .threads = { -1, }, |
176 | }; | 240 | }; |
177 | 241 | ||
178 | int perf_evsel__open(struct perf_evsel *evsel, | 242 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
179 | struct cpu_map *cpus, struct thread_map *threads) | 243 | struct thread_map *threads, bool group) |
180 | { | 244 | { |
181 | |||
182 | if (cpus == NULL) { | 245 | if (cpus == NULL) { |
183 | /* Work around old compiler warnings about strict aliasing */ | 246 | /* Work around old compiler warnings about strict aliasing */ |
184 | cpus = &empty_cpu_map.map; | 247 | cpus = &empty_cpu_map.map; |
@@ -187,15 +250,135 @@ int perf_evsel__open(struct perf_evsel *evsel, | |||
187 | if (threads == NULL) | 250 | if (threads == NULL) |
188 | threads = &empty_thread_map.map; | 251 | threads = &empty_thread_map.map; |
189 | 252 | ||
190 | return __perf_evsel__open(evsel, cpus, threads); | 253 | return __perf_evsel__open(evsel, cpus, threads, group); |
191 | } | 254 | } |
192 | 255 | ||
193 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus) | 256 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
257 | struct cpu_map *cpus, bool group) | ||
194 | { | 258 | { |
195 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map); | 259 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group); |
260 | } | ||
261 | |||
262 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | ||
263 | struct thread_map *threads, bool group) | ||
264 | { | ||
265 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group); | ||
266 | } | ||
267 | |||
268 | static int perf_event__parse_id_sample(const union perf_event *event, u64 type, | ||
269 | struct perf_sample *sample) | ||
270 | { | ||
271 | const u64 *array = event->sample.array; | ||
272 | |||
273 | array += ((event->header.size - | ||
274 | sizeof(event->header)) / sizeof(u64)) - 1; | ||
275 | |||
276 | if (type & PERF_SAMPLE_CPU) { | ||
277 | u32 *p = (u32 *)array; | ||
278 | sample->cpu = *p; | ||
279 | array--; | ||
280 | } | ||
281 | |||
282 | if (type & PERF_SAMPLE_STREAM_ID) { | ||
283 | sample->stream_id = *array; | ||
284 | array--; | ||
285 | } | ||
286 | |||
287 | if (type & PERF_SAMPLE_ID) { | ||
288 | sample->id = *array; | ||
289 | array--; | ||
290 | } | ||
291 | |||
292 | if (type & PERF_SAMPLE_TIME) { | ||
293 | sample->time = *array; | ||
294 | array--; | ||
295 | } | ||
296 | |||
297 | if (type & PERF_SAMPLE_TID) { | ||
298 | u32 *p = (u32 *)array; | ||
299 | sample->pid = p[0]; | ||
300 | sample->tid = p[1]; | ||
301 | } | ||
302 | |||
303 | return 0; | ||
196 | } | 304 | } |
197 | 305 | ||
198 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads) | 306 | int perf_event__parse_sample(const union perf_event *event, u64 type, |
307 | bool sample_id_all, struct perf_sample *data) | ||
199 | { | 308 | { |
200 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); | 309 | const u64 *array; |
310 | |||
311 | data->cpu = data->pid = data->tid = -1; | ||
312 | data->stream_id = data->id = data->time = -1ULL; | ||
313 | |||
314 | if (event->header.type != PERF_RECORD_SAMPLE) { | ||
315 | if (!sample_id_all) | ||
316 | return 0; | ||
317 | return perf_event__parse_id_sample(event, type, data); | ||
318 | } | ||
319 | |||
320 | array = event->sample.array; | ||
321 | |||
322 | if (type & PERF_SAMPLE_IP) { | ||
323 | data->ip = event->ip.ip; | ||
324 | array++; | ||
325 | } | ||
326 | |||
327 | if (type & PERF_SAMPLE_TID) { | ||
328 | u32 *p = (u32 *)array; | ||
329 | data->pid = p[0]; | ||
330 | data->tid = p[1]; | ||
331 | array++; | ||
332 | } | ||
333 | |||
334 | if (type & PERF_SAMPLE_TIME) { | ||
335 | data->time = *array; | ||
336 | array++; | ||
337 | } | ||
338 | |||
339 | if (type & PERF_SAMPLE_ADDR) { | ||
340 | data->addr = *array; | ||
341 | array++; | ||
342 | } | ||
343 | |||
344 | data->id = -1ULL; | ||
345 | if (type & PERF_SAMPLE_ID) { | ||
346 | data->id = *array; | ||
347 | array++; | ||
348 | } | ||
349 | |||
350 | if (type & PERF_SAMPLE_STREAM_ID) { | ||
351 | data->stream_id = *array; | ||
352 | array++; | ||
353 | } | ||
354 | |||
355 | if (type & PERF_SAMPLE_CPU) { | ||
356 | u32 *p = (u32 *)array; | ||
357 | data->cpu = *p; | ||
358 | array++; | ||
359 | } | ||
360 | |||
361 | if (type & PERF_SAMPLE_PERIOD) { | ||
362 | data->period = *array; | ||
363 | array++; | ||
364 | } | ||
365 | |||
366 | if (type & PERF_SAMPLE_READ) { | ||
367 | fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n"); | ||
368 | return -1; | ||
369 | } | ||
370 | |||
371 | if (type & PERF_SAMPLE_CALLCHAIN) { | ||
372 | data->callchain = (struct ip_callchain *)array; | ||
373 | array += 1 + data->callchain->nr; | ||
374 | } | ||
375 | |||
376 | if (type & PERF_SAMPLE_RAW) { | ||
377 | u32 *p = (u32 *)array; | ||
378 | data->raw_size = *p; | ||
379 | p++; | ||
380 | data->raw_data = p; | ||
381 | } | ||
382 | |||
383 | return 0; | ||
201 | } | 384 | } |