Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh...
[pandora-kernel.git] / tools / perf / util / evsel.c
1 #include "evsel.h"
2 #include "../perf.h"
3 #include "util.h"
4 #include "cpumap.h"
5 #include "thread.h"
6
7 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
8
9 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
10 {
11         struct perf_evsel *evsel = zalloc(sizeof(*evsel));
12
13         if (evsel != NULL) {
14                 evsel->idx         = idx;
15                 evsel->attr        = *attr;
16                 INIT_LIST_HEAD(&evsel->node);
17         }
18
19         return evsel;
20 }
21
22 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
23 {
24         evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
25         return evsel->fd != NULL ? 0 : -ENOMEM;
26 }
27
28 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
29 {
30         evsel->counts = zalloc((sizeof(*evsel->counts) +
31                                 (ncpus * sizeof(struct perf_counts_values))));
32         return evsel->counts != NULL ? 0 : -ENOMEM;
33 }
34
35 void perf_evsel__free_fd(struct perf_evsel *evsel)
36 {
37         xyarray__delete(evsel->fd);
38         evsel->fd = NULL;
39 }
40
41 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
42 {
43         int cpu, thread;
44
45         for (cpu = 0; cpu < ncpus; cpu++)
46                 for (thread = 0; thread < nthreads; ++thread) {
47                         close(FD(evsel, cpu, thread));
48                         FD(evsel, cpu, thread) = -1;
49                 }
50 }
51
52 void perf_evsel__delete(struct perf_evsel *evsel)
53 {
54         assert(list_empty(&evsel->node));
55         xyarray__delete(evsel->fd);
56         free(evsel);
57 }
58
59 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
60                               int cpu, int thread, bool scale)
61 {
62         struct perf_counts_values count;
63         size_t nv = scale ? 3 : 1;
64
65         if (FD(evsel, cpu, thread) < 0)
66                 return -EINVAL;
67
68         if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
69                 return -ENOMEM;
70
71         if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
72                 return -errno;
73
74         if (scale) {
75                 if (count.run == 0)
76                         count.val = 0;
77                 else if (count.run < count.ena)
78                         count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
79         } else
80                 count.ena = count.run = 0;
81
82         evsel->counts->cpu[cpu] = count;
83         return 0;
84 }
85
86 int __perf_evsel__read(struct perf_evsel *evsel,
87                        int ncpus, int nthreads, bool scale)
88 {
89         size_t nv = scale ? 3 : 1;
90         int cpu, thread;
91         struct perf_counts_values *aggr = &evsel->counts->aggr, count;
92
93         aggr->val = 0;
94
95         for (cpu = 0; cpu < ncpus; cpu++) {
96                 for (thread = 0; thread < nthreads; thread++) {
97                         if (FD(evsel, cpu, thread) < 0)
98                                 continue;
99
100                         if (readn(FD(evsel, cpu, thread),
101                                   &count, nv * sizeof(u64)) < 0)
102                                 return -errno;
103
104                         aggr->val += count.val;
105                         if (scale) {
106                                 aggr->ena += count.ena;
107                                 aggr->run += count.run;
108                         }
109                 }
110         }
111
112         evsel->counts->scaled = 0;
113         if (scale) {
114                 if (aggr->run == 0) {
115                         evsel->counts->scaled = -1;
116                         aggr->val = 0;
117                         return 0;
118                 }
119
120                 if (aggr->run < aggr->ena) {
121                         evsel->counts->scaled = 1;
122                         aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
123                 }
124         } else
125                 aggr->ena = aggr->run = 0;
126
127         return 0;
128 }
129
130 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
131                               struct thread_map *threads)
132 {
133         int cpu, thread;
134
135         if (evsel->fd == NULL &&
136             perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
137                 return -1;
138
139         for (cpu = 0; cpu < cpus->nr; cpu++) {
140                 for (thread = 0; thread < threads->nr; thread++) {
141                         FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
142                                                                      threads->map[thread],
143                                                                      cpus->map[cpu], -1, 0);
144                         if (FD(evsel, cpu, thread) < 0)
145                                 goto out_close;
146                 }
147         }
148
149         return 0;
150
151 out_close:
152         do {
153                 while (--thread >= 0) {
154                         close(FD(evsel, cpu, thread));
155                         FD(evsel, cpu, thread) = -1;
156                 }
157                 thread = threads->nr;
158         } while (--cpu >= 0);
159         return -1;
160 }
161
162 static struct {
163         struct cpu_map map;
164         int cpus[1];
165 } empty_cpu_map = {
166         .map.nr = 1,
167         .cpus   = { -1, },
168 };
169
170 static struct {
171         struct thread_map map;
172         int threads[1];
173 } empty_thread_map = {
174         .map.nr  = 1,
175         .threads = { -1, },
176 };
177
178 int perf_evsel__open(struct perf_evsel *evsel,
179                      struct cpu_map *cpus, struct thread_map *threads)
180 {
181
182         if (cpus == NULL) {
183                 /* Work around old compiler warnings about strict aliasing */
184                 cpus = &empty_cpu_map.map;
185         }
186
187         if (threads == NULL)
188                 threads = &empty_thread_map.map;
189
190         return __perf_evsel__open(evsel, cpus, threads);
191 }
192
193 int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus)
194 {
195         return __perf_evsel__open(evsel, cpus, &empty_thread_map.map);
196 }
197
198 int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads)
199 {
200         return __perf_evsel__open(evsel, &empty_cpu_map.map, threads);
201 }