blob: 3e87cbd3045a4a06ab6f72087273092f5a1c3463 [file] [log] [blame]
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001#include "util/util.h"
Ingo Molnar16f762a2009-05-27 09:10:38 +02002#include "builtin.h"
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02003
4#include <libelf.h>
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -03005#include <gelf.h>
6#include <elf.h>
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03007
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -03008#include "util/list.h"
Ingo Molnara930d2c2009-05-27 09:50:13 +02009#include "util/cache.h"
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -030010#include "util/rbtree.h"
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030011
Ingo Molnar53cb8bc2009-05-26 09:17:18 +020012#include "perf.h"
13
14#include "util/parse-options.h"
15#include "util/parse-events.h"
16
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030017#define SHOW_KERNEL 1
18#define SHOW_USER 2
19#define SHOW_HV 4
20
Ingo Molnar23ac9cb2009-05-27 09:33:18 +020021static char const *input_name = "perf.data";
Peter Zijlstra450aaa22009-05-27 20:20:23 +020022static char *vmlinux = NULL;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030023static int input;
24static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
25
Ingo Molnar97b07b62009-05-26 18:48:58 +020026static int dump_trace = 0;
Ingo Molnar16f762a2009-05-27 09:10:38 +020027static int verbose;
Ingo Molnar97b07b62009-05-26 18:48:58 +020028
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030029static unsigned long page_size;
30static unsigned long mmap_window = 32;
31
Ingo Molnar53cb8bc2009-05-26 09:17:18 +020032const char *perf_event_names[] = {
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030033 [PERF_EVENT_MMAP] = " PERF_EVENT_MMAP",
34 [PERF_EVENT_MUNMAP] = " PERF_EVENT_MUNMAP",
35 [PERF_EVENT_COMM] = " PERF_EVENT_COMM",
36};
37
38struct ip_event {
39 struct perf_event_header header;
40 __u64 ip;
41 __u32 pid, tid;
42};
43struct mmap_event {
44 struct perf_event_header header;
45 __u32 pid, tid;
46 __u64 start;
47 __u64 len;
48 __u64 pgoff;
49 char filename[PATH_MAX];
50};
51struct comm_event {
52 struct perf_event_header header;
53 __u32 pid,tid;
54 char comm[16];
55};
56
57typedef union event_union {
58 struct perf_event_header header;
59 struct ip_event ip;
60 struct mmap_event mmap;
61 struct comm_event comm;
62} event_t;
63
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030064struct symbol {
Ingo Molnar16f762a2009-05-27 09:10:38 +020065 struct rb_node rb_node;
66 __u64 start;
67 __u64 end;
68 char name[0];
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030069};
70
71static struct symbol *symbol__new(uint64_t start, uint64_t len, const char *name)
72{
73 struct symbol *self = malloc(sizeof(*self) + strlen(name) + 1);
74
75 if (self != NULL) {
76 self->start = start;
77 self->end = start + len;
78 strcpy(self->name, name);
79 }
80
81 return self;
82}
83
84static void symbol__delete(struct symbol *self)
85{
86 free(self);
87}
88
89static size_t symbol__fprintf(struct symbol *self, FILE *fp)
90{
Ingo Molnar16f762a2009-05-27 09:10:38 +020091 return fprintf(fp, " %llx-%llx %s\n",
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030092 self->start, self->end, self->name);
93}
94
95struct dso {
96 struct list_head node;
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -030097 struct rb_root syms;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030098 char name[0];
99};
100
101static struct dso *dso__new(const char *name)
102{
103 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
104
105 if (self != NULL) {
106 strcpy(self->name, name);
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300107 self->syms = RB_ROOT;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300108 }
109
110 return self;
111}
112
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300113static void dso__delete_symbols(struct dso *self)
114{
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300115 struct symbol *pos;
116 struct rb_node *next = rb_first(&self->syms);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300117
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300118 while (next) {
119 pos = rb_entry(next, struct symbol, rb_node);
120 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300121 symbol__delete(pos);
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300122 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300123}
124
125static void dso__delete(struct dso *self)
126{
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300127 dso__delete_symbols(self);
128 free(self);
129}
130
131static void dso__insert_symbol(struct dso *self, struct symbol *sym)
132{
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300133 struct rb_node **p = &self->syms.rb_node;
134 struct rb_node *parent = NULL;
135 const uint64_t ip = sym->start;
136 struct symbol *s;
137
138 while (*p != NULL) {
139 parent = *p;
140 s = rb_entry(parent, struct symbol, rb_node);
141 if (ip < s->start)
142 p = &(*p)->rb_left;
143 else
144 p = &(*p)->rb_right;
145 }
146 rb_link_node(&sym->rb_node, parent, p);
147 rb_insert_color(&sym->rb_node, &self->syms);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300148}
149
150static struct symbol *dso__find_symbol(struct dso *self, uint64_t ip)
151{
Ingo Molnar16f762a2009-05-27 09:10:38 +0200152 struct rb_node *n;
153
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300154 if (self == NULL)
155 return NULL;
156
Ingo Molnar16f762a2009-05-27 09:10:38 +0200157 n = self->syms.rb_node;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300158
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300159 while (n) {
160 struct symbol *s = rb_entry(n, struct symbol, rb_node);
161
162 if (ip < s->start)
163 n = n->rb_left;
164 else if (ip > s->end)
165 n = n->rb_right;
166 else
167 return s;
168 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300169
170 return NULL;
171}
172
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300173/**
174 * elf_symtab__for_each_symbol - iterate thru all the symbols
175 *
176 * @self: struct elf_symtab instance to iterate
177 * @index: uint32_t index
178 * @sym: GElf_Sym iterator
179 */
180#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
181 for (index = 0, gelf_getsym(syms, index, &sym);\
182 index < nr_syms; \
183 index++, gelf_getsym(syms, index, &sym))
184
185static inline uint8_t elf_sym__type(const GElf_Sym *sym)
186{
187 return GELF_ST_TYPE(sym->st_info);
188}
189
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200190static inline int elf_sym__is_function(const GElf_Sym *sym)
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300191{
192 return elf_sym__type(sym) == STT_FUNC &&
193 sym->st_name != 0 &&
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200194 sym->st_shndx != SHN_UNDEF &&
195 sym->st_size != 0;
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300196}
197
198static inline const char *elf_sym__name(const GElf_Sym *sym,
199 const Elf_Data *symstrs)
200{
201 return symstrs->d_buf + sym->st_name;
202}
203
204static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
205 GElf_Shdr *shp, const char *name,
206 size_t *index)
207{
208 Elf_Scn *sec = NULL;
209 size_t cnt = 1;
210
211 while ((sec = elf_nextscn(elf, sec)) != NULL) {
212 char *str;
213
214 gelf_getshdr(sec, shp);
215 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
216 if (!strcmp(name, str)) {
217 if (index)
218 *index = cnt;
219 break;
220 }
221 ++cnt;
222 }
223
224 return sec;
225}
226
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200227static int dso__load_sym(struct dso *self, int fd, char *name)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300228{
Ingo Molnar16f762a2009-05-27 09:10:38 +0200229 Elf_Data *symstrs;
230 uint32_t nr_syms;
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200231 int err = -1;
Ingo Molnar16f762a2009-05-27 09:10:38 +0200232 uint32_t index;
233 GElf_Ehdr ehdr;
234 GElf_Shdr shdr;
235 Elf_Data *syms;
236 GElf_Sym sym;
237 Elf_Scn *sec;
238 Elf *elf;
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200239 int nr = 0;
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300240
Ingo Molnar16f762a2009-05-27 09:10:38 +0200241 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300242 if (elf == NULL) {
243 fprintf(stderr, "%s: cannot read %s ELF file.\n",
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200244 __func__, name);
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300245 goto out_close;
246 }
247
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300248 if (gelf_getehdr(elf, &ehdr) == NULL) {
249 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
250 goto out_elf_end;
251 }
252
Ingo Molnar16f762a2009-05-27 09:10:38 +0200253 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300254 if (sec == NULL)
255 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
256
257 if (sec == NULL)
258 goto out_elf_end;
259
Ingo Molnar16f762a2009-05-27 09:10:38 +0200260 syms = elf_getdata(sec, NULL);
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300261 if (syms == NULL)
262 goto out_elf_end;
263
264 sec = elf_getscn(elf, shdr.sh_link);
265 if (sec == NULL)
266 goto out_elf_end;
267
Ingo Molnar16f762a2009-05-27 09:10:38 +0200268 symstrs = elf_getdata(sec, NULL);
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300269 if (symstrs == NULL)
270 goto out_elf_end;
271
Ingo Molnar16f762a2009-05-27 09:10:38 +0200272 nr_syms = shdr.sh_size / shdr.sh_entsize;
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300273
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300274 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200275 struct symbol *f;
276
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300277 if (!elf_sym__is_function(&sym))
278 continue;
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200279
280 sec = elf_getscn(elf, sym.st_shndx);
281 if (!sec)
282 goto out_elf_end;
283
284 gelf_getshdr(sec, &shdr);
285 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
286
287 f = symbol__new(sym.st_value, sym.st_size,
288 elf_sym__name(&sym, symstrs));
289 if (!f)
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300290 goto out_elf_end;
291
292 dso__insert_symbol(self, f);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200293
294 nr++;
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300295 }
296
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200297 err = nr;
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300298out_elf_end:
299 elf_end(elf);
300out_close:
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300301 return err;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300302}
303
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200304static int dso__load(struct dso *self)
305{
306 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
307 char *name = malloc(size);
308 int variant = 0;
309 int ret = -1;
310 int fd;
311
312 if (!name)
313 return -1;
314
315more:
316 do {
317 switch (variant) {
318 case 0: /* Fedora */
319 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
320 break;
321 case 1: /* Ubuntu */
322 snprintf(name, size, "/usr/lib/debug%s", self->name);
323 break;
324 case 2: /* Sane people */
325 snprintf(name, size, "%s", self->name);
326 break;
327
328 default:
329 goto out;
330 }
331 variant++;
332
333 fd = open(name, O_RDONLY);
334 } while (fd < 0);
335
336 ret = dso__load_sym(self, fd, name);
337 close(fd);
338
339 /*
340 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
341 */
342 if (!ret)
343 goto more;
344
345out:
346 free(name);
347 return ret;
348}
349
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300350static size_t dso__fprintf(struct dso *self, FILE *fp)
351{
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300352 size_t ret = fprintf(fp, "dso: %s\n", self->name);
353
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300354 struct rb_node *nd;
355 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
356 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300357 ret += symbol__fprintf(pos, fp);
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300358 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300359
360 return ret;
361}
362
363static LIST_HEAD(dsos);
364static struct dso *kernel_dso;
365
366static void dsos__add(struct dso *dso)
367{
368 list_add_tail(&dso->node, &dsos);
369}
370
371static struct dso *dsos__find(const char *name)
372{
373 struct dso *pos;
374
375 list_for_each_entry(pos, &dsos, node)
376 if (strcmp(pos->name, name) == 0)
377 return pos;
378 return NULL;
379}
380
381static struct dso *dsos__findnew(const char *name)
382{
383 struct dso *dso = dsos__find(name);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200384 int nr;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300385
386 if (dso == NULL) {
387 dso = dso__new(name);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200388 if (!dso)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300389 goto out_delete_dso;
390
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200391 nr = dso__load(dso);
392 if (nr < 0) {
393 fprintf(stderr, "Failed to open: %s\n", name);
394 goto out_delete_dso;
395 }
396 if (!nr) {
397 fprintf(stderr,
398 "Failed to find debug symbols for: %s, maybe install a debug package?\n",
399 name);
400 }
401
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300402 dsos__add(dso);
403 }
404
405 return dso;
406
407out_delete_dso:
408 dso__delete(dso);
409 return NULL;
410}
411
Ingo Molnar16f762a2009-05-27 09:10:38 +0200412static void dsos__fprintf(FILE *fp)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300413{
414 struct dso *pos;
415
416 list_for_each_entry(pos, &dsos, node)
417 dso__fprintf(pos, fp);
418}
419
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300420static int hex(char ch)
421{
422 if ((ch >= '0') && (ch <= '9'))
423 return ch - '0';
424 if ((ch >= 'a') && (ch <= 'f'))
425 return ch - 'a' + 10;
426 if ((ch >= 'A') && (ch <= 'F'))
427 return ch - 'A' + 10;
428 return -1;
429}
430
431/*
432 * While we find nice hex chars, build a long_val.
433 * Return number of chars processed.
434 */
Ingo Molnar16f762a2009-05-27 09:10:38 +0200435static int hex2long(char *ptr, unsigned long *long_val)
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300436{
437 const char *p = ptr;
438 *long_val = 0;
439
440 while (*p) {
441 const int hex_val = hex(*p);
442
443 if (hex_val < 0)
444 break;
445
446 *long_val = (*long_val << 4) | hex_val;
447 p++;
448 }
449
450 return p - ptr;
451}
452
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300453static int load_kallsyms(void)
454{
Ingo Molnaraf836322009-05-27 08:38:48 +0200455 struct rb_node *nd, *prevnd;
456 char *line = NULL;
457 FILE *file;
458 size_t n;
459
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300460 kernel_dso = dso__new("[kernel]");
461 if (kernel_dso == NULL)
462 return -1;
463
Ingo Molnaraf836322009-05-27 08:38:48 +0200464 file = fopen("/proc/kallsyms", "r");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300465 if (file == NULL)
466 goto out_delete_dso;
467
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300468 while (!feof(file)) {
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300469 unsigned long start;
Ingo Molnaraf836322009-05-27 08:38:48 +0200470 struct symbol *sym;
471 int line_len, len;
472 char symbol_type;
473
474 line_len = getline(&line, &n, file);
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300475 if (line_len < 0)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300476 break;
477
478 if (!line)
479 goto out_delete_dso;
480
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300481 line[--line_len] = '\0'; /* \n */
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300482
Ingo Molnaraf836322009-05-27 08:38:48 +0200483 len = hex2long(line, &start);
484
Arnaldo Carvalho de Melo03f63162009-05-26 19:21:55 -0300485 len++;
486 if (len + 2 >= line_len)
487 continue;
488
Ingo Molnaraf836322009-05-27 08:38:48 +0200489 symbol_type = toupper(line[len]);
Arnaldo Carvalho de Melo03f63162009-05-26 19:21:55 -0300490 /*
491 * We're interested only in code ('T'ext)
492 */
Ingo Molnaraf836322009-05-27 08:38:48 +0200493 if (symbol_type != 'T' && symbol_type != 'W')
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300494 continue;
495 /*
496 * Well fix up the end later, when we have all sorted.
497 */
Ingo Molnaraf836322009-05-27 08:38:48 +0200498 sym = symbol__new(start, 0xdead, line + len + 2);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300499
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300500 if (sym == NULL)
501 goto out_delete_dso;
502
503 dso__insert_symbol(kernel_dso, sym);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300504 }
505
Arnaldo Carvalho de Meloabd54f62009-05-26 12:21:34 -0300506 /*
507 * Now that we have all sorted out, just set the ->end of all
508 * symbols
509 */
Ingo Molnaraf836322009-05-27 08:38:48 +0200510 prevnd = rb_first(&kernel_dso->syms);
Arnaldo Carvalho de Meloabd54f62009-05-26 12:21:34 -0300511
512 if (prevnd == NULL)
513 goto out_delete_line;
514
515 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
516 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
517 *curr = rb_entry(nd, struct symbol, rb_node);
518
519 prev->end = curr->start - 1;
520 prevnd = nd;
521 }
522
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300523 dsos__add(kernel_dso);
524 free(line);
525 fclose(file);
Ingo Molnaraf836322009-05-27 08:38:48 +0200526
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300527 return 0;
528
Arnaldo Carvalho de Melo59d81022009-05-26 11:14:27 -0300529out_delete_line:
530 free(line);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300531out_delete_dso:
532 dso__delete(kernel_dso);
533 return -1;
534}
535
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200536static int load_kernel(void)
537{
538 int fd, nr;
539
540 if (!vmlinux)
541 goto kallsyms;
542
543 fd = open(vmlinux, O_RDONLY);
544 if (fd < 0)
545 goto kallsyms;
546
547 kernel_dso = dso__new("[kernel]");
548 if (!kernel_dso)
549 goto fail_open;
550
551 nr = dso__load_sym(kernel_dso, fd, vmlinux);
552
553 if (nr <= 0)
554 goto fail_load;
555
556 dsos__add(kernel_dso);
557 close(fd);
558
559 return 0;
560
561fail_load:
562 dso__delete(kernel_dso);
563fail_open:
564 close(fd);
565kallsyms:
566 return load_kallsyms();
567}
568
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300569struct map {
570 struct list_head node;
571 uint64_t start;
572 uint64_t end;
573 uint64_t pgoff;
574 struct dso *dso;
575};
576
577static struct map *map__new(struct mmap_event *event)
578{
579 struct map *self = malloc(sizeof(*self));
580
581 if (self != NULL) {
582 self->start = event->start;
583 self->end = event->start + event->len;
584 self->pgoff = event->pgoff;
585
586 self->dso = dsos__findnew(event->filename);
587 if (self->dso == NULL)
588 goto out_delete;
589 }
590 return self;
591out_delete:
592 free(self);
593 return NULL;
594}
595
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300596struct thread;
597
598static const char *thread__name(struct thread *self, char *bf, size_t size);
599
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300600struct symhist {
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300601 struct rb_node rb_node;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300602 struct dso *dso;
603 struct symbol *sym;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300604 struct thread *thread;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300605 uint64_t ip;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300606 uint32_t count;
607 char level;
608};
609
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300610static struct symhist *symhist__new(struct symbol *sym, uint64_t ip,
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300611 struct thread *thread, struct dso *dso,
612 char level)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300613{
614 struct symhist *self = malloc(sizeof(*self));
615
616 if (self != NULL) {
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300617 self->sym = sym;
618 self->thread = thread;
619 self->ip = ip;
620 self->dso = dso;
621 self->level = level;
622 self->count = 1;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300623 }
624
625 return self;
626}
627
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300628static void symhist__inc(struct symhist *self)
629{
630 ++self->count;
631}
632
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300633static size_t
634symhist__fprintf(struct symhist *self, uint64_t total_samples, FILE *fp)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300635{
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300636 char bf[32];
637 size_t ret;
638
639 if (total_samples)
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200640 ret = fprintf(fp, "%5.2f%% ", (self->count * 100.0) / total_samples);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300641 else
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200642 ret = fprintf(fp, "%12d ", self->count);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300643
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -0300644 ret += fprintf(fp, "%14s [%c] ",
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300645 thread__name(self->thread, bf, sizeof(bf)),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -0300646 self->level);
647
648 if (verbose)
649 ret += fprintf(fp, "%#018llx ", (unsigned long long)self->ip);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300650
651 if (self->level != '.')
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300652 ret += fprintf(fp, "%s\n",
653 self->sym ? self->sym->name : "<unknown>");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300654 else
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300655 ret += fprintf(fp, "%s: %s\n",
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200656 self->dso ? self->dso->name : "<unknown>",
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300657 self->sym ? self->sym->name : "<unknown>");
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300658 return ret;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300659}
660
661struct thread {
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300662 struct rb_node rb_node;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300663 struct list_head maps;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300664 struct rb_root symhists;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300665 pid_t pid;
666 char *comm;
667};
668
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300669static const char *thread__name(struct thread *self, char *bf, size_t size)
670{
671 if (self->comm)
672 return self->comm;
673
674 snprintf(bf, sizeof(bf), ":%u", self->pid);
675 return bf;
676}
677
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300678static struct thread *thread__new(pid_t pid)
679{
680 struct thread *self = malloc(sizeof(*self));
681
682 if (self != NULL) {
683 self->pid = pid;
684 self->comm = NULL;
685 INIT_LIST_HEAD(&self->maps);
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300686 self->symhists = RB_ROOT;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300687 }
688
689 return self;
690}
691
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300692static int thread__symbol_incnew(struct thread *self, struct symbol *sym,
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300693 uint64_t ip, struct dso *dso, char level)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300694{
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300695 struct rb_node **p = &self->symhists.rb_node;
696 struct rb_node *parent = NULL;
697 struct symhist *sh;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300698
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300699 while (*p != NULL) {
Ingo Molnar16f762a2009-05-27 09:10:38 +0200700 uint64_t start;
701
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300702 parent = *p;
703 sh = rb_entry(parent, struct symhist, rb_node);
704
705 if (sh->sym == sym || ip == sh->ip) {
706 symhist__inc(sh);
707 return 0;
708 }
709
710 /* Handle unresolved symbols too */
Ingo Molnar16f762a2009-05-27 09:10:38 +0200711 start = !sh->sym ? sh->ip : sh->sym->start;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300712
713 if (ip < start)
714 p = &(*p)->rb_left;
715 else
716 p = &(*p)->rb_right;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300717 }
718
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300719 sh = symhist__new(sym, ip, self, dso, level);
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300720 if (sh == NULL)
721 return -ENOMEM;
722 rb_link_node(&sh->rb_node, parent, p);
723 rb_insert_color(&sh->rb_node, &self->symhists);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300724 return 0;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300725}
726
727static int thread__set_comm(struct thread *self, const char *comm)
728{
729 self->comm = strdup(comm);
730 return self->comm ? 0 : -ENOMEM;
731}
732
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300733static size_t thread__fprintf(struct thread *self, FILE *fp)
734{
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300735 int ret = fprintf(fp, "thread: %d %s\n", self->pid, self->comm);
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300736 struct rb_node *nd;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300737
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300738 for (nd = rb_first(&self->symhists); nd; nd = rb_next(nd)) {
739 struct symhist *pos = rb_entry(nd, struct symhist, rb_node);
Ingo Molnar16f762a2009-05-27 09:10:38 +0200740
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300741 ret += symhist__fprintf(pos, 0, fp);
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300742 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300743
744 return ret;
745}
746
Ingo Molnar16f762a2009-05-27 09:10:38 +0200747static struct rb_root threads;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300748
749static struct thread *threads__findnew(pid_t pid)
750{
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300751 struct rb_node **p = &threads.rb_node;
752 struct rb_node *parent = NULL;
753 struct thread *th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300754
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300755 while (*p != NULL) {
756 parent = *p;
757 th = rb_entry(parent, struct thread, rb_node);
758
759 if (th->pid == pid)
760 return th;
761
762 if (pid < th->pid)
763 p = &(*p)->rb_left;
764 else
765 p = &(*p)->rb_right;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300766 }
767
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300768 th = thread__new(pid);
769 if (th != NULL) {
770 rb_link_node(&th->rb_node, parent, p);
771 rb_insert_color(&th->rb_node, &threads);
772 }
773 return th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300774}
775
776static void thread__insert_map(struct thread *self, struct map *map)
777{
778 list_add_tail(&map->node, &self->maps);
779}
780
781static struct map *thread__find_map(struct thread *self, uint64_t ip)
782{
Ingo Molnar16f762a2009-05-27 09:10:38 +0200783 struct map *pos;
784
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300785 if (self == NULL)
786 return NULL;
787
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300788 list_for_each_entry(pos, &self->maps, node)
789 if (ip >= pos->start && ip <= pos->end)
790 return pos;
791
792 return NULL;
793}
794
Ingo Molnar16f762a2009-05-27 09:10:38 +0200795static void threads__fprintf(FILE *fp)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300796{
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300797 struct rb_node *nd;
798 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
799 struct thread *pos = rb_entry(nd, struct thread, rb_node);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300800 thread__fprintf(pos, fp);
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300801 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300802}
803
Ingo Molnar16f762a2009-05-27 09:10:38 +0200804static struct rb_root global_symhists;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300805
806static void threads__insert_symhist(struct symhist *sh)
807{
808 struct rb_node **p = &global_symhists.rb_node;
809 struct rb_node *parent = NULL;
810 struct symhist *iter;
811
812 while (*p != NULL) {
813 parent = *p;
814 iter = rb_entry(parent, struct symhist, rb_node);
815
816 /* Reverse order */
817 if (sh->count > iter->count)
818 p = &(*p)->rb_left;
819 else
820 p = &(*p)->rb_right;
821 }
822
823 rb_link_node(&sh->rb_node, parent, p);
824 rb_insert_color(&sh->rb_node, &global_symhists);
825}
826
827static void threads__sort_symhists(void)
828{
829 struct rb_node *nd;
830
831 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
832 struct thread *thread = rb_entry(nd, struct thread, rb_node);
833 struct rb_node *next = rb_first(&thread->symhists);
834
835 while (next) {
836 struct symhist *n = rb_entry(next, struct symhist,
837 rb_node);
838 next = rb_next(&n->rb_node);
839 rb_erase(&n->rb_node, &thread->symhists);
840 threads__insert_symhist(n);
841 }
842
843 }
844}
845
846static size_t threads__symhists_fprintf(uint64_t total_samples, FILE *fp)
847{
848 struct rb_node *nd;
849 size_t ret = 0;
850
851 for (nd = rb_first(&global_symhists); nd; nd = rb_next(nd)) {
852 struct symhist *pos = rb_entry(nd, struct symhist, rb_node);
853 ret += symhist__fprintf(pos, total_samples, fp);
854 }
855
856 return ret;
857}
858
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200859static int __cmd_report(void)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300860{
861 unsigned long offset = 0;
862 unsigned long head = 0;
863 struct stat stat;
864 char *buf;
865 event_t *event;
866 int ret, rc = EXIT_FAILURE;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200867 uint32_t size;
Ingo Molnarf49515b2009-05-26 19:03:36 +0200868 unsigned long total = 0, total_mmap = 0, total_comm = 0, total_unknown = 0;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300869
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300870 input = open(input_name, O_RDONLY);
871 if (input < 0) {
872 perror("failed to open file");
873 exit(-1);
874 }
875
876 ret = fstat(input, &stat);
877 if (ret < 0) {
878 perror("failed to stat file");
879 exit(-1);
880 }
881
882 if (!stat.st_size) {
883 fprintf(stderr, "zero-sized file, nothing to do!\n");
884 exit(0);
885 }
886
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200887 if (load_kernel() < 0) {
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300888 perror("failed to open kallsyms");
889 return EXIT_FAILURE;
890 }
891
892remap:
893 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
894 MAP_SHARED, input, offset);
895 if (buf == MAP_FAILED) {
896 perror("failed to mmap file");
897 exit(-1);
898 }
899
900more:
901 event = (event_t *)(buf + head);
902
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200903 size = event->header.size;
904 if (!size)
905 size = 8;
906
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300907 if (head + event->header.size >= page_size * mmap_window) {
908 unsigned long shift = page_size * (head / page_size);
909 int ret;
910
911 ret = munmap(buf, page_size * mmap_window);
912 assert(ret == 0);
913
914 offset += shift;
915 head -= shift;
916 goto remap;
917 }
918
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200919 size = event->header.size;
920 if (!size)
921 goto broken_event;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300922
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300923 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
924 char level;
925 int show = 0;
926 struct dso *dso = NULL;
927 struct thread *thread = threads__findnew(event->ip.pid);
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200928 uint64_t ip = event->ip.ip;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300929
Ingo Molnar97b07b62009-05-26 18:48:58 +0200930 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200931 fprintf(stderr, "%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
932 (void *)(offset + head),
933 (void *)(long)(event->header.size),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200934 event->header.misc,
935 event->ip.pid,
Ingo Molnar16f762a2009-05-27 09:10:38 +0200936 (void *)(long)ip);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200937 }
938
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300939 if (thread == NULL) {
940 fprintf(stderr, "problem processing %d event, bailing out\n",
941 event->header.type);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300942 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300943 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300944
945 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
946 show = SHOW_KERNEL;
947 level = 'k';
948 dso = kernel_dso;
949 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
Ingo Molnar16f762a2009-05-27 09:10:38 +0200950 struct map *map;
951
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300952 show = SHOW_USER;
953 level = '.';
Ingo Molnar16f762a2009-05-27 09:10:38 +0200954
955 map = thread__find_map(thread, ip);
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200956 if (map != NULL) {
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300957 dso = map->dso;
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200958 ip -= map->start + map->pgoff;
959 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300960 } else {
961 show = SHOW_HV;
962 level = 'H';
963 }
964
965 if (show & show_mask) {
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200966 struct symbol *sym = dso__find_symbol(dso, ip);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300967
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200968 if (thread__symbol_incnew(thread, sym, ip, dso, level)) {
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300969 fprintf(stderr, "problem incrementing symbol count, bailing out\n");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300970 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300971 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300972 }
973 total++;
974 } else switch (event->header.type) {
975 case PERF_EVENT_MMAP: {
976 struct thread *thread = threads__findnew(event->mmap.pid);
977 struct map *map = map__new(&event->mmap);
978
Ingo Molnar97b07b62009-05-26 18:48:58 +0200979 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200980 fprintf(stderr, "%p [%p]: PERF_EVENT_MMAP: [%p(%p) @ %p]: %s\n",
981 (void *)(offset + head),
982 (void *)(long)(event->header.size),
Ingo Molnar16f762a2009-05-27 09:10:38 +0200983 (void *)(long)event->mmap.start,
984 (void *)(long)event->mmap.len,
985 (void *)(long)event->mmap.pgoff,
Ingo Molnar97b07b62009-05-26 18:48:58 +0200986 event->mmap.filename);
987 }
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300988 if (thread == NULL || map == NULL) {
989 fprintf(stderr, "problem processing PERF_EVENT_MMAP, bailing out\n");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300990 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300991 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300992 thread__insert_map(thread, map);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200993 total_mmap++;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300994 break;
995 }
996 case PERF_EVENT_COMM: {
997 struct thread *thread = threads__findnew(event->comm.pid);
998
Ingo Molnar97b07b62009-05-26 18:48:58 +0200999 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +02001000 fprintf(stderr, "%p [%p]: PERF_EVENT_COMM: %s:%d\n",
1001 (void *)(offset + head),
1002 (void *)(long)(event->header.size),
Ingo Molnar97b07b62009-05-26 18:48:58 +02001003 event->comm.comm, event->comm.pid);
1004 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001005 if (thread == NULL ||
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -03001006 thread__set_comm(thread, event->comm.comm)) {
1007 fprintf(stderr, "problem processing PERF_EVENT_COMM, bailing out\n");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001008 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -03001009 }
Ingo Molnar97b07b62009-05-26 18:48:58 +02001010 total_comm++;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001011 break;
1012 }
Ingo Molnar97b07b62009-05-26 18:48:58 +02001013 default: {
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001014broken_event:
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +02001015 if (dump_trace)
1016 fprintf(stderr, "%p [%p]: skipping unknown header type: %d\n",
1017 (void *)(offset + head),
1018 (void *)(long)(event->header.size),
1019 event->header.type);
1020
Ingo Molnar3e706112009-05-26 18:53:17 +02001021 total_unknown++;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001022
1023 /*
1024 * assume we lost track of the stream, check alignment, and
1025 * increment a single u64 in the hope to catch on again 'soon'.
1026 */
1027
1028 if (unlikely(head & 7))
1029 head &= ~7ULL;
1030
1031 size = 8;
Ingo Molnar97b07b62009-05-26 18:48:58 +02001032 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001033 }
1034
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001035 head += size;
Ingo Molnarf49515b2009-05-26 19:03:36 +02001036
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001037 if (offset + head < stat.st_size)
1038 goto more;
1039
1040 rc = EXIT_SUCCESS;
1041done:
1042 close(input);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001043
1044 if (dump_trace) {
Ingo Molnar3e706112009-05-26 18:53:17 +02001045 fprintf(stderr, " IP events: %10ld\n", total);
1046 fprintf(stderr, " mmap events: %10ld\n", total_mmap);
1047 fprintf(stderr, " comm events: %10ld\n", total_comm);
1048 fprintf(stderr, " unknown events: %10ld\n", total_unknown);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001049
1050 return 0;
1051 }
1052
Ingo Molnar16f762a2009-05-27 09:10:38 +02001053 if (verbose >= 2) {
1054 dsos__fprintf(stdout);
1055 threads__fprintf(stdout);
1056 }
1057
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001058 threads__sort_symhists();
1059 threads__symhists_fprintf(total, stdout);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001060
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001061 return rc;
1062}
1063
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001064static const char * const report_usage[] = {
1065 "perf report [<options>] <command>",
1066 NULL
1067};
1068
1069static const struct option options[] = {
1070 OPT_STRING('i', "input", &input_name, "file",
1071 "input file name"),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -03001072 OPT_BOOLEAN('v', "verbose", &verbose,
1073 "be more verbose (show symbol address, etc)"),
Ingo Molnar97b07b62009-05-26 18:48:58 +02001074 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1075 "dump raw trace in ASCII"),
Peter Zijlstra450aaa22009-05-27 20:20:23 +02001076 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001077 OPT_END()
1078};
1079
1080int cmd_report(int argc, const char **argv, const char *prefix)
1081{
1082 elf_version(EV_CURRENT);
1083
1084 page_size = getpagesize();
1085
1086 parse_options(argc, argv, options, report_usage, 0);
1087
Ingo Molnara930d2c2009-05-27 09:50:13 +02001088 setup_pager();
1089
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001090 return __cmd_report();
1091}