blob: 04fc7ec0c3597dbd7ad4c56ede7e9176313a876c [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
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -03004#include "util/list.h"
Ingo Molnara930d2c2009-05-27 09:50:13 +02005#include "util/cache.h"
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -03006#include "util/rbtree.h"
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03007#include "util/symbol.h"
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03008
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02009#include "perf.h"
10
11#include "util/parse-options.h"
12#include "util/parse-events.h"
13
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030014#define SHOW_KERNEL 1
15#define SHOW_USER 2
16#define SHOW_HV 4
17
Ingo Molnar23ac9cb2009-05-27 09:33:18 +020018static char const *input_name = "perf.data";
Peter Zijlstra450aaa22009-05-27 20:20:23 +020019static char *vmlinux = NULL;
Peter Zijlstra37f440c2009-05-27 20:20:26 +020020static char *sort_order = "pid,symbol";
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030021static int input;
22static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
23
Ingo Molnar97b07b62009-05-26 18:48:58 +020024static int dump_trace = 0;
Ingo Molnar16f762a2009-05-27 09:10:38 +020025static int verbose;
Ingo Molnar97b07b62009-05-26 18:48:58 +020026
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030027static unsigned long page_size;
28static unsigned long mmap_window = 32;
29
Ingo Molnar53cb8bc2009-05-26 09:17:18 +020030const char *perf_event_names[] = {
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030031 [PERF_EVENT_MMAP] = " PERF_EVENT_MMAP",
32 [PERF_EVENT_MUNMAP] = " PERF_EVENT_MUNMAP",
33 [PERF_EVENT_COMM] = " PERF_EVENT_COMM",
34};
35
36struct ip_event {
37 struct perf_event_header header;
38 __u64 ip;
39 __u32 pid, tid;
40};
41struct mmap_event {
42 struct perf_event_header header;
43 __u32 pid, tid;
44 __u64 start;
45 __u64 len;
46 __u64 pgoff;
47 char filename[PATH_MAX];
48};
49struct comm_event {
50 struct perf_event_header header;
51 __u32 pid,tid;
52 char comm[16];
53};
54
55typedef union event_union {
56 struct perf_event_header header;
57 struct ip_event ip;
58 struct mmap_event mmap;
59 struct comm_event comm;
60} event_t;
61
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030062static LIST_HEAD(dsos);
63static struct dso *kernel_dso;
64
65static void dsos__add(struct dso *dso)
66{
67 list_add_tail(&dso->node, &dsos);
68}
69
70static struct dso *dsos__find(const char *name)
71{
72 struct dso *pos;
73
74 list_for_each_entry(pos, &dsos, node)
75 if (strcmp(pos->name, name) == 0)
76 return pos;
77 return NULL;
78}
79
80static struct dso *dsos__findnew(const char *name)
81{
82 struct dso *dso = dsos__find(name);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +020083 int nr;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030084
85 if (dso == NULL) {
86 dso = dso__new(name);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +020087 if (!dso)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030088 goto out_delete_dso;
89
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +020090 nr = dso__load(dso);
91 if (nr < 0) {
92 fprintf(stderr, "Failed to open: %s\n", name);
93 goto out_delete_dso;
94 }
95 if (!nr) {
96 fprintf(stderr,
97 "Failed to find debug symbols for: %s, maybe install a debug package?\n",
98 name);
99 }
100
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300101 dsos__add(dso);
102 }
103
104 return dso;
105
106out_delete_dso:
107 dso__delete(dso);
108 return NULL;
109}
110
Ingo Molnar16f762a2009-05-27 09:10:38 +0200111static void dsos__fprintf(FILE *fp)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300112{
113 struct dso *pos;
114
115 list_for_each_entry(pos, &dsos, node)
116 dso__fprintf(pos, fp);
117}
118
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200119static int load_kernel(void)
120{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300121 int err = -1;
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200122
123 kernel_dso = dso__new("[kernel]");
124 if (!kernel_dso)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300125 return -1;
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200126
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300127 if (vmlinux)
128 err = dso__load_vmlinux(kernel_dso, vmlinux);
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200129
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300130 if (err)
131 err = dso__load_kallsyms(kernel_dso);
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200132
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300133 if (err) {
134 dso__delete(kernel_dso);
135 kernel_dso = NULL;
136 } else
137 dsos__add(kernel_dso);
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200138
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300139 return err;
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200140}
141
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300142struct map {
143 struct list_head node;
144 uint64_t start;
145 uint64_t end;
146 uint64_t pgoff;
147 struct dso *dso;
148};
149
150static struct map *map__new(struct mmap_event *event)
151{
152 struct map *self = malloc(sizeof(*self));
153
154 if (self != NULL) {
155 self->start = event->start;
156 self->end = event->start + event->len;
157 self->pgoff = event->pgoff;
158
159 self->dso = dsos__findnew(event->filename);
160 if (self->dso == NULL)
161 goto out_delete;
162 }
163 return self;
164out_delete:
165 free(self);
166 return NULL;
167}
168
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300169struct thread;
170
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300171struct thread {
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300172 struct rb_node rb_node;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300173 struct list_head maps;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300174 pid_t pid;
175 char *comm;
176};
177
178static struct thread *thread__new(pid_t pid)
179{
180 struct thread *self = malloc(sizeof(*self));
181
182 if (self != NULL) {
183 self->pid = pid;
184 self->comm = NULL;
185 INIT_LIST_HEAD(&self->maps);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300186 }
187
188 return self;
189}
190
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300191static int thread__set_comm(struct thread *self, const char *comm)
192{
193 self->comm = strdup(comm);
194 return self->comm ? 0 : -ENOMEM;
195}
196
Ingo Molnar16f762a2009-05-27 09:10:38 +0200197static struct rb_root threads;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300198
199static struct thread *threads__findnew(pid_t pid)
200{
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300201 struct rb_node **p = &threads.rb_node;
202 struct rb_node *parent = NULL;
203 struct thread *th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300204
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300205 while (*p != NULL) {
206 parent = *p;
207 th = rb_entry(parent, struct thread, rb_node);
208
209 if (th->pid == pid)
210 return th;
211
212 if (pid < th->pid)
213 p = &(*p)->rb_left;
214 else
215 p = &(*p)->rb_right;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300216 }
217
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300218 th = thread__new(pid);
219 if (th != NULL) {
220 rb_link_node(&th->rb_node, parent, p);
221 rb_insert_color(&th->rb_node, &threads);
222 }
223 return th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300224}
225
226static void thread__insert_map(struct thread *self, struct map *map)
227{
228 list_add_tail(&map->node, &self->maps);
229}
230
231static struct map *thread__find_map(struct thread *self, uint64_t ip)
232{
Ingo Molnar16f762a2009-05-27 09:10:38 +0200233 struct map *pos;
234
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300235 if (self == NULL)
236 return NULL;
237
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300238 list_for_each_entry(pos, &self->maps, node)
239 if (ip >= pos->start && ip <= pos->end)
240 return pos;
241
242 return NULL;
243}
244
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200245/*
246 * histogram, sorted on item, collects counts
247 */
248
249static struct rb_root hist;
250
251struct hist_entry {
252 struct rb_node rb_node;
253
254 struct thread *thread;
255 struct map *map;
256 struct dso *dso;
257 struct symbol *sym;
258 uint64_t ip;
259 char level;
260
261 uint32_t count;
262};
263
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200264/*
265 * configurable sorting bits
266 */
267
268struct sort_entry {
269 struct list_head list;
270
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200271 char *header;
272
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200273 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
274 size_t (*print)(FILE *fp, struct hist_entry *);
275};
276
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200277static int64_t
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200278sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
279{
280 return right->thread->pid - left->thread->pid;
281}
282
283static size_t
284sort__thread_print(FILE *fp, struct hist_entry *self)
285{
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200286 return fprintf(fp, " %16s:%5d", self->thread->comm ?: "", self->thread->pid);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200287}
288
289static struct sort_entry sort_thread = {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200290 .header = " Command: Pid ",
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200291 .cmp = sort__thread_cmp,
292 .print = sort__thread_print,
293};
294
295static int64_t
Peter Zijlstra992444b2009-05-27 20:20:27 +0200296sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
297{
298 char *comm_l = left->thread->comm;
299 char *comm_r = right->thread->comm;
300
301 if (!comm_l || !comm_r) {
302 if (!comm_l && !comm_r)
303 return 0;
304 else if (!comm_l)
305 return -1;
306 else
307 return 1;
308 }
309
310 return strcmp(comm_l, comm_r);
311}
312
313static size_t
314sort__comm_print(FILE *fp, struct hist_entry *self)
315{
Ingo Molnar2d655372009-05-27 21:36:22 +0200316 return fprintf(fp, " %16s", self->thread->comm ?: "<unknown>");
Peter Zijlstra992444b2009-05-27 20:20:27 +0200317}
318
319static struct sort_entry sort_comm = {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200320 .header = " Command",
Peter Zijlstra992444b2009-05-27 20:20:27 +0200321 .cmp = sort__comm_cmp,
322 .print = sort__comm_print,
323};
324
325static int64_t
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200326sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
327{
328 struct dso *dso_l = left->dso;
329 struct dso *dso_r = right->dso;
330
331 if (!dso_l || !dso_r) {
332 if (!dso_l && !dso_r)
333 return 0;
334 else if (!dso_l)
335 return -1;
336 else
337 return 1;
338 }
339
340 return strcmp(dso_l->name, dso_r->name);
341}
342
343static size_t
344sort__dso_print(FILE *fp, struct hist_entry *self)
345{
Ingo Molnar2d655372009-05-27 21:36:22 +0200346 return fprintf(fp, " %64s", self->dso ? self->dso->name : "<unknown>");
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200347}
348
349static struct sort_entry sort_dso = {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200350 .header = " Shared Object",
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200351 .cmp = sort__dso_cmp,
352 .print = sort__dso_print,
353};
354
355static int64_t
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200356sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300357{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200358 uint64_t ip_l, ip_r;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200359
360 if (left->sym == right->sym)
361 return 0;
362
363 ip_l = left->sym ? left->sym->start : left->ip;
364 ip_r = right->sym ? right->sym->start : right->ip;
365
366 return (int64_t)(ip_r - ip_l);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300367}
368
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200369static size_t
370sort__sym_print(FILE *fp, struct hist_entry *self)
371{
372 size_t ret = 0;
373
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200374 if (verbose)
Ingo Molnar2d655372009-05-27 21:36:22 +0200375 ret += fprintf(fp, " %#018llx", (unsigned long long)self->ip);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200376
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200377 ret += fprintf(fp, " %s: %s",
378 self->dso ? self->dso->name : "<unknown>",
379 self->sym ? self->sym->name : "<unknown>");
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200380
381 return ret;
382}
383
384static struct sort_entry sort_sym = {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200385 .header = "Shared Object: Symbol",
386 .cmp = sort__sym_cmp,
387 .print = sort__sym_print,
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200388};
389
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200390struct sort_dimension {
391 char *name;
392 struct sort_entry *entry;
393 int taken;
394};
395
396static struct sort_dimension sort_dimensions[] = {
397 { .name = "pid", .entry = &sort_thread, },
Peter Zijlstra992444b2009-05-27 20:20:27 +0200398 { .name = "comm", .entry = &sort_comm, },
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200399 { .name = "dso", .entry = &sort_dso, },
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200400 { .name = "symbol", .entry = &sort_sym, },
401};
402
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200403static LIST_HEAD(hist_entry__sort_list);
404
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200405static int sort_dimension__add(char *tok)
406{
407 int i;
408
409 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
410 struct sort_dimension *sd = &sort_dimensions[i];
411
412 if (sd->taken)
413 continue;
414
415 if (strcmp(tok, sd->name))
416 continue;
417
418 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
419 sd->taken = 1;
420 return 0;
421 }
422
423 return -ESRCH;
424}
425
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200426static void setup_sorting(void)
427{
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200428 char *tmp, *tok, *str = strdup(sort_order);
429
430 for (tok = strtok_r(str, ", ", &tmp);
431 tok; tok = strtok_r(NULL, ", ", &tmp))
432 sort_dimension__add(tok);
433
434 free(str);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200435}
436
437static int64_t
438hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
439{
440 struct sort_entry *se;
441 int64_t cmp = 0;
442
443 list_for_each_entry(se, &hist_entry__sort_list, list) {
444 cmp = se->cmp(left, right);
445 if (cmp)
446 break;
447 }
448
449 return cmp;
450}
451
452static size_t
453hist_entry__fprintf(FILE *fp, struct hist_entry *self, uint64_t total_samples)
454{
455 struct sort_entry *se;
456 size_t ret;
457
458 if (total_samples) {
Ingo Molnar2d655372009-05-27 21:36:22 +0200459 ret = fprintf(fp, " %5.2f%%",
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200460 (self->count * 100.0) / total_samples);
461 } else
462 ret = fprintf(fp, "%12d ", self->count);
463
464 list_for_each_entry(se, &hist_entry__sort_list, list)
465 ret += se->print(fp, self);
466
467 ret += fprintf(fp, "\n");
468
469 return ret;
470}
471
472/*
473 * collect histogram counts
474 */
475
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200476static int
477hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
478 struct symbol *sym, uint64_t ip, char level)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300479{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200480 struct rb_node **p = &hist.rb_node;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300481 struct rb_node *parent = NULL;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200482 struct hist_entry *he;
483 struct hist_entry entry = {
484 .thread = thread,
485 .map = map,
486 .dso = dso,
487 .sym = sym,
488 .ip = ip,
489 .level = level,
490 .count = 1,
491 };
492 int cmp;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300493
494 while (*p != NULL) {
495 parent = *p;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200496 he = rb_entry(parent, struct hist_entry, rb_node);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300497
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200498 cmp = hist_entry__cmp(&entry, he);
499
500 if (!cmp) {
501 he->count++;
502 return 0;
503 }
504
505 if (cmp < 0)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300506 p = &(*p)->rb_left;
507 else
508 p = &(*p)->rb_right;
509 }
510
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200511 he = malloc(sizeof(*he));
512 if (!he)
513 return -ENOMEM;
514 *he = entry;
515 rb_link_node(&he->rb_node, parent, p);
516 rb_insert_color(&he->rb_node, &hist);
517
518 return 0;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300519}
520
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200521/*
522 * reverse the map, sort on count.
523 */
524
525static struct rb_root output_hists;
526
527static void output__insert_entry(struct hist_entry *he)
528{
529 struct rb_node **p = &output_hists.rb_node;
530 struct rb_node *parent = NULL;
531 struct hist_entry *iter;
532
533 while (*p != NULL) {
534 parent = *p;
535 iter = rb_entry(parent, struct hist_entry, rb_node);
536
537 if (he->count > iter->count)
538 p = &(*p)->rb_left;
539 else
540 p = &(*p)->rb_right;
541 }
542
543 rb_link_node(&he->rb_node, parent, p);
544 rb_insert_color(&he->rb_node, &output_hists);
545}
546
547static void output__resort(void)
548{
549 struct rb_node *next = rb_first(&hist);
550 struct hist_entry *n;
551
552 while (next) {
553 n = rb_entry(next, struct hist_entry, rb_node);
554 next = rb_next(&n->rb_node);
555
556 rb_erase(&n->rb_node, &hist);
557 output__insert_entry(n);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300558 }
559}
560
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200561static size_t output__fprintf(FILE *fp, uint64_t total_samples)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300562{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200563 struct hist_entry *pos;
Ingo Molnar2d655372009-05-27 21:36:22 +0200564 struct sort_entry *se;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300565 struct rb_node *nd;
566 size_t ret = 0;
567
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200568 fprintf(fp, "#\n");
569
570 fprintf(fp, "# Overhead");
571 list_for_each_entry(se, &hist_entry__sort_list, list)
572 fprintf(fp, " %s", se->header);
573 fprintf(fp, "\n");
574
575 fprintf(fp, "# ........");
Ingo Molnar2d655372009-05-27 21:36:22 +0200576 list_for_each_entry(se, &hist_entry__sort_list, list) {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200577 int i;
578
579 fprintf(fp, " ");
580 for (i = 0; i < strlen(se->header); i++)
581 fprintf(fp, ".");
Ingo Molnar2d655372009-05-27 21:36:22 +0200582 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200583 fprintf(fp, "\n");
584
585 fprintf(fp, "#\n");
Ingo Molnar2d655372009-05-27 21:36:22 +0200586
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200587 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
588 pos = rb_entry(nd, struct hist_entry, rb_node);
589 ret += hist_entry__fprintf(fp, pos, total_samples);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300590 }
591
592 return ret;
593}
594
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200595
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200596static int __cmd_report(void)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300597{
598 unsigned long offset = 0;
599 unsigned long head = 0;
600 struct stat stat;
601 char *buf;
602 event_t *event;
603 int ret, rc = EXIT_FAILURE;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200604 uint32_t size;
Ingo Molnarf49515b2009-05-26 19:03:36 +0200605 unsigned long total = 0, total_mmap = 0, total_comm = 0, total_unknown = 0;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300606
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300607 input = open(input_name, O_RDONLY);
608 if (input < 0) {
609 perror("failed to open file");
610 exit(-1);
611 }
612
613 ret = fstat(input, &stat);
614 if (ret < 0) {
615 perror("failed to stat file");
616 exit(-1);
617 }
618
619 if (!stat.st_size) {
620 fprintf(stderr, "zero-sized file, nothing to do!\n");
621 exit(0);
622 }
623
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200624 if (load_kernel() < 0) {
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300625 perror("failed to load kernel symbols");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300626 return EXIT_FAILURE;
627 }
628
629remap:
630 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
631 MAP_SHARED, input, offset);
632 if (buf == MAP_FAILED) {
633 perror("failed to mmap file");
634 exit(-1);
635 }
636
637more:
638 event = (event_t *)(buf + head);
639
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200640 size = event->header.size;
641 if (!size)
642 size = 8;
643
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300644 if (head + event->header.size >= page_size * mmap_window) {
645 unsigned long shift = page_size * (head / page_size);
646 int ret;
647
648 ret = munmap(buf, page_size * mmap_window);
649 assert(ret == 0);
650
651 offset += shift;
652 head -= shift;
653 goto remap;
654 }
655
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200656 size = event->header.size;
657 if (!size)
658 goto broken_event;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300659
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300660 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
661 char level;
662 int show = 0;
663 struct dso *dso = NULL;
664 struct thread *thread = threads__findnew(event->ip.pid);
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200665 uint64_t ip = event->ip.ip;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200666 struct map *map = NULL;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300667
Ingo Molnar97b07b62009-05-26 18:48:58 +0200668 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200669 fprintf(stderr, "%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
670 (void *)(offset + head),
671 (void *)(long)(event->header.size),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200672 event->header.misc,
673 event->ip.pid,
Ingo Molnar16f762a2009-05-27 09:10:38 +0200674 (void *)(long)ip);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200675 }
676
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300677 if (thread == NULL) {
Ingo Molnar55717312009-05-27 22:13:17 +0200678 fprintf(stderr, "problem processing %d event, skipping it.\n",
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300679 event->header.type);
Ingo Molnar55717312009-05-27 22:13:17 +0200680 goto broken_event;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300681 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300682
683 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
684 show = SHOW_KERNEL;
685 level = 'k';
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200686
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300687 dso = kernel_dso;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200688
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300689 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
Ingo Molnar16f762a2009-05-27 09:10:38 +0200690
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300691 show = SHOW_USER;
692 level = '.';
Ingo Molnar16f762a2009-05-27 09:10:38 +0200693
694 map = thread__find_map(thread, ip);
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200695 if (map != NULL) {
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300696 dso = map->dso;
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200697 ip -= map->start + map->pgoff;
698 }
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200699
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300700 } else {
701 show = SHOW_HV;
702 level = 'H';
703 }
704
705 if (show & show_mask) {
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200706 struct symbol *sym = dso__find_symbol(dso, ip);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300707
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200708 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
709 fprintf(stderr,
Ingo Molnar55717312009-05-27 22:13:17 +0200710 "problem incrementing symbol count, skipping event\n");
711 goto broken_event;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300712 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300713 }
714 total++;
715 } else switch (event->header.type) {
716 case PERF_EVENT_MMAP: {
717 struct thread *thread = threads__findnew(event->mmap.pid);
718 struct map *map = map__new(&event->mmap);
719
Ingo Molnar97b07b62009-05-26 18:48:58 +0200720 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200721 fprintf(stderr, "%p [%p]: PERF_EVENT_MMAP: [%p(%p) @ %p]: %s\n",
722 (void *)(offset + head),
723 (void *)(long)(event->header.size),
Ingo Molnar16f762a2009-05-27 09:10:38 +0200724 (void *)(long)event->mmap.start,
725 (void *)(long)event->mmap.len,
726 (void *)(long)event->mmap.pgoff,
Ingo Molnar97b07b62009-05-26 18:48:58 +0200727 event->mmap.filename);
728 }
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300729 if (thread == NULL || map == NULL) {
Ingo Molnar55717312009-05-27 22:13:17 +0200730 fprintf(stderr, "problem processing PERF_EVENT_MMAP, skipping event.\n");
731 goto broken_event;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300732 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300733 thread__insert_map(thread, map);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200734 total_mmap++;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300735 break;
736 }
737 case PERF_EVENT_COMM: {
738 struct thread *thread = threads__findnew(event->comm.pid);
739
Ingo Molnar97b07b62009-05-26 18:48:58 +0200740 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200741 fprintf(stderr, "%p [%p]: PERF_EVENT_COMM: %s:%d\n",
742 (void *)(offset + head),
743 (void *)(long)(event->header.size),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200744 event->comm.comm, event->comm.pid);
745 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300746 if (thread == NULL ||
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300747 thread__set_comm(thread, event->comm.comm)) {
Ingo Molnar55717312009-05-27 22:13:17 +0200748 fprintf(stderr, "problem processing PERF_EVENT_COMM, skipping event.\n");
749 goto broken_event;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300750 }
Ingo Molnar97b07b62009-05-26 18:48:58 +0200751 total_comm++;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300752 break;
753 }
Ingo Molnar97b07b62009-05-26 18:48:58 +0200754 default: {
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200755broken_event:
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200756 if (dump_trace)
757 fprintf(stderr, "%p [%p]: skipping unknown header type: %d\n",
758 (void *)(offset + head),
759 (void *)(long)(event->header.size),
760 event->header.type);
761
Ingo Molnar3e706112009-05-26 18:53:17 +0200762 total_unknown++;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200763
764 /*
765 * assume we lost track of the stream, check alignment, and
766 * increment a single u64 in the hope to catch on again 'soon'.
767 */
768
769 if (unlikely(head & 7))
770 head &= ~7ULL;
771
772 size = 8;
Ingo Molnar97b07b62009-05-26 18:48:58 +0200773 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300774 }
775
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200776 head += size;
Ingo Molnarf49515b2009-05-26 19:03:36 +0200777
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300778 if (offset + head < stat.st_size)
779 goto more;
780
781 rc = EXIT_SUCCESS;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300782 close(input);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200783
784 if (dump_trace) {
Ingo Molnar3e706112009-05-26 18:53:17 +0200785 fprintf(stderr, " IP events: %10ld\n", total);
786 fprintf(stderr, " mmap events: %10ld\n", total_mmap);
787 fprintf(stderr, " comm events: %10ld\n", total_comm);
788 fprintf(stderr, " unknown events: %10ld\n", total_unknown);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200789
790 return 0;
791 }
792
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200793 if (verbose >= 2)
Ingo Molnar16f762a2009-05-27 09:10:38 +0200794 dsos__fprintf(stdout);
Ingo Molnar16f762a2009-05-27 09:10:38 +0200795
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200796 output__resort();
797 output__fprintf(stdout, total);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300798
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300799 return rc;
800}
801
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200802static const char * const report_usage[] = {
803 "perf report [<options>] <command>",
804 NULL
805};
806
807static const struct option options[] = {
808 OPT_STRING('i', "input", &input_name, "file",
809 "input file name"),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -0300810 OPT_BOOLEAN('v', "verbose", &verbose,
811 "be more verbose (show symbol address, etc)"),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200812 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
813 "dump raw trace in ASCII"),
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200814 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
Ingo Molnar63299f02009-05-28 10:52:00 +0200815 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
816 "sort by key(s): pid, comm, dso, symbol. Default: pid,symbol"),
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200817 OPT_END()
818};
819
820int cmd_report(int argc, const char **argv, const char *prefix)
821{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300822 symbol__init();
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200823
824 page_size = getpagesize();
825
826 parse_options(argc, argv, options, report_usage, 0);
827
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200828 setup_sorting();
829
Ingo Molnara930d2c2009-05-27 09:50:13 +0200830 setup_pager();
831
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200832 return __cmd_report();
833}