blob: 4e9f2bc104527d9860cd9adf52bf75251860d70f [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) {
Arnaldo Carvalho de Melo0085c952009-05-28 14:55:13 -030086 dso = dso__new(name, 0);
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 Meloa827c872009-05-28 14:55:19 -0300121 int err;
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200122
Arnaldo Carvalho de Melo0085c952009-05-28 14:55:13 -0300123 kernel_dso = dso__new("[kernel]", 0);
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200124 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 Meloa827c872009-05-28 14:55:19 -0300127 err = dso__load_kernel(kernel_dso, vmlinux);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300128 if (err) {
129 dso__delete(kernel_dso);
130 kernel_dso = NULL;
131 } else
132 dsos__add(kernel_dso);
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200133
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300134 return err;
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200135}
136
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300137struct map {
138 struct list_head node;
139 uint64_t start;
140 uint64_t end;
141 uint64_t pgoff;
142 struct dso *dso;
143};
144
145static struct map *map__new(struct mmap_event *event)
146{
147 struct map *self = malloc(sizeof(*self));
148
149 if (self != NULL) {
150 self->start = event->start;
151 self->end = event->start + event->len;
152 self->pgoff = event->pgoff;
153
154 self->dso = dsos__findnew(event->filename);
155 if (self->dso == NULL)
156 goto out_delete;
157 }
158 return self;
159out_delete:
160 free(self);
161 return NULL;
162}
163
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300164struct thread;
165
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300166struct thread {
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300167 struct rb_node rb_node;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300168 struct list_head maps;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300169 pid_t pid;
170 char *comm;
171};
172
173static struct thread *thread__new(pid_t pid)
174{
175 struct thread *self = malloc(sizeof(*self));
176
177 if (self != NULL) {
178 self->pid = pid;
179 self->comm = NULL;
180 INIT_LIST_HEAD(&self->maps);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300181 }
182
183 return self;
184}
185
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300186static int thread__set_comm(struct thread *self, const char *comm)
187{
188 self->comm = strdup(comm);
189 return self->comm ? 0 : -ENOMEM;
190}
191
Ingo Molnar16f762a2009-05-27 09:10:38 +0200192static struct rb_root threads;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300193
194static struct thread *threads__findnew(pid_t pid)
195{
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300196 struct rb_node **p = &threads.rb_node;
197 struct rb_node *parent = NULL;
198 struct thread *th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300199
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300200 while (*p != NULL) {
201 parent = *p;
202 th = rb_entry(parent, struct thread, rb_node);
203
204 if (th->pid == pid)
205 return th;
206
207 if (pid < th->pid)
208 p = &(*p)->rb_left;
209 else
210 p = &(*p)->rb_right;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300211 }
212
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300213 th = thread__new(pid);
214 if (th != NULL) {
215 rb_link_node(&th->rb_node, parent, p);
216 rb_insert_color(&th->rb_node, &threads);
217 }
218 return th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300219}
220
221static void thread__insert_map(struct thread *self, struct map *map)
222{
223 list_add_tail(&map->node, &self->maps);
224}
225
226static struct map *thread__find_map(struct thread *self, uint64_t ip)
227{
Ingo Molnar16f762a2009-05-27 09:10:38 +0200228 struct map *pos;
229
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300230 if (self == NULL)
231 return NULL;
232
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300233 list_for_each_entry(pos, &self->maps, node)
234 if (ip >= pos->start && ip <= pos->end)
235 return pos;
236
237 return NULL;
238}
239
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200240/*
241 * histogram, sorted on item, collects counts
242 */
243
244static struct rb_root hist;
245
246struct hist_entry {
247 struct rb_node rb_node;
248
249 struct thread *thread;
250 struct map *map;
251 struct dso *dso;
252 struct symbol *sym;
253 uint64_t ip;
254 char level;
255
256 uint32_t count;
257};
258
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200259/*
260 * configurable sorting bits
261 */
262
263struct sort_entry {
264 struct list_head list;
265
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200266 char *header;
267
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200268 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
269 size_t (*print)(FILE *fp, struct hist_entry *);
270};
271
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200272static int64_t
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200273sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
274{
275 return right->thread->pid - left->thread->pid;
276}
277
278static size_t
279sort__thread_print(FILE *fp, struct hist_entry *self)
280{
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200281 return fprintf(fp, " %16s:%5d", self->thread->comm ?: "", self->thread->pid);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200282}
283
284static struct sort_entry sort_thread = {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200285 .header = " Command: Pid ",
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200286 .cmp = sort__thread_cmp,
287 .print = sort__thread_print,
288};
289
290static int64_t
Peter Zijlstra992444b2009-05-27 20:20:27 +0200291sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
292{
293 char *comm_l = left->thread->comm;
294 char *comm_r = right->thread->comm;
295
296 if (!comm_l || !comm_r) {
297 if (!comm_l && !comm_r)
298 return 0;
299 else if (!comm_l)
300 return -1;
301 else
302 return 1;
303 }
304
305 return strcmp(comm_l, comm_r);
306}
307
308static size_t
309sort__comm_print(FILE *fp, struct hist_entry *self)
310{
Ingo Molnar2d655372009-05-27 21:36:22 +0200311 return fprintf(fp, " %16s", self->thread->comm ?: "<unknown>");
Peter Zijlstra992444b2009-05-27 20:20:27 +0200312}
313
314static struct sort_entry sort_comm = {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200315 .header = " Command",
Peter Zijlstra992444b2009-05-27 20:20:27 +0200316 .cmp = sort__comm_cmp,
317 .print = sort__comm_print,
318};
319
320static int64_t
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200321sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
322{
323 struct dso *dso_l = left->dso;
324 struct dso *dso_r = right->dso;
325
326 if (!dso_l || !dso_r) {
327 if (!dso_l && !dso_r)
328 return 0;
329 else if (!dso_l)
330 return -1;
331 else
332 return 1;
333 }
334
335 return strcmp(dso_l->name, dso_r->name);
336}
337
338static size_t
339sort__dso_print(FILE *fp, struct hist_entry *self)
340{
Ingo Molnar2d655372009-05-27 21:36:22 +0200341 return fprintf(fp, " %64s", self->dso ? self->dso->name : "<unknown>");
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200342}
343
344static struct sort_entry sort_dso = {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200345 .header = " Shared Object",
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200346 .cmp = sort__dso_cmp,
347 .print = sort__dso_print,
348};
349
350static int64_t
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200351sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300352{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200353 uint64_t ip_l, ip_r;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200354
355 if (left->sym == right->sym)
356 return 0;
357
358 ip_l = left->sym ? left->sym->start : left->ip;
359 ip_r = right->sym ? right->sym->start : right->ip;
360
361 return (int64_t)(ip_r - ip_l);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300362}
363
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200364static size_t
365sort__sym_print(FILE *fp, struct hist_entry *self)
366{
367 size_t ret = 0;
368
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200369 if (verbose)
Ingo Molnar2d655372009-05-27 21:36:22 +0200370 ret += fprintf(fp, " %#018llx", (unsigned long long)self->ip);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200371
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200372 ret += fprintf(fp, " %s: %s",
373 self->dso ? self->dso->name : "<unknown>",
374 self->sym ? self->sym->name : "<unknown>");
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200375
376 return ret;
377}
378
379static struct sort_entry sort_sym = {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200380 .header = "Shared Object: Symbol",
381 .cmp = sort__sym_cmp,
382 .print = sort__sym_print,
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200383};
384
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200385struct sort_dimension {
386 char *name;
387 struct sort_entry *entry;
388 int taken;
389};
390
391static struct sort_dimension sort_dimensions[] = {
392 { .name = "pid", .entry = &sort_thread, },
Peter Zijlstra992444b2009-05-27 20:20:27 +0200393 { .name = "comm", .entry = &sort_comm, },
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200394 { .name = "dso", .entry = &sort_dso, },
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200395 { .name = "symbol", .entry = &sort_sym, },
396};
397
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200398static LIST_HEAD(hist_entry__sort_list);
399
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200400static int sort_dimension__add(char *tok)
401{
402 int i;
403
404 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
405 struct sort_dimension *sd = &sort_dimensions[i];
406
407 if (sd->taken)
408 continue;
409
410 if (strcmp(tok, sd->name))
411 continue;
412
413 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
414 sd->taken = 1;
415 return 0;
416 }
417
418 return -ESRCH;
419}
420
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200421static void setup_sorting(void)
422{
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200423 char *tmp, *tok, *str = strdup(sort_order);
424
425 for (tok = strtok_r(str, ", ", &tmp);
426 tok; tok = strtok_r(NULL, ", ", &tmp))
427 sort_dimension__add(tok);
428
429 free(str);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200430}
431
432static int64_t
433hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
434{
435 struct sort_entry *se;
436 int64_t cmp = 0;
437
438 list_for_each_entry(se, &hist_entry__sort_list, list) {
439 cmp = se->cmp(left, right);
440 if (cmp)
441 break;
442 }
443
444 return cmp;
445}
446
447static size_t
448hist_entry__fprintf(FILE *fp, struct hist_entry *self, uint64_t total_samples)
449{
450 struct sort_entry *se;
451 size_t ret;
452
453 if (total_samples) {
Ingo Molnar2d655372009-05-27 21:36:22 +0200454 ret = fprintf(fp, " %5.2f%%",
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200455 (self->count * 100.0) / total_samples);
456 } else
457 ret = fprintf(fp, "%12d ", self->count);
458
459 list_for_each_entry(se, &hist_entry__sort_list, list)
460 ret += se->print(fp, self);
461
462 ret += fprintf(fp, "\n");
463
464 return ret;
465}
466
467/*
468 * collect histogram counts
469 */
470
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200471static int
472hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
473 struct symbol *sym, uint64_t ip, char level)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300474{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200475 struct rb_node **p = &hist.rb_node;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300476 struct rb_node *parent = NULL;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200477 struct hist_entry *he;
478 struct hist_entry entry = {
479 .thread = thread,
480 .map = map,
481 .dso = dso,
482 .sym = sym,
483 .ip = ip,
484 .level = level,
485 .count = 1,
486 };
487 int cmp;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300488
489 while (*p != NULL) {
490 parent = *p;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200491 he = rb_entry(parent, struct hist_entry, rb_node);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300492
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200493 cmp = hist_entry__cmp(&entry, he);
494
495 if (!cmp) {
496 he->count++;
497 return 0;
498 }
499
500 if (cmp < 0)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300501 p = &(*p)->rb_left;
502 else
503 p = &(*p)->rb_right;
504 }
505
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200506 he = malloc(sizeof(*he));
507 if (!he)
508 return -ENOMEM;
509 *he = entry;
510 rb_link_node(&he->rb_node, parent, p);
511 rb_insert_color(&he->rb_node, &hist);
512
513 return 0;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300514}
515
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200516/*
517 * reverse the map, sort on count.
518 */
519
520static struct rb_root output_hists;
521
522static void output__insert_entry(struct hist_entry *he)
523{
524 struct rb_node **p = &output_hists.rb_node;
525 struct rb_node *parent = NULL;
526 struct hist_entry *iter;
527
528 while (*p != NULL) {
529 parent = *p;
530 iter = rb_entry(parent, struct hist_entry, rb_node);
531
532 if (he->count > iter->count)
533 p = &(*p)->rb_left;
534 else
535 p = &(*p)->rb_right;
536 }
537
538 rb_link_node(&he->rb_node, parent, p);
539 rb_insert_color(&he->rb_node, &output_hists);
540}
541
542static void output__resort(void)
543{
544 struct rb_node *next = rb_first(&hist);
545 struct hist_entry *n;
546
547 while (next) {
548 n = rb_entry(next, struct hist_entry, rb_node);
549 next = rb_next(&n->rb_node);
550
551 rb_erase(&n->rb_node, &hist);
552 output__insert_entry(n);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300553 }
554}
555
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200556static size_t output__fprintf(FILE *fp, uint64_t total_samples)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300557{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200558 struct hist_entry *pos;
Ingo Molnar2d655372009-05-27 21:36:22 +0200559 struct sort_entry *se;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300560 struct rb_node *nd;
561 size_t ret = 0;
562
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200563 fprintf(fp, "#\n");
564
565 fprintf(fp, "# Overhead");
566 list_for_each_entry(se, &hist_entry__sort_list, list)
567 fprintf(fp, " %s", se->header);
568 fprintf(fp, "\n");
569
570 fprintf(fp, "# ........");
Ingo Molnar2d655372009-05-27 21:36:22 +0200571 list_for_each_entry(se, &hist_entry__sort_list, list) {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200572 int i;
573
574 fprintf(fp, " ");
575 for (i = 0; i < strlen(se->header); i++)
576 fprintf(fp, ".");
Ingo Molnar2d655372009-05-27 21:36:22 +0200577 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200578 fprintf(fp, "\n");
579
580 fprintf(fp, "#\n");
Ingo Molnar2d655372009-05-27 21:36:22 +0200581
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200582 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
583 pos = rb_entry(nd, struct hist_entry, rb_node);
584 ret += hist_entry__fprintf(fp, pos, total_samples);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300585 }
586
587 return ret;
588}
589
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200590
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200591static int __cmd_report(void)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300592{
593 unsigned long offset = 0;
594 unsigned long head = 0;
595 struct stat stat;
596 char *buf;
597 event_t *event;
598 int ret, rc = EXIT_FAILURE;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200599 uint32_t size;
Ingo Molnarf49515b2009-05-26 19:03:36 +0200600 unsigned long total = 0, total_mmap = 0, total_comm = 0, total_unknown = 0;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300601
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300602 input = open(input_name, O_RDONLY);
603 if (input < 0) {
604 perror("failed to open file");
605 exit(-1);
606 }
607
608 ret = fstat(input, &stat);
609 if (ret < 0) {
610 perror("failed to stat file");
611 exit(-1);
612 }
613
614 if (!stat.st_size) {
615 fprintf(stderr, "zero-sized file, nothing to do!\n");
616 exit(0);
617 }
618
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200619 if (load_kernel() < 0) {
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300620 perror("failed to load kernel symbols");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300621 return EXIT_FAILURE;
622 }
623
624remap:
625 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
626 MAP_SHARED, input, offset);
627 if (buf == MAP_FAILED) {
628 perror("failed to mmap file");
629 exit(-1);
630 }
631
632more:
633 event = (event_t *)(buf + head);
634
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200635 size = event->header.size;
636 if (!size)
637 size = 8;
638
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300639 if (head + event->header.size >= page_size * mmap_window) {
640 unsigned long shift = page_size * (head / page_size);
641 int ret;
642
643 ret = munmap(buf, page_size * mmap_window);
644 assert(ret == 0);
645
646 offset += shift;
647 head -= shift;
648 goto remap;
649 }
650
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200651 size = event->header.size;
652 if (!size)
653 goto broken_event;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300654
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300655 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
656 char level;
657 int show = 0;
658 struct dso *dso = NULL;
659 struct thread *thread = threads__findnew(event->ip.pid);
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200660 uint64_t ip = event->ip.ip;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200661 struct map *map = NULL;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300662
Ingo Molnar97b07b62009-05-26 18:48:58 +0200663 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200664 fprintf(stderr, "%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
665 (void *)(offset + head),
666 (void *)(long)(event->header.size),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200667 event->header.misc,
668 event->ip.pid,
Ingo Molnar16f762a2009-05-27 09:10:38 +0200669 (void *)(long)ip);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200670 }
671
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300672 if (thread == NULL) {
Ingo Molnar55717312009-05-27 22:13:17 +0200673 fprintf(stderr, "problem processing %d event, skipping it.\n",
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300674 event->header.type);
Ingo Molnar55717312009-05-27 22:13:17 +0200675 goto broken_event;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300676 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300677
678 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
679 show = SHOW_KERNEL;
680 level = 'k';
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200681
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300682 dso = kernel_dso;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200683
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300684 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
Ingo Molnar16f762a2009-05-27 09:10:38 +0200685
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300686 show = SHOW_USER;
687 level = '.';
Ingo Molnar16f762a2009-05-27 09:10:38 +0200688
689 map = thread__find_map(thread, ip);
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200690 if (map != NULL) {
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300691 dso = map->dso;
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200692 ip -= map->start + map->pgoff;
693 }
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200694
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300695 } else {
696 show = SHOW_HV;
697 level = 'H';
698 }
699
700 if (show & show_mask) {
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200701 struct symbol *sym = dso__find_symbol(dso, ip);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300702
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200703 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
704 fprintf(stderr,
Ingo Molnar55717312009-05-27 22:13:17 +0200705 "problem incrementing symbol count, skipping event\n");
706 goto broken_event;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300707 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300708 }
709 total++;
710 } else switch (event->header.type) {
711 case PERF_EVENT_MMAP: {
712 struct thread *thread = threads__findnew(event->mmap.pid);
713 struct map *map = map__new(&event->mmap);
714
Ingo Molnar97b07b62009-05-26 18:48:58 +0200715 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200716 fprintf(stderr, "%p [%p]: PERF_EVENT_MMAP: [%p(%p) @ %p]: %s\n",
717 (void *)(offset + head),
718 (void *)(long)(event->header.size),
Ingo Molnar16f762a2009-05-27 09:10:38 +0200719 (void *)(long)event->mmap.start,
720 (void *)(long)event->mmap.len,
721 (void *)(long)event->mmap.pgoff,
Ingo Molnar97b07b62009-05-26 18:48:58 +0200722 event->mmap.filename);
723 }
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300724 if (thread == NULL || map == NULL) {
Ingo Molnar55717312009-05-27 22:13:17 +0200725 fprintf(stderr, "problem processing PERF_EVENT_MMAP, skipping event.\n");
726 goto broken_event;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300727 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300728 thread__insert_map(thread, map);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200729 total_mmap++;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300730 break;
731 }
732 case PERF_EVENT_COMM: {
733 struct thread *thread = threads__findnew(event->comm.pid);
734
Ingo Molnar97b07b62009-05-26 18:48:58 +0200735 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200736 fprintf(stderr, "%p [%p]: PERF_EVENT_COMM: %s:%d\n",
737 (void *)(offset + head),
738 (void *)(long)(event->header.size),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200739 event->comm.comm, event->comm.pid);
740 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300741 if (thread == NULL ||
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300742 thread__set_comm(thread, event->comm.comm)) {
Ingo Molnar55717312009-05-27 22:13:17 +0200743 fprintf(stderr, "problem processing PERF_EVENT_COMM, skipping event.\n");
744 goto broken_event;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300745 }
Ingo Molnar97b07b62009-05-26 18:48:58 +0200746 total_comm++;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300747 break;
748 }
Ingo Molnar97b07b62009-05-26 18:48:58 +0200749 default: {
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200750broken_event:
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200751 if (dump_trace)
752 fprintf(stderr, "%p [%p]: skipping unknown header type: %d\n",
753 (void *)(offset + head),
754 (void *)(long)(event->header.size),
755 event->header.type);
756
Ingo Molnar3e706112009-05-26 18:53:17 +0200757 total_unknown++;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200758
759 /*
760 * assume we lost track of the stream, check alignment, and
761 * increment a single u64 in the hope to catch on again 'soon'.
762 */
763
764 if (unlikely(head & 7))
765 head &= ~7ULL;
766
767 size = 8;
Ingo Molnar97b07b62009-05-26 18:48:58 +0200768 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300769 }
770
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200771 head += size;
Ingo Molnarf49515b2009-05-26 19:03:36 +0200772
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300773 if (offset + head < stat.st_size)
774 goto more;
775
776 rc = EXIT_SUCCESS;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300777 close(input);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200778
779 if (dump_trace) {
Ingo Molnar3e706112009-05-26 18:53:17 +0200780 fprintf(stderr, " IP events: %10ld\n", total);
781 fprintf(stderr, " mmap events: %10ld\n", total_mmap);
782 fprintf(stderr, " comm events: %10ld\n", total_comm);
783 fprintf(stderr, " unknown events: %10ld\n", total_unknown);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200784
785 return 0;
786 }
787
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200788 if (verbose >= 2)
Ingo Molnar16f762a2009-05-27 09:10:38 +0200789 dsos__fprintf(stdout);
Ingo Molnar16f762a2009-05-27 09:10:38 +0200790
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200791 output__resort();
792 output__fprintf(stdout, total);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300793
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300794 return rc;
795}
796
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200797static const char * const report_usage[] = {
798 "perf report [<options>] <command>",
799 NULL
800};
801
802static const struct option options[] = {
803 OPT_STRING('i', "input", &input_name, "file",
804 "input file name"),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -0300805 OPT_BOOLEAN('v', "verbose", &verbose,
806 "be more verbose (show symbol address, etc)"),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200807 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
808 "dump raw trace in ASCII"),
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200809 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
Ingo Molnar63299f02009-05-28 10:52:00 +0200810 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
811 "sort by key(s): pid, comm, dso, symbol. Default: pid,symbol"),
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200812 OPT_END()
813};
814
815int cmd_report(int argc, const char **argv, const char *prefix)
816{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300817 symbol__init();
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200818
819 page_size = getpagesize();
820
821 parse_options(argc, argv, options, report_usage, 0);
822
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200823 setup_sorting();
824
Ingo Molnara930d2c2009-05-27 09:50:13 +0200825 setup_pager();
826
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200827 return __cmd_report();
828}