blob: 856186fd2bd4cd47dd756529d591e468928b712d [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 thread {
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 list_head maps;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300603 pid_t pid;
604 char *comm;
605};
606
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300607static const char *thread__name(struct thread *self, char *bf, size_t size)
608{
609 if (self->comm)
610 return self->comm;
611
612 snprintf(bf, sizeof(bf), ":%u", self->pid);
613 return bf;
614}
615
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300616static struct thread *thread__new(pid_t pid)
617{
618 struct thread *self = malloc(sizeof(*self));
619
620 if (self != NULL) {
621 self->pid = pid;
622 self->comm = NULL;
623 INIT_LIST_HEAD(&self->maps);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300624 }
625
626 return self;
627}
628
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300629static int thread__set_comm(struct thread *self, const char *comm)
630{
631 self->comm = strdup(comm);
632 return self->comm ? 0 : -ENOMEM;
633}
634
Ingo Molnar16f762a2009-05-27 09:10:38 +0200635static struct rb_root threads;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300636
637static struct thread *threads__findnew(pid_t pid)
638{
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300639 struct rb_node **p = &threads.rb_node;
640 struct rb_node *parent = NULL;
641 struct thread *th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300642
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300643 while (*p != NULL) {
644 parent = *p;
645 th = rb_entry(parent, struct thread, rb_node);
646
647 if (th->pid == pid)
648 return th;
649
650 if (pid < th->pid)
651 p = &(*p)->rb_left;
652 else
653 p = &(*p)->rb_right;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300654 }
655
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300656 th = thread__new(pid);
657 if (th != NULL) {
658 rb_link_node(&th->rb_node, parent, p);
659 rb_insert_color(&th->rb_node, &threads);
660 }
661 return th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300662}
663
664static void thread__insert_map(struct thread *self, struct map *map)
665{
666 list_add_tail(&map->node, &self->maps);
667}
668
669static struct map *thread__find_map(struct thread *self, uint64_t ip)
670{
Ingo Molnar16f762a2009-05-27 09:10:38 +0200671 struct map *pos;
672
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300673 if (self == NULL)
674 return NULL;
675
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300676 list_for_each_entry(pos, &self->maps, node)
677 if (ip >= pos->start && ip <= pos->end)
678 return pos;
679
680 return NULL;
681}
682
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200683/*
684 * histogram, sorted on item, collects counts
685 */
686
687static struct rb_root hist;
688
689struct hist_entry {
690 struct rb_node rb_node;
691
692 struct thread *thread;
693 struct map *map;
694 struct dso *dso;
695 struct symbol *sym;
696 uint64_t ip;
697 char level;
698
699 uint32_t count;
700};
701
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200702/*
703 * configurable sorting bits
704 */
705
706struct sort_entry {
707 struct list_head list;
708
709 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
710 size_t (*print)(FILE *fp, struct hist_entry *);
711};
712
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200713static int64_t
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200714sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
715{
716 return right->thread->pid - left->thread->pid;
717}
718
719static size_t
720sort__thread_print(FILE *fp, struct hist_entry *self)
721{
722 char bf[32];
723
724 return fprintf(fp, "%14s ",
725 thread__name(self->thread, bf, sizeof(bf)));
726}
727
728static struct sort_entry sort_thread = {
729 .cmp = sort__thread_cmp,
730 .print = sort__thread_print,
731};
732
733static int64_t
734sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300735{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200736 uint64_t ip_l, ip_r;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200737
738 if (left->sym == right->sym)
739 return 0;
740
741 ip_l = left->sym ? left->sym->start : left->ip;
742 ip_r = right->sym ? right->sym->start : right->ip;
743
744 return (int64_t)(ip_r - ip_l);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300745}
746
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200747static size_t
748sort__sym_print(FILE *fp, struct hist_entry *self)
749{
750 size_t ret = 0;
751
752 ret += fprintf(fp, "[%c] ", self->level);
753
754 if (verbose)
755 ret += fprintf(fp, "%#018llx ", (unsigned long long)self->ip);
756
757 if (self->level != '.')
758 ret += fprintf(fp, "%s ",
759 self->sym ? self->sym->name : "<unknown>");
760 else
761 ret += fprintf(fp, "%s: %s ",
762 self->dso ? self->dso->name : "<unknown>",
763 self->sym ? self->sym->name : "<unknown>");
764
765 return ret;
766}
767
768static struct sort_entry sort_sym = {
769 .cmp = sort__sym_cmp,
770 .print = sort__sym_print,
771};
772
773static LIST_HEAD(hist_entry__sort_list);
774
775static void setup_sorting(void)
776{
777 list_add_tail(&sort_thread.list, &hist_entry__sort_list);
778 list_add_tail(&sort_sym.list, &hist_entry__sort_list);
779}
780
781static int64_t
782hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
783{
784 struct sort_entry *se;
785 int64_t cmp = 0;
786
787 list_for_each_entry(se, &hist_entry__sort_list, list) {
788 cmp = se->cmp(left, right);
789 if (cmp)
790 break;
791 }
792
793 return cmp;
794}
795
796static size_t
797hist_entry__fprintf(FILE *fp, struct hist_entry *self, uint64_t total_samples)
798{
799 struct sort_entry *se;
800 size_t ret;
801
802 if (total_samples) {
803 ret = fprintf(fp, "%5.2f%% ",
804 (self->count * 100.0) / total_samples);
805 } else
806 ret = fprintf(fp, "%12d ", self->count);
807
808 list_for_each_entry(se, &hist_entry__sort_list, list)
809 ret += se->print(fp, self);
810
811 ret += fprintf(fp, "\n");
812
813 return ret;
814}
815
816/*
817 * collect histogram counts
818 */
819
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200820static int
821hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
822 struct symbol *sym, uint64_t ip, char level)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300823{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200824 struct rb_node **p = &hist.rb_node;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300825 struct rb_node *parent = NULL;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200826 struct hist_entry *he;
827 struct hist_entry entry = {
828 .thread = thread,
829 .map = map,
830 .dso = dso,
831 .sym = sym,
832 .ip = ip,
833 .level = level,
834 .count = 1,
835 };
836 int cmp;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300837
838 while (*p != NULL) {
839 parent = *p;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200840 he = rb_entry(parent, struct hist_entry, rb_node);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300841
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200842 cmp = hist_entry__cmp(&entry, he);
843
844 if (!cmp) {
845 he->count++;
846 return 0;
847 }
848
849 if (cmp < 0)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300850 p = &(*p)->rb_left;
851 else
852 p = &(*p)->rb_right;
853 }
854
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200855 he = malloc(sizeof(*he));
856 if (!he)
857 return -ENOMEM;
858 *he = entry;
859 rb_link_node(&he->rb_node, parent, p);
860 rb_insert_color(&he->rb_node, &hist);
861
862 return 0;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300863}
864
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200865/*
866 * reverse the map, sort on count.
867 */
868
869static struct rb_root output_hists;
870
871static void output__insert_entry(struct hist_entry *he)
872{
873 struct rb_node **p = &output_hists.rb_node;
874 struct rb_node *parent = NULL;
875 struct hist_entry *iter;
876
877 while (*p != NULL) {
878 parent = *p;
879 iter = rb_entry(parent, struct hist_entry, rb_node);
880
881 if (he->count > iter->count)
882 p = &(*p)->rb_left;
883 else
884 p = &(*p)->rb_right;
885 }
886
887 rb_link_node(&he->rb_node, parent, p);
888 rb_insert_color(&he->rb_node, &output_hists);
889}
890
891static void output__resort(void)
892{
893 struct rb_node *next = rb_first(&hist);
894 struct hist_entry *n;
895
896 while (next) {
897 n = rb_entry(next, struct hist_entry, rb_node);
898 next = rb_next(&n->rb_node);
899
900 rb_erase(&n->rb_node, &hist);
901 output__insert_entry(n);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300902 }
903}
904
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200905static size_t output__fprintf(FILE *fp, uint64_t total_samples)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300906{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200907 struct hist_entry *pos;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300908 struct rb_node *nd;
909 size_t ret = 0;
910
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200911 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
912 pos = rb_entry(nd, struct hist_entry, rb_node);
913 ret += hist_entry__fprintf(fp, pos, total_samples);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300914 }
915
916 return ret;
917}
918
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200919
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200920static int __cmd_report(void)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300921{
922 unsigned long offset = 0;
923 unsigned long head = 0;
924 struct stat stat;
925 char *buf;
926 event_t *event;
927 int ret, rc = EXIT_FAILURE;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200928 uint32_t size;
Ingo Molnarf49515b2009-05-26 19:03:36 +0200929 unsigned long total = 0, total_mmap = 0, total_comm = 0, total_unknown = 0;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300930
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300931 input = open(input_name, O_RDONLY);
932 if (input < 0) {
933 perror("failed to open file");
934 exit(-1);
935 }
936
937 ret = fstat(input, &stat);
938 if (ret < 0) {
939 perror("failed to stat file");
940 exit(-1);
941 }
942
943 if (!stat.st_size) {
944 fprintf(stderr, "zero-sized file, nothing to do!\n");
945 exit(0);
946 }
947
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200948 if (load_kernel() < 0) {
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300949 perror("failed to open kallsyms");
950 return EXIT_FAILURE;
951 }
952
953remap:
954 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
955 MAP_SHARED, input, offset);
956 if (buf == MAP_FAILED) {
957 perror("failed to mmap file");
958 exit(-1);
959 }
960
961more:
962 event = (event_t *)(buf + head);
963
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200964 size = event->header.size;
965 if (!size)
966 size = 8;
967
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300968 if (head + event->header.size >= page_size * mmap_window) {
969 unsigned long shift = page_size * (head / page_size);
970 int ret;
971
972 ret = munmap(buf, page_size * mmap_window);
973 assert(ret == 0);
974
975 offset += shift;
976 head -= shift;
977 goto remap;
978 }
979
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200980 size = event->header.size;
981 if (!size)
982 goto broken_event;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300983
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300984 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
985 char level;
986 int show = 0;
987 struct dso *dso = NULL;
988 struct thread *thread = threads__findnew(event->ip.pid);
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200989 uint64_t ip = event->ip.ip;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200990 struct map *map = NULL;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300991
Ingo Molnar97b07b62009-05-26 18:48:58 +0200992 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200993 fprintf(stderr, "%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
994 (void *)(offset + head),
995 (void *)(long)(event->header.size),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200996 event->header.misc,
997 event->ip.pid,
Ingo Molnar16f762a2009-05-27 09:10:38 +0200998 (void *)(long)ip);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200999 }
1000
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -03001001 if (thread == NULL) {
1002 fprintf(stderr, "problem processing %d event, bailing out\n",
1003 event->header.type);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001004 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -03001005 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001006
1007 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
1008 show = SHOW_KERNEL;
1009 level = 'k';
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001010
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001011 dso = kernel_dso;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001012
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001013 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
Ingo Molnar16f762a2009-05-27 09:10:38 +02001014
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001015 show = SHOW_USER;
1016 level = '.';
Ingo Molnar16f762a2009-05-27 09:10:38 +02001017
1018 map = thread__find_map(thread, ip);
Peter Zijlstraf17e04a2009-05-26 15:30:22 +02001019 if (map != NULL) {
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001020 dso = map->dso;
Peter Zijlstraf17e04a2009-05-26 15:30:22 +02001021 ip -= map->start + map->pgoff;
1022 }
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001023
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001024 } else {
1025 show = SHOW_HV;
1026 level = 'H';
1027 }
1028
1029 if (show & show_mask) {
Peter Zijlstraf17e04a2009-05-26 15:30:22 +02001030 struct symbol *sym = dso__find_symbol(dso, ip);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001031
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001032 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
1033 fprintf(stderr,
1034 "problem incrementing symbol count, bailing out\n");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001035 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -03001036 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001037 }
1038 total++;
1039 } else switch (event->header.type) {
1040 case PERF_EVENT_MMAP: {
1041 struct thread *thread = threads__findnew(event->mmap.pid);
1042 struct map *map = map__new(&event->mmap);
1043
Ingo Molnar97b07b62009-05-26 18:48:58 +02001044 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +02001045 fprintf(stderr, "%p [%p]: PERF_EVENT_MMAP: [%p(%p) @ %p]: %s\n",
1046 (void *)(offset + head),
1047 (void *)(long)(event->header.size),
Ingo Molnar16f762a2009-05-27 09:10:38 +02001048 (void *)(long)event->mmap.start,
1049 (void *)(long)event->mmap.len,
1050 (void *)(long)event->mmap.pgoff,
Ingo Molnar97b07b62009-05-26 18:48:58 +02001051 event->mmap.filename);
1052 }
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -03001053 if (thread == NULL || map == NULL) {
1054 fprintf(stderr, "problem processing PERF_EVENT_MMAP, bailing out\n");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001055 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -03001056 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001057 thread__insert_map(thread, map);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001058 total_mmap++;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001059 break;
1060 }
1061 case PERF_EVENT_COMM: {
1062 struct thread *thread = threads__findnew(event->comm.pid);
1063
Ingo Molnar97b07b62009-05-26 18:48:58 +02001064 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +02001065 fprintf(stderr, "%p [%p]: PERF_EVENT_COMM: %s:%d\n",
1066 (void *)(offset + head),
1067 (void *)(long)(event->header.size),
Ingo Molnar97b07b62009-05-26 18:48:58 +02001068 event->comm.comm, event->comm.pid);
1069 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001070 if (thread == NULL ||
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -03001071 thread__set_comm(thread, event->comm.comm)) {
1072 fprintf(stderr, "problem processing PERF_EVENT_COMM, bailing out\n");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001073 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -03001074 }
Ingo Molnar97b07b62009-05-26 18:48:58 +02001075 total_comm++;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001076 break;
1077 }
Ingo Molnar97b07b62009-05-26 18:48:58 +02001078 default: {
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001079broken_event:
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +02001080 if (dump_trace)
1081 fprintf(stderr, "%p [%p]: skipping unknown header type: %d\n",
1082 (void *)(offset + head),
1083 (void *)(long)(event->header.size),
1084 event->header.type);
1085
Ingo Molnar3e706112009-05-26 18:53:17 +02001086 total_unknown++;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001087
1088 /*
1089 * assume we lost track of the stream, check alignment, and
1090 * increment a single u64 in the hope to catch on again 'soon'.
1091 */
1092
1093 if (unlikely(head & 7))
1094 head &= ~7ULL;
1095
1096 size = 8;
Ingo Molnar97b07b62009-05-26 18:48:58 +02001097 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001098 }
1099
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001100 head += size;
Ingo Molnarf49515b2009-05-26 19:03:36 +02001101
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001102 if (offset + head < stat.st_size)
1103 goto more;
1104
1105 rc = EXIT_SUCCESS;
1106done:
1107 close(input);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001108
1109 if (dump_trace) {
Ingo Molnar3e706112009-05-26 18:53:17 +02001110 fprintf(stderr, " IP events: %10ld\n", total);
1111 fprintf(stderr, " mmap events: %10ld\n", total_mmap);
1112 fprintf(stderr, " comm events: %10ld\n", total_comm);
1113 fprintf(stderr, " unknown events: %10ld\n", total_unknown);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001114
1115 return 0;
1116 }
1117
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001118 if (verbose >= 2)
Ingo Molnar16f762a2009-05-27 09:10:38 +02001119 dsos__fprintf(stdout);
Ingo Molnar16f762a2009-05-27 09:10:38 +02001120
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001121 output__resort();
1122 output__fprintf(stdout, total);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001123
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001124 return rc;
1125}
1126
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001127static const char * const report_usage[] = {
1128 "perf report [<options>] <command>",
1129 NULL
1130};
1131
1132static const struct option options[] = {
1133 OPT_STRING('i', "input", &input_name, "file",
1134 "input file name"),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -03001135 OPT_BOOLEAN('v', "verbose", &verbose,
1136 "be more verbose (show symbol address, etc)"),
Ingo Molnar97b07b62009-05-26 18:48:58 +02001137 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1138 "dump raw trace in ASCII"),
Peter Zijlstra450aaa22009-05-27 20:20:23 +02001139 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001140 OPT_END()
1141};
1142
1143int cmd_report(int argc, const char **argv, const char *prefix)
1144{
1145 elf_version(EV_CURRENT);
1146
1147 page_size = getpagesize();
1148
1149 parse_options(argc, argv, options, report_usage, 0);
1150
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001151 setup_sorting();
1152
Ingo Molnara930d2c2009-05-27 09:50:13 +02001153 setup_pager();
1154
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001155 return __cmd_report();
1156}