aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c236
1 files changed, 197 insertions, 39 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 5eb5566f0c95..135b7837e6bf 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -15,8 +15,11 @@
15#include "util/rbtree.h" 15#include "util/rbtree.h"
16#include "util/symbol.h" 16#include "util/symbol.h"
17#include "util/string.h" 17#include "util/string.h"
18#include "util/callchain.h"
19#include "util/strlist.h"
18 20
19#include "perf.h" 21#include "perf.h"
22#include "util/header.h"
20 23
21#include "util/parse-options.h" 24#include "util/parse-options.h"
22#include "util/parse-events.h" 25#include "util/parse-events.h"
@@ -30,6 +33,8 @@ static char *vmlinux = NULL;
30 33
31static char default_sort_order[] = "comm,dso"; 34static char default_sort_order[] = "comm,dso";
32static char *sort_order = default_sort_order; 35static char *sort_order = default_sort_order;
36static char *dso_list_str, *comm_list_str, *sym_list_str;
37static struct strlist *dso_list, *comm_list, *sym_list;
33 38
34static int input; 39static int input;
35static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 40static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
@@ -51,6 +56,9 @@ static char *parent_pattern = default_parent_pattern;
51static regex_t parent_regex; 56static regex_t parent_regex;
52 57
53static int exclude_other = 1; 58static int exclude_other = 1;
59static int callchain;
60
61static u64 sample_type;
54 62
55struct ip_event { 63struct ip_event {
56 struct perf_event_header header; 64 struct perf_event_header header;
@@ -59,11 +67,6 @@ struct ip_event {
59 unsigned char __more_data[]; 67 unsigned char __more_data[];
60}; 68};
61 69
62struct ip_callchain {
63 u64 nr;
64 u64 ips[0];
65};
66
67struct mmap_event { 70struct mmap_event {
68 struct perf_event_header header; 71 struct perf_event_header header;
69 u32 pid, tid; 72 u32 pid, tid;
@@ -97,6 +100,13 @@ struct lost_event {
97 u64 lost; 100 u64 lost;
98}; 101};
99 102
103struct read_event {
104 struct perf_event_header header;
105 u32 pid,tid;
106 u64 value;
107 u64 format[3];
108};
109
100typedef union event_union { 110typedef union event_union {
101 struct perf_event_header header; 111 struct perf_event_header header;
102 struct ip_event ip; 112 struct ip_event ip;
@@ -105,6 +115,7 @@ typedef union event_union {
105 struct fork_event fork; 115 struct fork_event fork;
106 struct period_event period; 116 struct period_event period;
107 struct lost_event lost; 117 struct lost_event lost;
118 struct read_event read;
108} event_t; 119} event_t;
109 120
110static LIST_HEAD(dsos); 121static LIST_HEAD(dsos);
@@ -229,7 +240,7 @@ static u64 vdso__map_ip(struct map *map, u64 ip)
229 240
230static inline int is_anon_memory(const char *filename) 241static inline int is_anon_memory(const char *filename)
231{ 242{
232 return strcmp(filename, "//anon") == 0; 243 return strcmp(filename, "//anon") == 0;
233} 244}
234 245
235static struct map *map__new(struct mmap_event *event) 246static struct map *map__new(struct mmap_event *event)
@@ -400,9 +411,27 @@ static void thread__insert_map(struct thread *self, struct map *map)
400 411
401 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 412 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
402 if (map__overlap(pos, map)) { 413 if (map__overlap(pos, map)) {
403 list_del_init(&pos->node); 414 if (verbose >= 2) {
404 /* XXX leaks dsos */ 415 printf("overlapping maps:\n");
405 free(pos); 416 map__fprintf(map, stdout);
417 map__fprintf(pos, stdout);
418 }
419
420 if (map->start <= pos->start && map->end > pos->start)
421 pos->start = map->end;
422
423 if (map->end >= pos->end && map->start < pos->end)
424 pos->end = map->start;
425
426 if (verbose >= 2) {
427 printf("after collision:\n");
428 map__fprintf(pos, stdout);
429 }
430
431 if (pos->start >= pos->end) {
432 list_del_init(&pos->node);
433 free(pos);
434 }
406 } 435 }
407 } 436 }
408 437
@@ -464,17 +493,19 @@ static size_t threads__fprintf(FILE *fp)
464static struct rb_root hist; 493static struct rb_root hist;
465 494
466struct hist_entry { 495struct hist_entry {
467 struct rb_node rb_node; 496 struct rb_node rb_node;
468 497
469 struct thread *thread; 498 struct thread *thread;
470 struct map *map; 499 struct map *map;
471 struct dso *dso; 500 struct dso *dso;
472 struct symbol *sym; 501 struct symbol *sym;
473 struct symbol *parent; 502 struct symbol *parent;
474 u64 ip; 503 u64 ip;
475 char level; 504 char level;
476 505 struct callchain_node callchain;
477 u64 count; 506 struct rb_root sorted_chain;
507
508 u64 count;
478}; 509};
479 510
480/* 511/*
@@ -745,6 +776,48 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
745} 776}
746 777
747static size_t 778static size_t
779callchain__fprintf(FILE *fp, struct callchain_node *self, u64 total_samples)
780{
781 struct callchain_list *chain;
782 size_t ret = 0;
783
784 if (!self)
785 return 0;
786
787 ret += callchain__fprintf(fp, self->parent, total_samples);
788
789
790 list_for_each_entry(chain, &self->val, list)
791 ret += fprintf(fp, " %p\n", (void *)chain->ip);
792
793 return ret;
794}
795
796static size_t
797hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
798 u64 total_samples)
799{
800 struct rb_node *rb_node;
801 struct callchain_node *chain;
802 size_t ret = 0;
803
804 rb_node = rb_first(&self->sorted_chain);
805 while (rb_node) {
806 double percent;
807
808 chain = rb_entry(rb_node, struct callchain_node, rb_node);
809 percent = chain->hit * 100.0 / total_samples;
810 ret += fprintf(fp, " %6.2f%%\n", percent);
811 ret += callchain__fprintf(fp, chain, total_samples);
812 ret += fprintf(fp, "\n");
813 rb_node = rb_next(rb_node);
814 }
815
816 return ret;
817}
818
819
820static size_t
748hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples) 821hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
749{ 822{
750 struct sort_entry *se; 823 struct sort_entry *se;
@@ -784,6 +857,9 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
784 857
785 ret += fprintf(fp, "\n"); 858 ret += fprintf(fp, "\n");
786 859
860 if (callchain)
861 hist_entry_callchain__fprintf(fp, self, total_samples);
862
787 return ret; 863 return ret;
788} 864}
789 865
@@ -797,7 +873,7 @@ resolve_symbol(struct thread *thread, struct map **mapp,
797{ 873{
798 struct dso *dso = dsop ? *dsop : NULL; 874 struct dso *dso = dsop ? *dsop : NULL;
799 struct map *map = mapp ? *mapp : NULL; 875 struct map *map = mapp ? *mapp : NULL;
800 uint64_t ip = *ipp; 876 u64 ip = *ipp;
801 877
802 if (!thread) 878 if (!thread)
803 return NULL; 879 return NULL;
@@ -814,7 +890,6 @@ resolve_symbol(struct thread *thread, struct map **mapp,
814 *mapp = map; 890 *mapp = map;
815got_map: 891got_map:
816 ip = map->map_ip(map, ip); 892 ip = map->map_ip(map, ip);
817 *ipp = ip;
818 893
819 dso = map->dso; 894 dso = map->dso;
820 } else { 895 } else {
@@ -828,6 +903,8 @@ got_map:
828 dso = kernel_dso; 903 dso = kernel_dso;
829 } 904 }
830 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 905 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
906 dprintf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
907 *ipp = ip;
831 908
832 if (dsop) 909 if (dsop)
833 *dsop = dso; 910 *dsop = dso;
@@ -867,6 +944,7 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
867 .level = level, 944 .level = level,
868 .count = count, 945 .count = count,
869 .parent = NULL, 946 .parent = NULL,
947 .sorted_chain = RB_ROOT
870 }; 948 };
871 int cmp; 949 int cmp;
872 950
@@ -909,6 +987,8 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
909 987
910 if (!cmp) { 988 if (!cmp) {
911 he->count += count; 989 he->count += count;
990 if (callchain)
991 append_chain(&he->callchain, chain);
912 return 0; 992 return 0;
913 } 993 }
914 994
@@ -922,6 +1002,10 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
922 if (!he) 1002 if (!he)
923 return -ENOMEM; 1003 return -ENOMEM;
924 *he = entry; 1004 *he = entry;
1005 if (callchain) {
1006 callchain_init(&he->callchain);
1007 append_chain(&he->callchain, chain);
1008 }
925 rb_link_node(&he->rb_node, parent, p); 1009 rb_link_node(&he->rb_node, parent, p);
926 rb_insert_color(&he->rb_node, &hist); 1010 rb_insert_color(&he->rb_node, &hist);
927 1011
@@ -998,6 +1082,9 @@ static void output__insert_entry(struct hist_entry *he)
998 struct rb_node *parent = NULL; 1082 struct rb_node *parent = NULL;
999 struct hist_entry *iter; 1083 struct hist_entry *iter;
1000 1084
1085 if (callchain)
1086 sort_chain_to_rbtree(&he->sorted_chain, &he->callchain);
1087
1001 while (*p != NULL) { 1088 while (*p != NULL) {
1002 parent = *p; 1089 parent = *p;
1003 iter = rb_entry(parent, struct hist_entry, rb_node); 1090 iter = rb_entry(parent, struct hist_entry, rb_node);
@@ -1115,7 +1202,7 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
1115} 1202}
1116 1203
1117static int 1204static int
1118process_overflow_event(event_t *event, unsigned long offset, unsigned long head) 1205process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1119{ 1206{
1120 char level; 1207 char level;
1121 int show = 0; 1208 int show = 0;
@@ -1127,12 +1214,12 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1127 void *more_data = event->ip.__more_data; 1214 void *more_data = event->ip.__more_data;
1128 struct ip_callchain *chain = NULL; 1215 struct ip_callchain *chain = NULL;
1129 1216
1130 if (event->header.type & PERF_SAMPLE_PERIOD) { 1217 if (sample_type & PERF_SAMPLE_PERIOD) {
1131 period = *(u64 *)more_data; 1218 period = *(u64 *)more_data;
1132 more_data += sizeof(u64); 1219 more_data += sizeof(u64);
1133 } 1220 }
1134 1221
1135 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n", 1222 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n",
1136 (void *)(offset + head), 1223 (void *)(offset + head),
1137 (void *)(long)(event->header.size), 1224 (void *)(long)(event->header.size),
1138 event->header.misc, 1225 event->header.misc,
@@ -1140,7 +1227,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1140 (void *)(long)ip, 1227 (void *)(long)ip,
1141 (long long)period); 1228 (long long)period);
1142 1229
1143 if (event->header.type & PERF_SAMPLE_CALLCHAIN) { 1230 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
1144 int i; 1231 int i;
1145 1232
1146 chain = (void *)more_data; 1233 chain = (void *)more_data;
@@ -1166,6 +1253,9 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1166 return -1; 1253 return -1;
1167 } 1254 }
1168 1255
1256 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1257 return 0;
1258
1169 if (event->header.misc & PERF_EVENT_MISC_KERNEL) { 1259 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
1170 show = SHOW_KERNEL; 1260 show = SHOW_KERNEL;
1171 level = 'k'; 1261 level = 'k';
@@ -1188,6 +1278,12 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1188 if (show & show_mask) { 1278 if (show & show_mask) {
1189 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); 1279 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1190 1280
1281 if (dso_list && dso && dso->name && !strlist__has_entry(dso_list, dso->name))
1282 return 0;
1283
1284 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
1285 return 0;
1286
1191 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { 1287 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
1192 eprintf("problem incrementing symbol count, skipping event\n"); 1288 eprintf("problem incrementing symbol count, skipping event\n");
1193 return -1; 1289 return -1;
@@ -1328,14 +1424,27 @@ static void trace_event(event_t *event)
1328} 1424}
1329 1425
1330static int 1426static int
1427process_read_event(event_t *event, unsigned long offset, unsigned long head)
1428{
1429 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %Lu\n",
1430 (void *)(offset + head),
1431 (void *)(long)(event->header.size),
1432 event->read.pid,
1433 event->read.tid,
1434 event->read.value);
1435
1436 return 0;
1437}
1438
1439static int
1331process_event(event_t *event, unsigned long offset, unsigned long head) 1440process_event(event_t *event, unsigned long offset, unsigned long head)
1332{ 1441{
1333 trace_event(event); 1442 trace_event(event);
1334 1443
1335 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1336 return process_overflow_event(event, offset, head);
1337
1338 switch (event->header.type) { 1444 switch (event->header.type) {
1445 case PERF_EVENT_SAMPLE:
1446 return process_sample_event(event, offset, head);
1447
1339 case PERF_EVENT_MMAP: 1448 case PERF_EVENT_MMAP:
1340 return process_mmap_event(event, offset, head); 1449 return process_mmap_event(event, offset, head);
1341 1450
@@ -1351,6 +1460,9 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1351 case PERF_EVENT_LOST: 1460 case PERF_EVENT_LOST:
1352 return process_lost_event(event, offset, head); 1461 return process_lost_event(event, offset, head);
1353 1462
1463 case PERF_EVENT_READ:
1464 return process_read_event(event, offset, head);
1465
1354 /* 1466 /*
1355 * We dont process them right now but they are fine: 1467 * We dont process them right now but they are fine:
1356 */ 1468 */
@@ -1366,13 +1478,30 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1366 return 0; 1478 return 0;
1367} 1479}
1368 1480
1369static struct perf_file_header file_header; 1481static struct perf_header *header;
1482
1483static u64 perf_header__sample_type(void)
1484{
1485 u64 sample_type = 0;
1486 int i;
1487
1488 for (i = 0; i < header->attrs; i++) {
1489 struct perf_header_attr *attr = header->attr[i];
1490
1491 if (!sample_type)
1492 sample_type = attr->attr.sample_type;
1493 else if (sample_type != attr->attr.sample_type)
1494 die("non matching sample_type");
1495 }
1496
1497 return sample_type;
1498}
1370 1499
1371static int __cmd_report(void) 1500static int __cmd_report(void)
1372{ 1501{
1373 int ret, rc = EXIT_FAILURE; 1502 int ret, rc = EXIT_FAILURE;
1374 unsigned long offset = 0; 1503 unsigned long offset = 0;
1375 unsigned long head = sizeof(file_header); 1504 unsigned long head, shift;
1376 struct stat stat; 1505 struct stat stat;
1377 event_t *event; 1506 event_t *event;
1378 uint32_t size; 1507 uint32_t size;
@@ -1400,13 +1529,12 @@ static int __cmd_report(void)
1400 exit(0); 1529 exit(0);
1401 } 1530 }
1402 1531
1403 if (read(input, &file_header, sizeof(file_header)) == -1) { 1532 header = perf_header__read(input);
1404 perror("failed to read file headers"); 1533 head = header->data_offset;
1405 exit(-1);
1406 }
1407 1534
1408 if (sort__has_parent && 1535 sample_type = perf_header__sample_type();
1409 !(file_header.sample_type & PERF_SAMPLE_CALLCHAIN)) { 1536
1537 if (sort__has_parent && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1410 fprintf(stderr, "selected --sort parent, but no callchain data\n"); 1538 fprintf(stderr, "selected --sort parent, but no callchain data\n");
1411 exit(-1); 1539 exit(-1);
1412 } 1540 }
@@ -1426,6 +1554,11 @@ static int __cmd_report(void)
1426 cwd = NULL; 1554 cwd = NULL;
1427 cwdlen = 0; 1555 cwdlen = 0;
1428 } 1556 }
1557
1558 shift = page_size * (head / page_size);
1559 offset += shift;
1560 head -= shift;
1561
1429remap: 1562remap:
1430 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, 1563 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1431 MAP_SHARED, input, offset); 1564 MAP_SHARED, input, offset);
@@ -1442,9 +1575,10 @@ more:
1442 size = 8; 1575 size = 8;
1443 1576
1444 if (head + event->header.size >= page_size * mmap_window) { 1577 if (head + event->header.size >= page_size * mmap_window) {
1445 unsigned long shift = page_size * (head / page_size);
1446 int ret; 1578 int ret;
1447 1579
1580 shift = page_size * (head / page_size);
1581
1448 ret = munmap(buf, page_size * mmap_window); 1582 ret = munmap(buf, page_size * mmap_window);
1449 assert(ret == 0); 1583 assert(ret == 0);
1450 1584
@@ -1482,7 +1616,7 @@ more:
1482 1616
1483 head += size; 1617 head += size;
1484 1618
1485 if (offset + head >= sizeof(file_header) + file_header.data_size) 1619 if (offset + head >= header->data_offset + header->data_size)
1486 goto done; 1620 goto done;
1487 1621
1488 if (offset + head < stat.st_size) 1622 if (offset + head < stat.st_size)
@@ -1536,6 +1670,13 @@ static const struct option options[] = {
1536 "regex filter to identify parent, see: '--sort parent'"), 1670 "regex filter to identify parent, see: '--sort parent'"),
1537 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 1671 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1538 "Only display entries with parent-match"), 1672 "Only display entries with parent-match"),
1673 OPT_BOOLEAN('c', "callchain", &callchain, "Display callchains"),
1674 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1675 "only consider symbols in these dsos"),
1676 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1677 "only consider symbols in these comms"),
1678 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1679 "only consider these symbols"),
1539 OPT_END() 1680 OPT_END()
1540}; 1681};
1541 1682
@@ -1554,6 +1695,19 @@ static void setup_sorting(void)
1554 free(str); 1695 free(str);
1555} 1696}
1556 1697
1698static void setup_list(struct strlist **list, const char *list_str,
1699 const char *list_name)
1700{
1701 if (list_str) {
1702 *list = strlist__new(true, list_str);
1703 if (!*list) {
1704 fprintf(stderr, "problems parsing %s list\n",
1705 list_name);
1706 exit(129);
1707 }
1708 }
1709}
1710
1557int cmd_report(int argc, const char **argv, const char *prefix) 1711int cmd_report(int argc, const char **argv, const char *prefix)
1558{ 1712{
1559 symbol__init(); 1713 symbol__init();
@@ -1575,6 +1729,10 @@ int cmd_report(int argc, const char **argv, const char *prefix)
1575 if (argc) 1729 if (argc)
1576 usage_with_options(report_usage, options); 1730 usage_with_options(report_usage, options);
1577 1731
1732 setup_list(&dso_list, dso_list_str, "dso");
1733 setup_list(&comm_list, comm_list_str, "comm");
1734 setup_list(&sym_list, sym_list_str, "symbol");
1735
1578 setup_pager(); 1736 setup_pager();
1579 1737
1580 return __cmd_report(); 1738 return __cmd_report();