08c4cf5e66baf7e8fe1418da6162b62f476538ed
[pandora-kernel.git] / tools / perf / util / data_map.c
1 #include "symbol.h"
2 #include "util.h"
3 #include "debug.h"
4 #include "thread.h"
5 #include "session.h"
6
7 static int process_event_stub(event_t *event __used,
8                               struct perf_session *session __used)
9 {
10         dump_printf(": unhandled!\n");
11         return 0;
12 }
13
14 static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
15 {
16         if (!handler->process_sample_event)
17                 handler->process_sample_event = process_event_stub;
18         if (!handler->process_mmap_event)
19                 handler->process_mmap_event = process_event_stub;
20         if (!handler->process_comm_event)
21                 handler->process_comm_event = process_event_stub;
22         if (!handler->process_fork_event)
23                 handler->process_fork_event = process_event_stub;
24         if (!handler->process_exit_event)
25                 handler->process_exit_event = process_event_stub;
26         if (!handler->process_lost_event)
27                 handler->process_lost_event = process_event_stub;
28         if (!handler->process_read_event)
29                 handler->process_read_event = process_event_stub;
30         if (!handler->process_throttle_event)
31                 handler->process_throttle_event = process_event_stub;
32         if (!handler->process_unthrottle_event)
33                 handler->process_unthrottle_event = process_event_stub;
34 }
35
36 static const char *event__name[] = {
37         [0]                      = "TOTAL",
38         [PERF_RECORD_MMAP]       = "MMAP",
39         [PERF_RECORD_LOST]       = "LOST",
40         [PERF_RECORD_COMM]       = "COMM",
41         [PERF_RECORD_EXIT]       = "EXIT",
42         [PERF_RECORD_THROTTLE]   = "THROTTLE",
43         [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
44         [PERF_RECORD_FORK]       = "FORK",
45         [PERF_RECORD_READ]       = "READ",
46         [PERF_RECORD_SAMPLE]     = "SAMPLE",
47 };
48
49 unsigned long event__total[PERF_RECORD_MAX];
50
51 void event__print_totals(void)
52 {
53         int i;
54         for (i = 0; i < PERF_RECORD_MAX; ++i)
55                 pr_info("%10s events: %10ld\n",
56                         event__name[i], event__total[i]);
57 }
58
59 static int process_event(event_t *event, struct perf_session *session,
60                          struct perf_event_ops *ops,
61                          unsigned long offset, unsigned long head)
62 {
63         trace_event(event);
64
65         if (event->header.type < PERF_RECORD_MAX) {
66                 dump_printf("%p [%p]: PERF_RECORD_%s",
67                             (void *)(offset + head),
68                             (void *)(long)(event->header.size),
69                             event__name[event->header.type]);
70                 ++event__total[0];
71                 ++event__total[event->header.type];
72         }
73
74         switch (event->header.type) {
75         case PERF_RECORD_SAMPLE:
76                 return ops->process_sample_event(event, session);
77         case PERF_RECORD_MMAP:
78                 return ops->process_mmap_event(event, session);
79         case PERF_RECORD_COMM:
80                 return ops->process_comm_event(event, session);
81         case PERF_RECORD_FORK:
82                 return ops->process_fork_event(event, session);
83         case PERF_RECORD_EXIT:
84                 return ops->process_exit_event(event, session);
85         case PERF_RECORD_LOST:
86                 return ops->process_lost_event(event, session);
87         case PERF_RECORD_READ:
88                 return ops->process_read_event(event, session);
89         case PERF_RECORD_THROTTLE:
90                 return ops->process_throttle_event(event, session);
91         case PERF_RECORD_UNTHROTTLE:
92                 return ops->process_unthrottle_event(event, session);
93         default:
94                 ops->total_unknown++;
95                 return -1;
96         }
97 }
98
99 int perf_header__read_build_ids(int input, u64 offset, u64 size)
100 {
101         struct build_id_event bev;
102         char filename[PATH_MAX];
103         u64 limit = offset + size;
104         int err = -1;
105
106         while (offset < limit) {
107                 struct dso *dso;
108                 ssize_t len;
109
110                 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
111                         goto out;
112
113                 len = bev.header.size - sizeof(bev);
114                 if (read(input, filename, len) != len)
115                         goto out;
116
117                 dso = dsos__findnew(filename);
118                 if (dso != NULL)
119                         dso__set_build_id(dso, &bev.build_id);
120
121                 offset += bev.header.size;
122         }
123         err = 0;
124 out:
125         return err;
126 }
127
128 static struct thread *perf_session__register_idle_thread(struct perf_session *self)
129 {
130         struct thread *thread = perf_session__findnew(self, 0);
131
132         if (!thread || thread__set_comm(thread, "swapper")) {
133                 pr_err("problem inserting idle task.\n");
134                 thread = NULL;
135         }
136
137         return thread;
138 }
139
140 int perf_session__process_events(struct perf_session *self,
141                                  struct perf_event_ops *ops)
142 {
143         int err;
144         unsigned long head, shift;
145         unsigned long offset = 0;
146         size_t  page_size;
147         u64 sample_type;
148         event_t *event;
149         uint32_t size;
150         char *buf;
151
152         if (perf_session__register_idle_thread(self) == NULL)
153                 return -ENOMEM;
154
155         perf_event_ops__fill_defaults(ops);
156
157         page_size = getpagesize();
158
159         head = self->header.data_offset;
160         sample_type = perf_header__sample_type(&self->header);
161
162         err = -EINVAL;
163         if (ops->sample_type_check &&
164             ops->sample_type_check(sample_type, self) < 0)
165                 goto out_err;
166
167         if (!ops->full_paths) {
168                 char bf[PATH_MAX];
169
170                 if (getcwd(bf, sizeof(bf)) == NULL) {
171                         err = -errno;
172 out_getcwd_err:
173                         pr_err("failed to get the current directory\n");
174                         goto out_err;
175                 }
176                 self->cwd = strdup(bf);
177                 if (self->cwd == NULL) {
178                         err = -ENOMEM;
179                         goto out_getcwd_err;
180                 }
181                 self->cwdlen = strlen(self->cwd);
182         }
183
184         shift = page_size * (head / page_size);
185         offset += shift;
186         head -= shift;
187
188 remap:
189         buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
190                    MAP_SHARED, self->fd, offset);
191         if (buf == MAP_FAILED) {
192                 pr_err("failed to mmap file\n");
193                 err = -errno;
194                 goto out_err;
195         }
196
197 more:
198         event = (event_t *)(buf + head);
199
200         size = event->header.size;
201         if (!size)
202                 size = 8;
203
204         if (head + event->header.size >= page_size * self->mmap_window) {
205                 int munmap_ret;
206
207                 shift = page_size * (head / page_size);
208
209                 munmap_ret = munmap(buf, page_size * self->mmap_window);
210                 assert(munmap_ret == 0);
211
212                 offset += shift;
213                 head -= shift;
214                 goto remap;
215         }
216
217         size = event->header.size;
218
219         dump_printf("\n%p [%p]: event: %d\n",
220                         (void *)(offset + head),
221                         (void *)(long)event->header.size,
222                         event->header.type);
223
224         if (!size || process_event(event, self, ops, offset, head) < 0) {
225
226                 dump_printf("%p [%p]: skipping unknown header type: %d\n",
227                         (void *)(offset + head),
228                         (void *)(long)(event->header.size),
229                         event->header.type);
230
231                 /*
232                  * assume we lost track of the stream, check alignment, and
233                  * increment a single u64 in the hope to catch on again 'soon'.
234                  */
235
236                 if (unlikely(head & 7))
237                         head &= ~7ULL;
238
239                 size = 8;
240         }
241
242         head += size;
243
244         if (offset + head >= self->header.data_offset + self->header.data_size)
245                 goto done;
246
247         if (offset + head < self->size)
248                 goto more;
249
250 done:
251         err = 0;
252 out_err:
253         return err;
254 }