]> git.karo-electronics.de Git - mv-sheeva.git/blob - tools/perf/util/evsel.c
Merge branch 'linus' into perf/core
[mv-sheeva.git] / tools / perf / util / evsel.c
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
10 #include "evsel.h"
11 #include "evlist.h"
12 #include "util.h"
13 #include "cpumap.h"
14 #include "thread_map.h"
15
16 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
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
26 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
27 {
28         struct perf_evsel *evsel = zalloc(sizeof(*evsel));
29
30         if (evsel != NULL)
31                 perf_evsel__init(evsel, attr, idx);
32
33         return evsel;
34 }
35
36 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
37 {
38         evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
39         return evsel->fd != NULL ? 0 : -ENOMEM;
40 }
41
42 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
43 {
44         evsel->id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
45         return evsel->id != NULL ? 0 : -ENOMEM;
46 }
47
48 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
49 {
50         evsel->counts = zalloc((sizeof(*evsel->counts) +
51                                 (ncpus * sizeof(struct perf_counts_values))));
52         return evsel->counts != NULL ? 0 : -ENOMEM;
53 }
54
55 void perf_evsel__free_fd(struct perf_evsel *evsel)
56 {
57         xyarray__delete(evsel->fd);
58         evsel->fd = NULL;
59 }
60
61 void perf_evsel__free_id(struct perf_evsel *evsel)
62 {
63         xyarray__delete(evsel->id);
64         evsel->id = NULL;
65 }
66
67 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
68 {
69         int cpu, thread;
70
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;
75                 }
76 }
77
78 void perf_evsel__exit(struct perf_evsel *evsel)
79 {
80         assert(list_empty(&evsel->node));
81         xyarray__delete(evsel->fd);
82         xyarray__delete(evsel->id);
83 }
84
85 void perf_evsel__delete(struct perf_evsel *evsel)
86 {
87         perf_evsel__exit(evsel);
88         free(evsel);
89 }
90
91 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
92                               int cpu, int thread, bool scale)
93 {
94         struct perf_counts_values count;
95         size_t nv = scale ? 3 : 1;
96
97         if (FD(evsel, cpu, thread) < 0)
98                 return -EINVAL;
99
100         if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
101                 return -ENOMEM;
102
103         if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
104                 return -errno;
105
106         if (scale) {
107                 if (count.run == 0)
108                         count.val = 0;
109                 else if (count.run < count.ena)
110                         count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
111         } else
112                 count.ena = count.run = 0;
113
114         evsel->counts->cpu[cpu] = count;
115         return 0;
116 }
117
118 int __perf_evsel__read(struct perf_evsel *evsel,
119                        int ncpus, int nthreads, bool scale)
120 {
121         size_t nv = scale ? 3 : 1;
122         int cpu, thread;
123         struct perf_counts_values *aggr = &evsel->counts->aggr, count;
124
125         aggr->val = aggr->ena = aggr->run = 0;
126
127         for (cpu = 0; cpu < ncpus; cpu++) {
128                 for (thread = 0; thread < nthreads; thread++) {
129                         if (FD(evsel, cpu, thread) < 0)
130                                 continue;
131
132                         if (readn(FD(evsel, cpu, thread),
133                                   &count, nv * sizeof(u64)) < 0)
134                                 return -errno;
135
136                         aggr->val += count.val;
137                         if (scale) {
138                                 aggr->ena += count.ena;
139                                 aggr->run += count.run;
140                         }
141                 }
142         }
143
144         evsel->counts->scaled = 0;
145         if (scale) {
146                 if (aggr->run == 0) {
147                         evsel->counts->scaled = -1;
148                         aggr->val = 0;
149                         return 0;
150                 }
151
152                 if (aggr->run < aggr->ena) {
153                         evsel->counts->scaled = 1;
154                         aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
155                 }
156         } else
157                 aggr->ena = aggr->run = 0;
158
159         return 0;
160 }
161
162 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
163                               struct thread_map *threads, bool group, bool inherit)
164 {
165         int cpu, thread;
166
167         if (evsel->fd == NULL &&
168             perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
169                 return -1;
170
171         for (cpu = 0; cpu < cpus->nr; cpu++) {
172                 int group_fd = -1;
173
174                 evsel->attr.inherit = (cpus->map[cpu] < 0) && inherit;
175
176                 for (thread = 0; thread < threads->nr; thread++) {
177                         FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
178                                                                      threads->map[thread],
179                                                                      cpus->map[cpu],
180                                                                      group_fd, 0);
181                         if (FD(evsel, cpu, thread) < 0)
182                                 goto out_close;
183
184                         if (group && group_fd == -1)
185                                 group_fd = FD(evsel, cpu, thread);
186                 }
187         }
188
189         return 0;
190
191 out_close:
192         do {
193                 while (--thread >= 0) {
194                         close(FD(evsel, cpu, thread));
195                         FD(evsel, cpu, thread) = -1;
196                 }
197                 thread = threads->nr;
198         } while (--cpu >= 0);
199         return -1;
200 }
201
202 static struct {
203         struct cpu_map map;
204         int cpus[1];
205 } empty_cpu_map = {
206         .map.nr = 1,
207         .cpus   = { -1, },
208 };
209
210 static struct {
211         struct thread_map map;
212         int threads[1];
213 } empty_thread_map = {
214         .map.nr  = 1,
215         .threads = { -1, },
216 };
217
218 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
219                      struct thread_map *threads, bool group, bool inherit)
220 {
221         if (cpus == NULL) {
222                 /* Work around old compiler warnings about strict aliasing */
223                 cpus = &empty_cpu_map.map;
224         }
225
226         if (threads == NULL)
227                 threads = &empty_thread_map.map;
228
229         return __perf_evsel__open(evsel, cpus, threads, group, inherit);
230 }
231
232 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
233                              struct cpu_map *cpus, bool group, bool inherit)
234 {
235         return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit);
236 }
237
238 int perf_evsel__open_per_thread(struct perf_evsel *evsel,
239                                 struct thread_map *threads, bool group, bool inherit)
240 {
241         return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit);
242 }
243
244 static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
245                                        struct perf_sample *sample)
246 {
247         const u64 *array = event->sample.array;
248
249         array += ((event->header.size -
250                    sizeof(event->header)) / sizeof(u64)) - 1;
251
252         if (type & PERF_SAMPLE_CPU) {
253                 u32 *p = (u32 *)array;
254                 sample->cpu = *p;
255                 array--;
256         }
257
258         if (type & PERF_SAMPLE_STREAM_ID) {
259                 sample->stream_id = *array;
260                 array--;
261         }
262
263         if (type & PERF_SAMPLE_ID) {
264                 sample->id = *array;
265                 array--;
266         }
267
268         if (type & PERF_SAMPLE_TIME) {
269                 sample->time = *array;
270                 array--;
271         }
272
273         if (type & PERF_SAMPLE_TID) {
274                 u32 *p = (u32 *)array;
275                 sample->pid = p[0];
276                 sample->tid = p[1];
277         }
278
279         return 0;
280 }
281
282 int perf_event__parse_sample(const union perf_event *event, u64 type,
283                              bool sample_id_all, struct perf_sample *data)
284 {
285         const u64 *array;
286
287         data->cpu = data->pid = data->tid = -1;
288         data->stream_id = data->id = data->time = -1ULL;
289
290         if (event->header.type != PERF_RECORD_SAMPLE) {
291                 if (!sample_id_all)
292                         return 0;
293                 return perf_event__parse_id_sample(event, type, data);
294         }
295
296         array = event->sample.array;
297
298         if (type & PERF_SAMPLE_IP) {
299                 data->ip = event->ip.ip;
300                 array++;
301         }
302
303         if (type & PERF_SAMPLE_TID) {
304                 u32 *p = (u32 *)array;
305                 data->pid = p[0];
306                 data->tid = p[1];
307                 array++;
308         }
309
310         if (type & PERF_SAMPLE_TIME) {
311                 data->time = *array;
312                 array++;
313         }
314
315         if (type & PERF_SAMPLE_ADDR) {
316                 data->addr = *array;
317                 array++;
318         }
319
320         data->id = -1ULL;
321         if (type & PERF_SAMPLE_ID) {
322                 data->id = *array;
323                 array++;
324         }
325
326         if (type & PERF_SAMPLE_STREAM_ID) {
327                 data->stream_id = *array;
328                 array++;
329         }
330
331         if (type & PERF_SAMPLE_CPU) {
332                 u32 *p = (u32 *)array;
333                 data->cpu = *p;
334                 array++;
335         }
336
337         if (type & PERF_SAMPLE_PERIOD) {
338                 data->period = *array;
339                 array++;
340         }
341
342         if (type & PERF_SAMPLE_READ) {
343                 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
344                 return -1;
345         }
346
347         if (type & PERF_SAMPLE_CALLCHAIN) {
348                 data->callchain = (struct ip_callchain *)array;
349                 array += 1 + data->callchain->nr;
350         }
351
352         if (type & PERF_SAMPLE_RAW) {
353                 u32 *p = (u32 *)array;
354                 data->raw_size = *p;
355                 p++;
356                 data->raw_data = p;
357         }
358
359         return 0;
360 }