Merge branch 'fix/asoc' into for-linus
[pandora-kernel.git] / tools / perf / util / event.c
1 #include <linux/types.h>
2 #include "event.h"
3 #include "debug.h"
4 #include "string.h"
5 #include "thread.h"
6
7 static pid_t event__synthesize_comm(pid_t pid, int full,
8                                     int (*process)(event_t *event))
9 {
10         event_t ev;
11         char filename[PATH_MAX];
12         char bf[BUFSIZ];
13         FILE *fp;
14         size_t size = 0;
15         DIR *tasks;
16         struct dirent dirent, *next;
17         pid_t tgid = 0;
18
19         snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
20
21         fp = fopen(filename, "r");
22         if (fp == NULL) {
23 out_race:
24                 /*
25                  * We raced with a task exiting - just return:
26                  */
27                 pr_debug("couldn't open %s\n", filename);
28                 return 0;
29         }
30
31         memset(&ev.comm, 0, sizeof(ev.comm));
32         while (!ev.comm.comm[0] || !ev.comm.pid) {
33                 if (fgets(bf, sizeof(bf), fp) == NULL)
34                         goto out_failure;
35
36                 if (memcmp(bf, "Name:", 5) == 0) {
37                         char *name = bf + 5;
38                         while (*name && isspace(*name))
39                                 ++name;
40                         size = strlen(name) - 1;
41                         memcpy(ev.comm.comm, name, size++);
42                 } else if (memcmp(bf, "Tgid:", 5) == 0) {
43                         char *tgids = bf + 5;
44                         while (*tgids && isspace(*tgids))
45                                 ++tgids;
46                         tgid = ev.comm.pid = atoi(tgids);
47                 }
48         }
49
50         ev.comm.header.type = PERF_RECORD_COMM;
51         size = ALIGN(size, sizeof(u64));
52         ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
53
54         if (!full) {
55                 ev.comm.tid = pid;
56
57                 process(&ev);
58                 goto out_fclose;
59         }
60
61         snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
62
63         tasks = opendir(filename);
64         if (tasks == NULL)
65                 goto out_race;
66
67         while (!readdir_r(tasks, &dirent, &next) && next) {
68                 char *end;
69                 pid = strtol(dirent.d_name, &end, 10);
70                 if (*end)
71                         continue;
72
73                 ev.comm.tid = pid;
74
75                 process(&ev);
76         }
77         closedir(tasks);
78
79 out_fclose:
80         fclose(fp);
81         return tgid;
82
83 out_failure:
84         pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
85         return -1;
86 }
87
88 static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
89                                          int (*process)(event_t *event))
90 {
91         char filename[PATH_MAX];
92         FILE *fp;
93
94         snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
95
96         fp = fopen(filename, "r");
97         if (fp == NULL) {
98                 /*
99                  * We raced with a task exiting - just return:
100                  */
101                 pr_debug("couldn't open %s\n", filename);
102                 return -1;
103         }
104
105         while (1) {
106                 char bf[BUFSIZ], *pbf = bf;
107                 event_t ev = {
108                         .header = { .type = PERF_RECORD_MMAP },
109                 };
110                 int n;
111                 size_t size;
112                 if (fgets(bf, sizeof(bf), fp) == NULL)
113                         break;
114
115                 /* 00400000-0040c000 r-xp 00000000 fd:01 41038  /bin/cat */
116                 n = hex2u64(pbf, &ev.mmap.start);
117                 if (n < 0)
118                         continue;
119                 pbf += n + 1;
120                 n = hex2u64(pbf, &ev.mmap.len);
121                 if (n < 0)
122                         continue;
123                 pbf += n + 3;
124                 if (*pbf == 'x') { /* vm_exec */
125                         char *execname = strchr(bf, '/');
126
127                         /* Catch VDSO */
128                         if (execname == NULL)
129                                 execname = strstr(bf, "[vdso]");
130
131                         if (execname == NULL)
132                                 continue;
133
134                         size = strlen(execname);
135                         execname[size - 1] = '\0'; /* Remove \n */
136                         memcpy(ev.mmap.filename, execname, size);
137                         size = ALIGN(size, sizeof(u64));
138                         ev.mmap.len -= ev.mmap.start;
139                         ev.mmap.header.size = (sizeof(ev.mmap) -
140                                                (sizeof(ev.mmap.filename) - size));
141                         ev.mmap.pid = tgid;
142                         ev.mmap.tid = pid;
143
144                         process(&ev);
145                 }
146         }
147
148         fclose(fp);
149         return 0;
150 }
151
152 int event__synthesize_thread(pid_t pid, int (*process)(event_t *event))
153 {
154         pid_t tgid = event__synthesize_comm(pid, 1, process);
155         if (tgid == -1)
156                 return -1;
157         return event__synthesize_mmap_events(pid, tgid, process);
158 }
159
160 void event__synthesize_threads(int (*process)(event_t *event))
161 {
162         DIR *proc;
163         struct dirent dirent, *next;
164
165         proc = opendir("/proc");
166
167         while (!readdir_r(proc, &dirent, &next) && next) {
168                 char *end;
169                 pid_t pid = strtol(dirent.d_name, &end, 10);
170
171                 if (*end) /* only interested in proper numerical dirents */
172                         continue;
173
174                 event__synthesize_thread(pid, process);
175         }
176
177         closedir(proc);
178 }
179
180 char *event__cwd;
181 int  event__cwdlen;
182
183 struct events_stats event__stats;
184
185 int event__process_comm(event_t *self)
186 {
187         struct thread *thread = threads__findnew(self->comm.pid);
188
189         dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
190
191         if (thread == NULL || thread__set_comm(thread, self->comm.comm)) {
192                 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
193                 return -1;
194         }
195
196         return 0;
197 }
198
199 int event__process_lost(event_t *self)
200 {
201         dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
202         event__stats.lost += self->lost.lost;
203         return 0;
204 }
205
206 int event__process_mmap(event_t *self)
207 {
208         struct thread *thread = threads__findnew(self->mmap.pid);
209         struct map *map = map__new(&self->mmap, MAP__FUNCTION,
210                                    event__cwd, event__cwdlen);
211
212         dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
213                     self->mmap.pid, self->mmap.tid,
214                     (void *)(long)self->mmap.start,
215                     (void *)(long)self->mmap.len,
216                     (void *)(long)self->mmap.pgoff,
217                     self->mmap.filename);
218
219         if (thread == NULL || map == NULL)
220                 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
221         else
222                 thread__insert_map(thread, map);
223
224         return 0;
225 }
226
227 int event__process_task(event_t *self)
228 {
229         struct thread *thread = threads__findnew(self->fork.pid);
230         struct thread *parent = threads__findnew(self->fork.ppid);
231
232         dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
233                     self->fork.ppid, self->fork.ptid);
234         /*
235          * A thread clone will have the same PID for both parent and child.
236          */
237         if (thread == parent)
238                 return 0;
239
240         if (self->header.type == PERF_RECORD_EXIT)
241                 return 0;
242
243         if (thread == NULL || parent == NULL ||
244             thread__fork(thread, parent) < 0) {
245                 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
246                 return -1;
247         }
248
249         return 0;
250 }
251
252 void thread__find_addr_location(struct thread *self, u8 cpumode,
253                                 enum map_type type, u64 addr,
254                                 struct addr_location *al,
255                                 symbol_filter_t filter)
256 {
257         struct thread *thread = al->thread = self;
258
259         al->addr = addr;
260
261         if (cpumode & PERF_RECORD_MISC_KERNEL) {
262                 al->level = 'k';
263                 thread = kthread;
264         } else if (cpumode & PERF_RECORD_MISC_USER)
265                 al->level = '.';
266         else {
267                 al->level = 'H';
268                 al->map = NULL;
269                 al->sym = NULL;
270                 return;
271         }
272 try_again:
273         al->map = thread__find_map(thread, type, al->addr);
274         if (al->map == NULL) {
275                 /*
276                  * If this is outside of all known maps, and is a negative
277                  * address, try to look it up in the kernel dso, as it might be
278                  * a vsyscall or vdso (which executes in user-mode).
279                  *
280                  * XXX This is nasty, we should have a symbol list in the
281                  * "[vdso]" dso, but for now lets use the old trick of looking
282                  * in the whole kernel symbol list.
283                  */
284                 if ((long long)al->addr < 0 && thread != kthread) {
285                         thread = kthread;
286                         goto try_again;
287                 }
288                 al->sym = NULL;
289         } else {
290                 al->addr = al->map->map_ip(al->map, al->addr);
291                 al->sym = map__find_symbol(al->map, al->addr, filter);
292         }
293 }
294
295 int event__preprocess_sample(const event_t *self, struct addr_location *al,
296                              symbol_filter_t filter)
297 {
298         u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
299         struct thread *thread = threads__findnew(self->ip.pid);
300
301         if (thread == NULL)
302                 return -1;
303
304         dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
305
306         thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
307                                    self->ip.ip, al, filter);
308         dump_printf(" ...... dso: %s\n",
309                     al->map ? al->map->dso->long_name :
310                         al->level == 'H' ? "[hypervisor]" : "<not found>");
311         return 0;
312 }
313
314 int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
315 {
316         u64 *array = event->sample.array;
317
318         if (type & PERF_SAMPLE_IP) {
319                 data->ip = event->ip.ip;
320                 array++;
321         }
322
323         if (type & PERF_SAMPLE_TID) {
324                 u32 *p = (u32 *)array;
325                 data->pid = p[0];
326                 data->tid = p[1];
327                 array++;
328         }
329
330         if (type & PERF_SAMPLE_TIME) {
331                 data->time = *array;
332                 array++;
333         }
334
335         if (type & PERF_SAMPLE_ADDR) {
336                 data->addr = *array;
337                 array++;
338         }
339
340         if (type & PERF_SAMPLE_ID) {
341                 data->id = *array;
342                 array++;
343         }
344
345         if (type & PERF_SAMPLE_STREAM_ID) {
346                 data->stream_id = *array;
347                 array++;
348         }
349
350         if (type & PERF_SAMPLE_CPU) {
351                 u32 *p = (u32 *)array;
352                 data->cpu = *p;
353                 array++;
354         }
355
356         if (type & PERF_SAMPLE_PERIOD) {
357                 data->period = *array;
358                 array++;
359         }
360
361         if (type & PERF_SAMPLE_READ) {
362                 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
363                 return -1;
364         }
365
366         if (type & PERF_SAMPLE_CALLCHAIN) {
367                 data->callchain = (struct ip_callchain *)array;
368                 array += 1 + data->callchain->nr;
369         }
370
371         if (type & PERF_SAMPLE_RAW) {
372                 u32 *p = (u32 *)array;
373                 data->raw_size = *p;
374                 p++;
375                 data->raw_data = p;
376         }
377
378         return 0;
379 }