video: move SH_MIPI_DSI/SH_LCD_MIPI_DSI to the top of menu
[cascardo/linux.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(u32 type, u64 config, int idx)
10 {
11         struct perf_evsel *evsel = zalloc(sizeof(*evsel));
12
13         if (evsel != NULL) {
14                 evsel->idx         = idx;
15                 evsel->attr.type   = type;
16                 evsel->attr.config = config;
17                 INIT_LIST_HEAD(&evsel->node);
18         }
19
20         return evsel;
21 }
22
23 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
24 {
25         evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
26         return evsel->fd != NULL ? 0 : -ENOMEM;
27 }
28
29 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
30 {
31         evsel->counts = zalloc((sizeof(*evsel->counts) +
32                                 (ncpus * sizeof(struct perf_counts_values))));
33         return evsel->counts != NULL ? 0 : -ENOMEM;
34 }
35
36 void perf_evsel__free_fd(struct perf_evsel *evsel)
37 {
38         xyarray__delete(evsel->fd);
39         evsel->fd = NULL;
40 }
41
42 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
43 {
44         int cpu, thread;
45
46         for (cpu = 0; cpu < ncpus; cpu++)
47                 for (thread = 0; thread < nthreads; ++thread) {
48                         close(FD(evsel, cpu, thread));
49                         FD(evsel, cpu, thread) = -1;
50                 }
51 }
52
53 void perf_evsel__delete(struct perf_evsel *evsel)
54 {
55         assert(list_empty(&evsel->node));
56         xyarray__delete(evsel->fd);
57         free(evsel);
58 }
59
60 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
61                               int cpu, int thread, bool scale)
62 {
63         struct perf_counts_values count;
64         size_t nv = scale ? 3 : 1;
65
66         if (FD(evsel, cpu, thread) < 0)
67                 return -EINVAL;
68
69         if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
70                 return -ENOMEM;
71
72         if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
73                 return -errno;
74
75         if (scale) {
76                 if (count.run == 0)
77                         count.val = 0;
78                 else if (count.run < count.ena)
79                         count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
80         } else
81                 count.ena = count.run = 0;
82
83         evsel->counts->cpu[cpu] = count;
84         return 0;
85 }
86
87 int __perf_evsel__read(struct perf_evsel *evsel,
88                        int ncpus, int nthreads, bool scale)
89 {
90         size_t nv = scale ? 3 : 1;
91         int cpu, thread;
92         struct perf_counts_values *aggr = &evsel->counts->aggr, count;
93
94         aggr->val = 0;
95
96         for (cpu = 0; cpu < ncpus; cpu++) {
97                 for (thread = 0; thread < nthreads; thread++) {
98                         if (FD(evsel, cpu, thread) < 0)
99                                 continue;
100
101                         if (readn(FD(evsel, cpu, thread),
102                                   &count, nv * sizeof(u64)) < 0)
103                                 return -errno;
104
105                         aggr->val += count.val;
106                         if (scale) {
107                                 aggr->ena += count.ena;
108                                 aggr->run += count.run;
109                         }
110                 }
111         }
112
113         evsel->counts->scaled = 0;
114         if (scale) {
115                 if (aggr->run == 0) {
116                         evsel->counts->scaled = -1;
117                         aggr->val = 0;
118                         return 0;
119                 }
120
121                 if (aggr->run < aggr->ena) {
122                         evsel->counts->scaled = 1;
123                         aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
124                 }
125         } else
126                 aggr->ena = aggr->run = 0;
127
128         return 0;
129 }
130
131 int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus)
132 {
133         int cpu;
134
135         if (evsel->fd == NULL && perf_evsel__alloc_fd(evsel, cpus->nr, 1) < 0)
136                 return -1;
137
138         for (cpu = 0; cpu < cpus->nr; cpu++) {
139                 FD(evsel, cpu, 0) = sys_perf_event_open(&evsel->attr, -1,
140                                                         cpus->map[cpu], -1, 0);
141                 if (FD(evsel, cpu, 0) < 0)
142                         goto out_close;
143         }
144
145         return 0;
146
147 out_close:
148         while (--cpu >= 0) {
149                 close(FD(evsel, cpu, 0));
150                 FD(evsel, cpu, 0) = -1;
151         }
152         return -1;
153 }
154
155 int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads)
156 {
157         int thread;
158
159         if (evsel->fd == NULL && perf_evsel__alloc_fd(evsel, 1, threads->nr))
160                 return -1;
161
162         for (thread = 0; thread < threads->nr; thread++) {
163                 FD(evsel, 0, thread) = sys_perf_event_open(&evsel->attr,
164                                                            threads->map[thread], -1, -1, 0);
165                 if (FD(evsel, 0, thread) < 0)
166                         goto out_close;
167         }
168
169         return 0;
170
171 out_close:
172         while (--thread >= 0) {
173                 close(FD(evsel, 0, thread));
174                 FD(evsel, 0, thread) = -1;
175         }
176         return -1;
177 }
178
179 int perf_evsel__open(struct perf_evsel *evsel, 
180                      struct cpu_map *cpus, struct thread_map *threads)
181 {
182         if (threads == NULL)
183                 return perf_evsel__open_per_cpu(evsel, cpus);
184
185         return perf_evsel__open_per_thread(evsel, threads);
186 }