perf_counter: tools: report: Rework histogram code
[deliverable/linux.git] / Documentation / perf_counter / builtin-report.c
1 #include "util/util.h"
2 #include "builtin.h"
3
4 #include <libelf.h>
5 #include <gelf.h>
6 #include <elf.h>
7
8 #include "util/list.h"
9 #include "util/cache.h"
10 #include "util/rbtree.h"
11
12 #include "perf.h"
13
14 #include "util/parse-options.h"
15 #include "util/parse-events.h"
16
17 #define SHOW_KERNEL 1
18 #define SHOW_USER 2
19 #define SHOW_HV 4
20
21 static char const *input_name = "perf.data";
22 static char *vmlinux = NULL;
23 static int input;
24 static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
25
26 static int dump_trace = 0;
27 static int verbose;
28
29 static unsigned long page_size;
30 static unsigned long mmap_window = 32;
31
32 const char *perf_event_names[] = {
33 [PERF_EVENT_MMAP] = " PERF_EVENT_MMAP",
34 [PERF_EVENT_MUNMAP] = " PERF_EVENT_MUNMAP",
35 [PERF_EVENT_COMM] = " PERF_EVENT_COMM",
36 };
37
38 struct ip_event {
39 struct perf_event_header header;
40 __u64 ip;
41 __u32 pid, tid;
42 };
43 struct 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 };
51 struct comm_event {
52 struct perf_event_header header;
53 __u32 pid,tid;
54 char comm[16];
55 };
56
57 typedef 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
64 struct symbol {
65 struct rb_node rb_node;
66 __u64 start;
67 __u64 end;
68 char name[0];
69 };
70
71 static 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
84 static void symbol__delete(struct symbol *self)
85 {
86 free(self);
87 }
88
89 static size_t symbol__fprintf(struct symbol *self, FILE *fp)
90 {
91 return fprintf(fp, " %llx-%llx %s\n",
92 self->start, self->end, self->name);
93 }
94
95 struct dso {
96 struct list_head node;
97 struct rb_root syms;
98 char name[0];
99 };
100
101 static 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);
107 self->syms = RB_ROOT;
108 }
109
110 return self;
111 }
112
113 static void dso__delete_symbols(struct dso *self)
114 {
115 struct symbol *pos;
116 struct rb_node *next = rb_first(&self->syms);
117
118 while (next) {
119 pos = rb_entry(next, struct symbol, rb_node);
120 next = rb_next(&pos->rb_node);
121 symbol__delete(pos);
122 }
123 }
124
125 static void dso__delete(struct dso *self)
126 {
127 dso__delete_symbols(self);
128 free(self);
129 }
130
131 static void dso__insert_symbol(struct dso *self, struct symbol *sym)
132 {
133 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);
148 }
149
150 static struct symbol *dso__find_symbol(struct dso *self, uint64_t ip)
151 {
152 struct rb_node *n;
153
154 if (self == NULL)
155 return NULL;
156
157 n = self->syms.rb_node;
158
159 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 }
169
170 return NULL;
171 }
172
173 /**
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
185 static inline uint8_t elf_sym__type(const GElf_Sym *sym)
186 {
187 return GELF_ST_TYPE(sym->st_info);
188 }
189
190 static inline int elf_sym__is_function(const GElf_Sym *sym)
191 {
192 return elf_sym__type(sym) == STT_FUNC &&
193 sym->st_name != 0 &&
194 sym->st_shndx != SHN_UNDEF &&
195 sym->st_size != 0;
196 }
197
198 static 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
204 static 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
227 static int dso__load_sym(struct dso *self, int fd, char *name)
228 {
229 Elf_Data *symstrs;
230 uint32_t nr_syms;
231 int err = -1;
232 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;
239 int nr = 0;
240
241 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
242 if (elf == NULL) {
243 fprintf(stderr, "%s: cannot read %s ELF file.\n",
244 __func__, name);
245 goto out_close;
246 }
247
248 if (gelf_getehdr(elf, &ehdr) == NULL) {
249 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
250 goto out_elf_end;
251 }
252
253 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
254 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
260 syms = elf_getdata(sec, NULL);
261 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
268 symstrs = elf_getdata(sec, NULL);
269 if (symstrs == NULL)
270 goto out_elf_end;
271
272 nr_syms = shdr.sh_size / shdr.sh_entsize;
273
274 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
275 struct symbol *f;
276
277 if (!elf_sym__is_function(&sym))
278 continue;
279
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)
290 goto out_elf_end;
291
292 dso__insert_symbol(self, f);
293
294 nr++;
295 }
296
297 err = nr;
298 out_elf_end:
299 elf_end(elf);
300 out_close:
301 return err;
302 }
303
304 static 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
315 more:
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
345 out:
346 free(name);
347 return ret;
348 }
349
350 static size_t dso__fprintf(struct dso *self, FILE *fp)
351 {
352 size_t ret = fprintf(fp, "dso: %s\n", self->name);
353
354 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);
357 ret += symbol__fprintf(pos, fp);
358 }
359
360 return ret;
361 }
362
363 static LIST_HEAD(dsos);
364 static struct dso *kernel_dso;
365
366 static void dsos__add(struct dso *dso)
367 {
368 list_add_tail(&dso->node, &dsos);
369 }
370
371 static 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
381 static struct dso *dsos__findnew(const char *name)
382 {
383 struct dso *dso = dsos__find(name);
384 int nr;
385
386 if (dso == NULL) {
387 dso = dso__new(name);
388 if (!dso)
389 goto out_delete_dso;
390
391 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
402 dsos__add(dso);
403 }
404
405 return dso;
406
407 out_delete_dso:
408 dso__delete(dso);
409 return NULL;
410 }
411
412 static void dsos__fprintf(FILE *fp)
413 {
414 struct dso *pos;
415
416 list_for_each_entry(pos, &dsos, node)
417 dso__fprintf(pos, fp);
418 }
419
420 static 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 */
435 static int hex2long(char *ptr, unsigned long *long_val)
436 {
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
453 static int load_kallsyms(void)
454 {
455 struct rb_node *nd, *prevnd;
456 char *line = NULL;
457 FILE *file;
458 size_t n;
459
460 kernel_dso = dso__new("[kernel]");
461 if (kernel_dso == NULL)
462 return -1;
463
464 file = fopen("/proc/kallsyms", "r");
465 if (file == NULL)
466 goto out_delete_dso;
467
468 while (!feof(file)) {
469 unsigned long start;
470 struct symbol *sym;
471 int line_len, len;
472 char symbol_type;
473
474 line_len = getline(&line, &n, file);
475 if (line_len < 0)
476 break;
477
478 if (!line)
479 goto out_delete_dso;
480
481 line[--line_len] = '\0'; /* \n */
482
483 len = hex2long(line, &start);
484
485 len++;
486 if (len + 2 >= line_len)
487 continue;
488
489 symbol_type = toupper(line[len]);
490 /*
491 * We're interested only in code ('T'ext)
492 */
493 if (symbol_type != 'T' && symbol_type != 'W')
494 continue;
495 /*
496 * Well fix up the end later, when we have all sorted.
497 */
498 sym = symbol__new(start, 0xdead, line + len + 2);
499
500 if (sym == NULL)
501 goto out_delete_dso;
502
503 dso__insert_symbol(kernel_dso, sym);
504 }
505
506 /*
507 * Now that we have all sorted out, just set the ->end of all
508 * symbols
509 */
510 prevnd = rb_first(&kernel_dso->syms);
511
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
523 dsos__add(kernel_dso);
524 free(line);
525 fclose(file);
526
527 return 0;
528
529 out_delete_line:
530 free(line);
531 out_delete_dso:
532 dso__delete(kernel_dso);
533 return -1;
534 }
535
536 static 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
561 fail_load:
562 dso__delete(kernel_dso);
563 fail_open:
564 close(fd);
565 kallsyms:
566 return load_kallsyms();
567 }
568
569 struct map {
570 struct list_head node;
571 uint64_t start;
572 uint64_t end;
573 uint64_t pgoff;
574 struct dso *dso;
575 };
576
577 static 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;
591 out_delete:
592 free(self);
593 return NULL;
594 }
595
596 struct thread;
597
598 static const char *thread__name(struct thread *self, char *bf, size_t size);
599
600 struct thread {
601 struct rb_node rb_node;
602 struct list_head maps;
603 pid_t pid;
604 char *comm;
605 };
606
607 static 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
616 static 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);
624 }
625
626 return self;
627 }
628
629 static int thread__set_comm(struct thread *self, const char *comm)
630 {
631 self->comm = strdup(comm);
632 return self->comm ? 0 : -ENOMEM;
633 }
634
635 static struct rb_root threads;
636
637 static struct thread *threads__findnew(pid_t pid)
638 {
639 struct rb_node **p = &threads.rb_node;
640 struct rb_node *parent = NULL;
641 struct thread *th;
642
643 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;
654 }
655
656 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;
662 }
663
664 static void thread__insert_map(struct thread *self, struct map *map)
665 {
666 list_add_tail(&map->node, &self->maps);
667 }
668
669 static struct map *thread__find_map(struct thread *self, uint64_t ip)
670 {
671 struct map *pos;
672
673 if (self == NULL)
674 return NULL;
675
676 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
683 /*
684 * histogram, sorted on item, collects counts
685 */
686
687 static struct rb_root hist;
688
689 struct 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
702 static int64_t
703 hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
704 {
705 uint64_t ip_l, ip_r;
706 int cmp = right->thread->pid - left->thread->pid;
707
708 if (cmp)
709 return cmp;
710
711 if (left->sym == right->sym)
712 return 0;
713
714 ip_l = left->sym ? left->sym->start : left->ip;
715 ip_r = right->sym ? right->sym->start : right->ip;
716
717 return (int64_t)(ip_r - ip_l);
718 }
719
720 static int
721 hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
722 struct symbol *sym, uint64_t ip, char level)
723 {
724 struct rb_node **p = &hist.rb_node;
725 struct rb_node *parent = NULL;
726 struct hist_entry *he;
727 struct hist_entry entry = {
728 .thread = thread,
729 .map = map,
730 .dso = dso,
731 .sym = sym,
732 .ip = ip,
733 .level = level,
734 .count = 1,
735 };
736 int cmp;
737
738 while (*p != NULL) {
739 parent = *p;
740 he = rb_entry(parent, struct hist_entry, rb_node);
741
742 cmp = hist_entry__cmp(&entry, he);
743
744 if (!cmp) {
745 he->count++;
746 return 0;
747 }
748
749 if (cmp < 0)
750 p = &(*p)->rb_left;
751 else
752 p = &(*p)->rb_right;
753 }
754
755 he = malloc(sizeof(*he));
756 if (!he)
757 return -ENOMEM;
758 *he = entry;
759 rb_link_node(&he->rb_node, parent, p);
760 rb_insert_color(&he->rb_node, &hist);
761
762 return 0;
763 }
764
765 static size_t
766 hist_entry__fprintf(FILE *fp, struct hist_entry *self, uint64_t total_samples)
767 {
768 char bf[32];
769 size_t ret;
770
771 if (total_samples) {
772 ret = fprintf(fp, "%5.2f%% ",
773 (self->count * 100.0) / total_samples);
774 } else
775 ret = fprintf(fp, "%12d ", self->count);
776
777 ret += fprintf(fp, "%14s [%c] ",
778 thread__name(self->thread, bf, sizeof(bf)),
779 self->level);
780
781 if (verbose)
782 ret += fprintf(fp, "%#018llx ", (unsigned long long)self->ip);
783
784 if (self->level != '.')
785 ret += fprintf(fp, "%s\n",
786 self->sym ? self->sym->name : "<unknown>");
787 else
788 ret += fprintf(fp, "%s: %s\n",
789 self->dso ? self->dso->name : "<unknown>",
790 self->sym ? self->sym->name : "<unknown>");
791 return ret;
792 }
793
794 /*
795 * reverse the map, sort on count.
796 */
797
798 static struct rb_root output_hists;
799
800 static void output__insert_entry(struct hist_entry *he)
801 {
802 struct rb_node **p = &output_hists.rb_node;
803 struct rb_node *parent = NULL;
804 struct hist_entry *iter;
805
806 while (*p != NULL) {
807 parent = *p;
808 iter = rb_entry(parent, struct hist_entry, rb_node);
809
810 if (he->count > iter->count)
811 p = &(*p)->rb_left;
812 else
813 p = &(*p)->rb_right;
814 }
815
816 rb_link_node(&he->rb_node, parent, p);
817 rb_insert_color(&he->rb_node, &output_hists);
818 }
819
820 static void output__resort(void)
821 {
822 struct rb_node *next = rb_first(&hist);
823 struct hist_entry *n;
824
825 while (next) {
826 n = rb_entry(next, struct hist_entry, rb_node);
827 next = rb_next(&n->rb_node);
828
829 rb_erase(&n->rb_node, &hist);
830 output__insert_entry(n);
831 }
832 }
833
834 static size_t output__fprintf(FILE *fp, uint64_t total_samples)
835 {
836 struct hist_entry *pos;
837 struct rb_node *nd;
838 size_t ret = 0;
839
840 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
841 pos = rb_entry(nd, struct hist_entry, rb_node);
842 ret += hist_entry__fprintf(fp, pos, total_samples);
843 }
844
845 return ret;
846 }
847
848
849 static int __cmd_report(void)
850 {
851 unsigned long offset = 0;
852 unsigned long head = 0;
853 struct stat stat;
854 char *buf;
855 event_t *event;
856 int ret, rc = EXIT_FAILURE;
857 uint32_t size;
858 unsigned long total = 0, total_mmap = 0, total_comm = 0, total_unknown = 0;
859
860 input = open(input_name, O_RDONLY);
861 if (input < 0) {
862 perror("failed to open file");
863 exit(-1);
864 }
865
866 ret = fstat(input, &stat);
867 if (ret < 0) {
868 perror("failed to stat file");
869 exit(-1);
870 }
871
872 if (!stat.st_size) {
873 fprintf(stderr, "zero-sized file, nothing to do!\n");
874 exit(0);
875 }
876
877 if (load_kernel() < 0) {
878 perror("failed to open kallsyms");
879 return EXIT_FAILURE;
880 }
881
882 remap:
883 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
884 MAP_SHARED, input, offset);
885 if (buf == MAP_FAILED) {
886 perror("failed to mmap file");
887 exit(-1);
888 }
889
890 more:
891 event = (event_t *)(buf + head);
892
893 size = event->header.size;
894 if (!size)
895 size = 8;
896
897 if (head + event->header.size >= page_size * mmap_window) {
898 unsigned long shift = page_size * (head / page_size);
899 int ret;
900
901 ret = munmap(buf, page_size * mmap_window);
902 assert(ret == 0);
903
904 offset += shift;
905 head -= shift;
906 goto remap;
907 }
908
909 size = event->header.size;
910 if (!size)
911 goto broken_event;
912
913 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
914 char level;
915 int show = 0;
916 struct dso *dso = NULL;
917 struct thread *thread = threads__findnew(event->ip.pid);
918 uint64_t ip = event->ip.ip;
919 struct map *map = NULL;
920
921 if (dump_trace) {
922 fprintf(stderr, "%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
923 (void *)(offset + head),
924 (void *)(long)(event->header.size),
925 event->header.misc,
926 event->ip.pid,
927 (void *)(long)ip);
928 }
929
930 if (thread == NULL) {
931 fprintf(stderr, "problem processing %d event, bailing out\n",
932 event->header.type);
933 goto done;
934 }
935
936 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
937 show = SHOW_KERNEL;
938 level = 'k';
939
940 dso = kernel_dso;
941
942 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
943
944 show = SHOW_USER;
945 level = '.';
946
947 map = thread__find_map(thread, ip);
948 if (map != NULL) {
949 dso = map->dso;
950 ip -= map->start + map->pgoff;
951 }
952
953 } else {
954 show = SHOW_HV;
955 level = 'H';
956 }
957
958 if (show & show_mask) {
959 struct symbol *sym = dso__find_symbol(dso, ip);
960
961 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
962 fprintf(stderr,
963 "problem incrementing symbol count, bailing out\n");
964 goto done;
965 }
966 }
967 total++;
968 } else switch (event->header.type) {
969 case PERF_EVENT_MMAP: {
970 struct thread *thread = threads__findnew(event->mmap.pid);
971 struct map *map = map__new(&event->mmap);
972
973 if (dump_trace) {
974 fprintf(stderr, "%p [%p]: PERF_EVENT_MMAP: [%p(%p) @ %p]: %s\n",
975 (void *)(offset + head),
976 (void *)(long)(event->header.size),
977 (void *)(long)event->mmap.start,
978 (void *)(long)event->mmap.len,
979 (void *)(long)event->mmap.pgoff,
980 event->mmap.filename);
981 }
982 if (thread == NULL || map == NULL) {
983 fprintf(stderr, "problem processing PERF_EVENT_MMAP, bailing out\n");
984 goto done;
985 }
986 thread__insert_map(thread, map);
987 total_mmap++;
988 break;
989 }
990 case PERF_EVENT_COMM: {
991 struct thread *thread = threads__findnew(event->comm.pid);
992
993 if (dump_trace) {
994 fprintf(stderr, "%p [%p]: PERF_EVENT_COMM: %s:%d\n",
995 (void *)(offset + head),
996 (void *)(long)(event->header.size),
997 event->comm.comm, event->comm.pid);
998 }
999 if (thread == NULL ||
1000 thread__set_comm(thread, event->comm.comm)) {
1001 fprintf(stderr, "problem processing PERF_EVENT_COMM, bailing out\n");
1002 goto done;
1003 }
1004 total_comm++;
1005 break;
1006 }
1007 default: {
1008 broken_event:
1009 if (dump_trace)
1010 fprintf(stderr, "%p [%p]: skipping unknown header type: %d\n",
1011 (void *)(offset + head),
1012 (void *)(long)(event->header.size),
1013 event->header.type);
1014
1015 total_unknown++;
1016
1017 /*
1018 * assume we lost track of the stream, check alignment, and
1019 * increment a single u64 in the hope to catch on again 'soon'.
1020 */
1021
1022 if (unlikely(head & 7))
1023 head &= ~7ULL;
1024
1025 size = 8;
1026 }
1027 }
1028
1029 head += size;
1030
1031 if (offset + head < stat.st_size)
1032 goto more;
1033
1034 rc = EXIT_SUCCESS;
1035 done:
1036 close(input);
1037
1038 if (dump_trace) {
1039 fprintf(stderr, " IP events: %10ld\n", total);
1040 fprintf(stderr, " mmap events: %10ld\n", total_mmap);
1041 fprintf(stderr, " comm events: %10ld\n", total_comm);
1042 fprintf(stderr, " unknown events: %10ld\n", total_unknown);
1043
1044 return 0;
1045 }
1046
1047 if (verbose >= 2)
1048 dsos__fprintf(stdout);
1049
1050 output__resort();
1051 output__fprintf(stdout, total);
1052
1053 return rc;
1054 }
1055
1056 static const char * const report_usage[] = {
1057 "perf report [<options>] <command>",
1058 NULL
1059 };
1060
1061 static const struct option options[] = {
1062 OPT_STRING('i', "input", &input_name, "file",
1063 "input file name"),
1064 OPT_BOOLEAN('v', "verbose", &verbose,
1065 "be more verbose (show symbol address, etc)"),
1066 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1067 "dump raw trace in ASCII"),
1068 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1069 OPT_END()
1070 };
1071
1072 int cmd_report(int argc, const char **argv, const char *prefix)
1073 {
1074 elf_version(EV_CURRENT);
1075
1076 page_size = getpagesize();
1077
1078 parse_options(argc, argv, options, report_usage, 0);
1079
1080 setup_pager();
1081
1082 return __cmd_report();
1083 }
This page took 0.07065 seconds and 5 git commands to generate.