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.c146
1 files changed, 124 insertions, 22 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index b20a4b6e31b7..8b2ec882e6e0 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -31,13 +31,14 @@
31static char const *input_name = "perf.data"; 31static char const *input_name = "perf.data";
32static char *vmlinux = NULL; 32static char *vmlinux = NULL;
33 33
34static char default_sort_order[] = "comm,dso"; 34static char default_sort_order[] = "comm,dso,symbol";
35static char *sort_order = default_sort_order; 35static char *sort_order = default_sort_order;
36static char *dso_list_str, *comm_list_str, *sym_list_str, 36static char *dso_list_str, *comm_list_str, *sym_list_str,
37 *col_width_list_str; 37 *col_width_list_str;
38static struct strlist *dso_list, *comm_list, *sym_list; 38static struct strlist *dso_list, *comm_list, *sym_list;
39static char *field_sep; 39static char *field_sep;
40 40
41static int force;
41static int input; 42static int input;
42static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 43static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
43 44
@@ -68,7 +69,7 @@ static int callchain;
68 69
69static 70static
70struct callchain_param callchain_param = { 71struct callchain_param callchain_param = {
71 .mode = CHAIN_GRAPH_ABS, 72 .mode = CHAIN_GRAPH_REL,
72 .min_percent = 0.5 73 .min_percent = 0.5
73}; 74};
74 75
@@ -99,6 +100,7 @@ struct comm_event {
99struct fork_event { 100struct fork_event {
100 struct perf_event_header header; 101 struct perf_event_header header;
101 u32 pid, ppid; 102 u32 pid, ppid;
103 u32 tid, ptid;
102}; 104};
103 105
104struct lost_event { 106struct lost_event {
@@ -111,7 +113,9 @@ struct read_event {
111 struct perf_event_header header; 113 struct perf_event_header header;
112 u32 pid,tid; 114 u32 pid,tid;
113 u64 value; 115 u64 value;
114 u64 format[3]; 116 u64 time_enabled;
117 u64 time_running;
118 u64 id;
115}; 119};
116 120
117typedef union event_union { 121typedef union event_union {
@@ -252,7 +256,7 @@ static int strcommon(const char *pathname)
252{ 256{
253 int n = 0; 257 int n = 0;
254 258
255 while (pathname[n] == cwd[n] && n < cwdlen) 259 while (n < cwdlen && pathname[n] == cwd[n])
256 ++n; 260 ++n;
257 261
258 return n; 262 return n;
@@ -697,7 +701,8 @@ sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
697 size_t ret = 0; 701 size_t ret = 0;
698 702
699 if (verbose) 703 if (verbose)
700 ret += repsep_fprintf(fp, "%#018llx ", (u64)self->ip); 704 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
705 dso__symtab_origin(self->dso));
701 706
702 ret += repsep_fprintf(fp, "[%c] ", self->level); 707 ret += repsep_fprintf(fp, "[%c] ", self->level);
703 if (self->sym) { 708 if (self->sym) {
@@ -887,6 +892,21 @@ ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
887 return ret; 892 return ret;
888} 893}
889 894
895static struct symbol *rem_sq_bracket;
896static struct callchain_list rem_hits;
897
898static void init_rem_hits(void)
899{
900 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
901 if (!rem_sq_bracket) {
902 fprintf(stderr, "Not enough memory to display remaining hits\n");
903 return;
904 }
905
906 strcpy(rem_sq_bracket->name, "[...]");
907 rem_hits.sym = rem_sq_bracket;
908}
909
890static size_t 910static size_t
891callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 911callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
892 u64 total_samples, int depth, int depth_mask) 912 u64 total_samples, int depth, int depth_mask)
@@ -896,25 +916,34 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
896 struct callchain_list *chain; 916 struct callchain_list *chain;
897 int new_depth_mask = depth_mask; 917 int new_depth_mask = depth_mask;
898 u64 new_total; 918 u64 new_total;
919 u64 remaining;
899 size_t ret = 0; 920 size_t ret = 0;
900 int i; 921 int i;
901 922
902 if (callchain_param.mode == CHAIN_GRAPH_REL) 923 if (callchain_param.mode == CHAIN_GRAPH_REL)
903 new_total = self->cumul_hit; 924 new_total = self->children_hit;
904 else 925 else
905 new_total = total_samples; 926 new_total = total_samples;
906 927
928 remaining = new_total;
929
907 node = rb_first(&self->rb_root); 930 node = rb_first(&self->rb_root);
908 while (node) { 931 while (node) {
932 u64 cumul;
933
909 child = rb_entry(node, struct callchain_node, rb_node); 934 child = rb_entry(node, struct callchain_node, rb_node);
935 cumul = cumul_hits(child);
936 remaining -= cumul;
910 937
911 /* 938 /*
912 * The depth mask manages the output of pipes that show 939 * The depth mask manages the output of pipes that show
913 * the depth. We don't want to keep the pipes of the current 940 * the depth. We don't want to keep the pipes of the current
914 * level for the last child of this depth 941 * level for the last child of this depth.
942 * Except if we have remaining filtered hits. They will
943 * supersede the last child
915 */ 944 */
916 next = rb_next(node); 945 next = rb_next(node);
917 if (!next) 946 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
918 new_depth_mask &= ~(1 << (depth - 1)); 947 new_depth_mask &= ~(1 << (depth - 1));
919 948
920 /* 949 /*
@@ -929,7 +958,7 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
929 ret += ipchain__fprintf_graph(fp, chain, depth, 958 ret += ipchain__fprintf_graph(fp, chain, depth,
930 new_depth_mask, i++, 959 new_depth_mask, i++,
931 new_total, 960 new_total,
932 child->cumul_hit); 961 cumul);
933 } 962 }
934 ret += callchain__fprintf_graph(fp, child, new_total, 963 ret += callchain__fprintf_graph(fp, child, new_total,
935 depth + 1, 964 depth + 1,
@@ -937,6 +966,19 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
937 node = next; 966 node = next;
938 } 967 }
939 968
969 if (callchain_param.mode == CHAIN_GRAPH_REL &&
970 remaining && remaining != new_total) {
971
972 if (!rem_sq_bracket)
973 return ret;
974
975 new_depth_mask &= ~(1 << (depth - 1));
976
977 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
978 new_depth_mask, 0, new_total,
979 remaining);
980 }
981
940 return ret; 982 return ret;
941} 983}
942 984
@@ -1357,6 +1399,8 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1357 unsigned int width; 1399 unsigned int width;
1358 char *col_width = col_width_list_str; 1400 char *col_width = col_width_list_str;
1359 1401
1402 init_rem_hits();
1403
1360 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples); 1404 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
1361 fprintf(fp, "#\n"); 1405 fprintf(fp, "#\n");
1362 1406
@@ -1423,11 +1467,13 @@ print_entries:
1423 if (sort_order == default_sort_order && 1467 if (sort_order == default_sort_order &&
1424 parent_pattern == default_parent_pattern) { 1468 parent_pattern == default_parent_pattern) {
1425 fprintf(fp, "#\n"); 1469 fprintf(fp, "#\n");
1426 fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n"); 1470 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
1427 fprintf(fp, "#\n"); 1471 fprintf(fp, "#\n");
1428 } 1472 }
1429 fprintf(fp, "\n"); 1473 fprintf(fp, "\n");
1430 1474
1475 free(rem_sq_bracket);
1476
1431 return ret; 1477 return ret;
1432} 1478}
1433 1479
@@ -1481,11 +1527,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1481 more_data += sizeof(u64); 1527 more_data += sizeof(u64);
1482 } 1528 }
1483 1529
1484 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n", 1530 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
1485 (void *)(offset + head), 1531 (void *)(offset + head),
1486 (void *)(long)(event->header.size), 1532 (void *)(long)(event->header.size),
1487 event->header.misc, 1533 event->header.misc,
1488 event->ip.pid, 1534 event->ip.pid, event->ip.tid,
1489 (void *)(long)ip, 1535 (void *)(long)ip,
1490 (long long)period); 1536 (long long)period);
1491 1537
@@ -1545,10 +1591,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1545 if (show & show_mask) { 1591 if (show & show_mask) {
1546 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); 1592 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1547 1593
1548 if (dso_list && dso && dso->name && !strlist__has_entry(dso_list, dso->name)) 1594 if (dso_list && (!dso || !dso->name ||
1595 !strlist__has_entry(dso_list, dso->name)))
1549 return 0; 1596 return 0;
1550 1597
1551 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name)) 1598 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
1552 return 0; 1599 return 0;
1553 1600
1554 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { 1601 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
@@ -1567,10 +1614,11 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1567 struct thread *thread = threads__findnew(event->mmap.pid); 1614 struct thread *thread = threads__findnew(event->mmap.pid);
1568 struct map *map = map__new(&event->mmap); 1615 struct map *map = map__new(&event->mmap);
1569 1616
1570 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", 1617 dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1571 (void *)(offset + head), 1618 (void *)(offset + head),
1572 (void *)(long)(event->header.size), 1619 (void *)(long)(event->header.size),
1573 event->mmap.pid, 1620 event->mmap.pid,
1621 event->mmap.tid,
1574 (void *)(long)event->mmap.start, 1622 (void *)(long)event->mmap.start,
1575 (void *)(long)event->mmap.len, 1623 (void *)(long)event->mmap.len,
1576 (void *)(long)event->mmap.pgoff, 1624 (void *)(long)event->mmap.pgoff,
@@ -1608,15 +1656,27 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1608} 1656}
1609 1657
1610static int 1658static int
1611process_fork_event(event_t *event, unsigned long offset, unsigned long head) 1659process_task_event(event_t *event, unsigned long offset, unsigned long head)
1612{ 1660{
1613 struct thread *thread = threads__findnew(event->fork.pid); 1661 struct thread *thread = threads__findnew(event->fork.pid);
1614 struct thread *parent = threads__findnew(event->fork.ppid); 1662 struct thread *parent = threads__findnew(event->fork.ppid);
1615 1663
1616 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 1664 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
1617 (void *)(offset + head), 1665 (void *)(offset + head),
1618 (void *)(long)(event->header.size), 1666 (void *)(long)(event->header.size),
1619 event->fork.pid, event->fork.ppid); 1667 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1668 event->fork.pid, event->fork.tid,
1669 event->fork.ppid, event->fork.ptid);
1670
1671 /*
1672 * A thread clone will have the same PID for both
1673 * parent and child.
1674 */
1675 if (thread == parent)
1676 return 0;
1677
1678 if (event->header.type == PERF_EVENT_EXIT)
1679 return 0;
1620 1680
1621 if (!thread || !parent || thread__fork(thread, parent)) { 1681 if (!thread || !parent || thread__fork(thread, parent)) {
1622 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 1682 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
@@ -1677,14 +1737,37 @@ static void trace_event(event_t *event)
1677 dprintf(".\n"); 1737 dprintf(".\n");
1678} 1738}
1679 1739
1740static struct perf_header *header;
1741
1742static struct perf_counter_attr *perf_header__find_attr(u64 id)
1743{
1744 int i;
1745
1746 for (i = 0; i < header->attrs; i++) {
1747 struct perf_header_attr *attr = header->attr[i];
1748 int j;
1749
1750 for (j = 0; j < attr->ids; j++) {
1751 if (attr->id[j] == id)
1752 return &attr->attr;
1753 }
1754 }
1755
1756 return NULL;
1757}
1758
1680static int 1759static int
1681process_read_event(event_t *event, unsigned long offset, unsigned long head) 1760process_read_event(event_t *event, unsigned long offset, unsigned long head)
1682{ 1761{
1683 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %Lu\n", 1762 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
1763
1764 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
1684 (void *)(offset + head), 1765 (void *)(offset + head),
1685 (void *)(long)(event->header.size), 1766 (void *)(long)(event->header.size),
1686 event->read.pid, 1767 event->read.pid,
1687 event->read.tid, 1768 event->read.tid,
1769 attr ? __event_name(attr->type, attr->config)
1770 : "FAIL",
1688 event->read.value); 1771 event->read.value);
1689 1772
1690 return 0; 1773 return 0;
@@ -1706,7 +1789,8 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1706 return process_comm_event(event, offset, head); 1789 return process_comm_event(event, offset, head);
1707 1790
1708 case PERF_EVENT_FORK: 1791 case PERF_EVENT_FORK:
1709 return process_fork_event(event, offset, head); 1792 case PERF_EVENT_EXIT:
1793 return process_task_event(event, offset, head);
1710 1794
1711 case PERF_EVENT_LOST: 1795 case PERF_EVENT_LOST:
1712 return process_lost_event(event, offset, head); 1796 return process_lost_event(event, offset, head);
@@ -1729,8 +1813,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1729 return 0; 1813 return 0;
1730} 1814}
1731 1815
1732static struct perf_header *header;
1733
1734static u64 perf_header__sample_type(void) 1816static u64 perf_header__sample_type(void)
1735{ 1817{
1736 u64 sample_type = 0; 1818 u64 sample_type = 0;
@@ -1775,6 +1857,11 @@ static int __cmd_report(void)
1775 exit(-1); 1857 exit(-1);
1776 } 1858 }
1777 1859
1860 if (!force && (stat.st_uid != geteuid())) {
1861 fprintf(stderr, "file: %s not owned by current user\n", input_name);
1862 exit(-1);
1863 }
1864
1778 if (!stat.st_size) { 1865 if (!stat.st_size) {
1779 fprintf(stderr, "zero-sized file, nothing to do!\n"); 1866 fprintf(stderr, "zero-sized file, nothing to do!\n");
1780 exit(0); 1867 exit(0);
@@ -1798,6 +1885,13 @@ static int __cmd_report(void)
1798 " -g?\n"); 1885 " -g?\n");
1799 exit(-1); 1886 exit(-1);
1800 } 1887 }
1888 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1889 callchain = 1;
1890 if (register_callchain_param(&callchain_param) < 0) {
1891 fprintf(stderr, "Can't register callchain"
1892 " params\n");
1893 exit(-1);
1894 }
1801 } 1895 }
1802 1896
1803 if (load_kernel() < 0) { 1897 if (load_kernel() < 0) {
@@ -1936,6 +2030,13 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
1936 else if (!strncmp(tok, "fractal", strlen(arg))) 2030 else if (!strncmp(tok, "fractal", strlen(arg)))
1937 callchain_param.mode = CHAIN_GRAPH_REL; 2031 callchain_param.mode = CHAIN_GRAPH_REL;
1938 2032
2033 else if (!strncmp(tok, "none", strlen(arg))) {
2034 callchain_param.mode = CHAIN_NONE;
2035 callchain = 0;
2036
2037 return 0;
2038 }
2039
1939 else 2040 else
1940 return -1; 2041 return -1;
1941 2042
@@ -1969,6 +2070,7 @@ static const struct option options[] = {
1969 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 2070 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1970 "dump raw trace in ASCII"), 2071 "dump raw trace in ASCII"),
1971 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 2072 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
2073 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1972 OPT_BOOLEAN('m', "modules", &modules, 2074 OPT_BOOLEAN('m', "modules", &modules,
1973 "load module symbols - WARNING: use only with -k and LIVE kernel"), 2075 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1974 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 2076 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,