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.c399
1 files changed, 305 insertions, 94 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 4e5cc266311e..8b2ec882e6e0 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -31,11 +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;
37static struct strlist *dso_list, *comm_list, *sym_list; 38static struct strlist *dso_list, *comm_list, *sym_list;
39static char *field_sep;
38 40
41static int force;
39static int input; 42static int input;
40static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 43static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
41 44
@@ -49,6 +52,7 @@ static int verbose;
49static int modules; 52static int modules;
50 53
51static int full_paths; 54static int full_paths;
55static int show_nr_samples;
52 56
53static unsigned long page_size; 57static unsigned long page_size;
54static unsigned long mmap_window = 32; 58static unsigned long mmap_window = 32;
@@ -65,7 +69,7 @@ static int callchain;
65 69
66static 70static
67struct callchain_param callchain_param = { 71struct callchain_param callchain_param = {
68 .mode = CHAIN_GRAPH_ABS, 72 .mode = CHAIN_GRAPH_REL,
69 .min_percent = 0.5 73 .min_percent = 0.5
70}; 74};
71 75
@@ -96,13 +100,7 @@ struct comm_event {
96struct fork_event { 100struct fork_event {
97 struct perf_event_header header; 101 struct perf_event_header header;
98 u32 pid, ppid; 102 u32 pid, ppid;
99}; 103 u32 tid, ptid;
100
101struct period_event {
102 struct perf_event_header header;
103 u64 time;
104 u64 id;
105 u64 sample_period;
106}; 104};
107 105
108struct lost_event { 106struct lost_event {
@@ -115,7 +113,9 @@ struct read_event {
115 struct perf_event_header header; 113 struct perf_event_header header;
116 u32 pid,tid; 114 u32 pid,tid;
117 u64 value; 115 u64 value;
118 u64 format[3]; 116 u64 time_enabled;
117 u64 time_running;
118 u64 id;
119}; 119};
120 120
121typedef union event_union { 121typedef union event_union {
@@ -124,11 +124,37 @@ typedef union event_union {
124 struct mmap_event mmap; 124 struct mmap_event mmap;
125 struct comm_event comm; 125 struct comm_event comm;
126 struct fork_event fork; 126 struct fork_event fork;
127 struct period_event period;
128 struct lost_event lost; 127 struct lost_event lost;
129 struct read_event read; 128 struct read_event read;
130} event_t; 129} event_t;
131 130
131static int repsep_fprintf(FILE *fp, const char *fmt, ...)
132{
133 int n;
134 va_list ap;
135
136 va_start(ap, fmt);
137 if (!field_sep)
138 n = vfprintf(fp, fmt, ap);
139 else {
140 char *bf = NULL;
141 n = vasprintf(&bf, fmt, ap);
142 if (n > 0) {
143 char *sep = bf;
144 while (1) {
145 sep = strchr(sep, *field_sep);
146 if (sep == NULL)
147 break;
148 *sep = '.';
149 }
150 }
151 fputs(bf, fp);
152 free(bf);
153 }
154 va_end(ap);
155 return n;
156}
157
132static LIST_HEAD(dsos); 158static LIST_HEAD(dsos);
133static struct dso *kernel_dso; 159static struct dso *kernel_dso;
134static struct dso *vdso; 160static struct dso *vdso;
@@ -230,7 +256,7 @@ static int strcommon(const char *pathname)
230{ 256{
231 int n = 0; 257 int n = 0;
232 258
233 while (pathname[n] == cwd[n] && n < cwdlen) 259 while (n < cwdlen && pathname[n] == cwd[n])
234 ++n; 260 ++n;
235 261
236 return n; 262 return n;
@@ -360,12 +386,28 @@ static struct thread *thread__new(pid_t pid)
360 return self; 386 return self;
361} 387}
362 388
389static unsigned int dsos__col_width,
390 comms__col_width,
391 threads__col_width;
392
363static int thread__set_comm(struct thread *self, const char *comm) 393static int thread__set_comm(struct thread *self, const char *comm)
364{ 394{
365 if (self->comm) 395 if (self->comm)
366 free(self->comm); 396 free(self->comm);
367 self->comm = strdup(comm); 397 self->comm = strdup(comm);
368 return self->comm ? 0 : -ENOMEM; 398 if (!self->comm)
399 return -ENOMEM;
400
401 if (!col_width_list_str && !field_sep &&
402 (!comm_list || strlist__has_entry(comm_list, comm))) {
403 unsigned int slen = strlen(comm);
404 if (slen > comms__col_width) {
405 comms__col_width = slen;
406 threads__col_width = slen + 6;
407 }
408 }
409
410 return 0;
369} 411}
370 412
371static size_t thread__fprintf(struct thread *self, FILE *fp) 413static size_t thread__fprintf(struct thread *self, FILE *fp)
@@ -536,7 +578,9 @@ struct sort_entry {
536 578
537 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 579 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
538 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 580 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
539 size_t (*print)(FILE *fp, struct hist_entry *); 581 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
582 unsigned int *width;
583 bool elide;
540}; 584};
541 585
542static int64_t cmp_null(void *l, void *r) 586static int64_t cmp_null(void *l, void *r)
@@ -558,15 +602,17 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
558} 602}
559 603
560static size_t 604static size_t
561sort__thread_print(FILE *fp, struct hist_entry *self) 605sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
562{ 606{
563 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); 607 return repsep_fprintf(fp, "%*s:%5d", width - 6,
608 self->thread->comm ?: "", self->thread->pid);
564} 609}
565 610
566static struct sort_entry sort_thread = { 611static struct sort_entry sort_thread = {
567 .header = " Command: Pid", 612 .header = "Command: Pid",
568 .cmp = sort__thread_cmp, 613 .cmp = sort__thread_cmp,
569 .print = sort__thread_print, 614 .print = sort__thread_print,
615 .width = &threads__col_width,
570}; 616};
571 617
572/* --sort comm */ 618/* --sort comm */
@@ -590,16 +636,17 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
590} 636}
591 637
592static size_t 638static size_t
593sort__comm_print(FILE *fp, struct hist_entry *self) 639sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
594{ 640{
595 return fprintf(fp, "%16s", self->thread->comm); 641 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
596} 642}
597 643
598static struct sort_entry sort_comm = { 644static struct sort_entry sort_comm = {
599 .header = " Command", 645 .header = "Command",
600 .cmp = sort__comm_cmp, 646 .cmp = sort__comm_cmp,
601 .collapse = sort__comm_collapse, 647 .collapse = sort__comm_collapse,
602 .print = sort__comm_print, 648 .print = sort__comm_print,
649 .width = &comms__col_width,
603}; 650};
604 651
605/* --sort dso */ 652/* --sort dso */
@@ -617,18 +664,19 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
617} 664}
618 665
619static size_t 666static size_t
620sort__dso_print(FILE *fp, struct hist_entry *self) 667sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
621{ 668{
622 if (self->dso) 669 if (self->dso)
623 return fprintf(fp, "%-25s", self->dso->name); 670 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
624 671
625 return fprintf(fp, "%016llx ", (u64)self->ip); 672 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
626} 673}
627 674
628static struct sort_entry sort_dso = { 675static struct sort_entry sort_dso = {
629 .header = "Shared Object ", 676 .header = "Shared Object",
630 .cmp = sort__dso_cmp, 677 .cmp = sort__dso_cmp,
631 .print = sort__dso_print, 678 .print = sort__dso_print,
679 .width = &dsos__col_width,
632}; 680};
633 681
634/* --sort symbol */ 682/* --sort symbol */
@@ -648,22 +696,23 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
648} 696}
649 697
650static size_t 698static size_t
651sort__sym_print(FILE *fp, struct hist_entry *self) 699sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
652{ 700{
653 size_t ret = 0; 701 size_t ret = 0;
654 702
655 if (verbose) 703 if (verbose)
656 ret += fprintf(fp, "%#018llx ", (u64)self->ip); 704 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
705 dso__symtab_origin(self->dso));
657 706
707 ret += repsep_fprintf(fp, "[%c] ", self->level);
658 if (self->sym) { 708 if (self->sym) {
659 ret += fprintf(fp, "[%c] %s", 709 ret += repsep_fprintf(fp, "%s", self->sym->name);
660 self->dso == kernel_dso ? 'k' :
661 self->dso == hypervisor_dso ? 'h' : '.', self->sym->name);
662 710
663 if (self->sym->module) 711 if (self->sym->module)
664 ret += fprintf(fp, "\t[%s]", self->sym->module->name); 712 ret += repsep_fprintf(fp, "\t[%s]",
713 self->sym->module->name);
665 } else { 714 } else {
666 ret += fprintf(fp, "%#016llx", (u64)self->ip); 715 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
667 } 716 }
668 717
669 return ret; 718 return ret;
@@ -690,19 +739,19 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
690} 739}
691 740
692static size_t 741static size_t
693sort__parent_print(FILE *fp, struct hist_entry *self) 742sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
694{ 743{
695 size_t ret = 0; 744 return repsep_fprintf(fp, "%-*s", width,
696 745 self->parent ? self->parent->name : "[other]");
697 ret += fprintf(fp, "%-20s", self->parent ? self->parent->name : "[other]");
698
699 return ret;
700} 746}
701 747
748static unsigned int parent_symbol__col_width;
749
702static struct sort_entry sort_parent = { 750static struct sort_entry sort_parent = {
703 .header = "Parent symbol ", 751 .header = "Parent symbol",
704 .cmp = sort__parent_cmp, 752 .cmp = sort__parent_cmp,
705 .print = sort__parent_print, 753 .print = sort__parent_print,
754 .width = &parent_symbol__col_width,
706}; 755};
707 756
708static int sort__need_collapse = 0; 757static int sort__need_collapse = 0;
@@ -843,6 +892,21 @@ ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
843 return ret; 892 return ret;
844} 893}
845 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
846static size_t 910static size_t
847callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 911callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
848 u64 total_samples, int depth, int depth_mask) 912 u64 total_samples, int depth, int depth_mask)
@@ -852,25 +916,34 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
852 struct callchain_list *chain; 916 struct callchain_list *chain;
853 int new_depth_mask = depth_mask; 917 int new_depth_mask = depth_mask;
854 u64 new_total; 918 u64 new_total;
919 u64 remaining;
855 size_t ret = 0; 920 size_t ret = 0;
856 int i; 921 int i;
857 922
858 if (callchain_param.mode == CHAIN_GRAPH_REL) 923 if (callchain_param.mode == CHAIN_GRAPH_REL)
859 new_total = self->cumul_hit; 924 new_total = self->children_hit;
860 else 925 else
861 new_total = total_samples; 926 new_total = total_samples;
862 927
928 remaining = new_total;
929
863 node = rb_first(&self->rb_root); 930 node = rb_first(&self->rb_root);
864 while (node) { 931 while (node) {
932 u64 cumul;
933
865 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;
866 937
867 /* 938 /*
868 * The depth mask manages the output of pipes that show 939 * The depth mask manages the output of pipes that show
869 * 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
870 * 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
871 */ 944 */
872 next = rb_next(node); 945 next = rb_next(node);
873 if (!next) 946 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
874 new_depth_mask &= ~(1 << (depth - 1)); 947 new_depth_mask &= ~(1 << (depth - 1));
875 948
876 /* 949 /*
@@ -885,7 +958,7 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
885 ret += ipchain__fprintf_graph(fp, chain, depth, 958 ret += ipchain__fprintf_graph(fp, chain, depth,
886 new_depth_mask, i++, 959 new_depth_mask, i++,
887 new_total, 960 new_total,
888 child->cumul_hit); 961 cumul);
889 } 962 }
890 ret += callchain__fprintf_graph(fp, child, new_total, 963 ret += callchain__fprintf_graph(fp, child, new_total,
891 depth + 1, 964 depth + 1,
@@ -893,6 +966,19 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
893 node = next; 966 node = next;
894 } 967 }
895 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
896 return ret; 982 return ret;
897} 983}
898 984
@@ -967,17 +1053,25 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
967 return 0; 1053 return 0;
968 1054
969 if (total_samples) 1055 if (total_samples)
970 ret = percent_color_fprintf(fp, " %6.2f%%", 1056 ret = percent_color_fprintf(fp,
971 (self->count * 100.0) / total_samples); 1057 field_sep ? "%.2f" : " %6.2f%%",
1058 (self->count * 100.0) / total_samples);
972 else 1059 else
973 ret = fprintf(fp, "%12Ld ", self->count); 1060 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
1061
1062 if (show_nr_samples) {
1063 if (field_sep)
1064 fprintf(fp, "%c%lld", *field_sep, self->count);
1065 else
1066 fprintf(fp, "%11lld", self->count);
1067 }
974 1068
975 list_for_each_entry(se, &hist_entry__sort_list, list) { 1069 list_for_each_entry(se, &hist_entry__sort_list, list) {
976 if (exclude_other && (se == &sort_parent)) 1070 if (se->elide)
977 continue; 1071 continue;
978 1072
979 fprintf(fp, " "); 1073 fprintf(fp, "%s", field_sep ?: " ");
980 ret += se->print(fp, self); 1074 ret += se->print(fp, self, se->width ? *se->width : 0);
981 } 1075 }
982 1076
983 ret += fprintf(fp, "\n"); 1077 ret += fprintf(fp, "\n");
@@ -992,6 +1086,18 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
992 * 1086 *
993 */ 1087 */
994 1088
1089static void dso__calc_col_width(struct dso *self)
1090{
1091 if (!col_width_list_str && !field_sep &&
1092 (!dso_list || strlist__has_entry(dso_list, self->name))) {
1093 unsigned int slen = strlen(self->name);
1094 if (slen > dsos__col_width)
1095 dsos__col_width = slen;
1096 }
1097
1098 self->slen_calculated = 1;
1099}
1100
995static struct symbol * 1101static struct symbol *
996resolve_symbol(struct thread *thread, struct map **mapp, 1102resolve_symbol(struct thread *thread, struct map **mapp,
997 struct dso **dsop, u64 *ipp) 1103 struct dso **dsop, u64 *ipp)
@@ -1011,6 +1117,14 @@ resolve_symbol(struct thread *thread, struct map **mapp,
1011 1117
1012 map = thread__find_map(thread, ip); 1118 map = thread__find_map(thread, ip);
1013 if (map != NULL) { 1119 if (map != NULL) {
1120 /*
1121 * We have to do this here as we may have a dso
1122 * with no symbol hit that has a name longer than
1123 * the ones with symbols sampled.
1124 */
1125 if (!sort_dso.elide && !map->dso->slen_calculated)
1126 dso__calc_col_width(map->dso);
1127
1014 if (mapp) 1128 if (mapp)
1015 *mapp = map; 1129 *mapp = map;
1016got_map: 1130got_map:
@@ -1282,35 +1396,69 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1282 struct sort_entry *se; 1396 struct sort_entry *se;
1283 struct rb_node *nd; 1397 struct rb_node *nd;
1284 size_t ret = 0; 1398 size_t ret = 0;
1399 unsigned int width;
1400 char *col_width = col_width_list_str;
1285 1401
1286 fprintf(fp, "\n"); 1402 init_rem_hits();
1287 fprintf(fp, "#\n"); 1403
1288 fprintf(fp, "# (%Ld samples)\n", (u64)total_samples); 1404 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
1289 fprintf(fp, "#\n"); 1405 fprintf(fp, "#\n");
1290 1406
1291 fprintf(fp, "# Overhead"); 1407 fprintf(fp, "# Overhead");
1408 if (show_nr_samples) {
1409 if (field_sep)
1410 fprintf(fp, "%cSamples", *field_sep);
1411 else
1412 fputs(" Samples ", fp);
1413 }
1292 list_for_each_entry(se, &hist_entry__sort_list, list) { 1414 list_for_each_entry(se, &hist_entry__sort_list, list) {
1293 if (exclude_other && (se == &sort_parent)) 1415 if (se->elide)
1294 continue; 1416 continue;
1295 fprintf(fp, " %s", se->header); 1417 if (field_sep) {
1418 fprintf(fp, "%c%s", *field_sep, se->header);
1419 continue;
1420 }
1421 width = strlen(se->header);
1422 if (se->width) {
1423 if (col_width_list_str) {
1424 if (col_width) {
1425 *se->width = atoi(col_width);
1426 col_width = strchr(col_width, ',');
1427 if (col_width)
1428 ++col_width;
1429 }
1430 }
1431 width = *se->width = max(*se->width, width);
1432 }
1433 fprintf(fp, " %*s", width, se->header);
1296 } 1434 }
1297 fprintf(fp, "\n"); 1435 fprintf(fp, "\n");
1298 1436
1437 if (field_sep)
1438 goto print_entries;
1439
1299 fprintf(fp, "# ........"); 1440 fprintf(fp, "# ........");
1441 if (show_nr_samples)
1442 fprintf(fp, " ..........");
1300 list_for_each_entry(se, &hist_entry__sort_list, list) { 1443 list_for_each_entry(se, &hist_entry__sort_list, list) {
1301 unsigned int i; 1444 unsigned int i;
1302 1445
1303 if (exclude_other && (se == &sort_parent)) 1446 if (se->elide)
1304 continue; 1447 continue;
1305 1448
1306 fprintf(fp, " "); 1449 fprintf(fp, " ");
1307 for (i = 0; i < strlen(se->header); i++) 1450 if (se->width)
1451 width = *se->width;
1452 else
1453 width = strlen(se->header);
1454 for (i = 0; i < width; i++)
1308 fprintf(fp, "."); 1455 fprintf(fp, ".");
1309 } 1456 }
1310 fprintf(fp, "\n"); 1457 fprintf(fp, "\n");
1311 1458
1312 fprintf(fp, "#\n"); 1459 fprintf(fp, "#\n");
1313 1460
1461print_entries:
1314 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { 1462 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1315 pos = rb_entry(nd, struct hist_entry, rb_node); 1463 pos = rb_entry(nd, struct hist_entry, rb_node);
1316 ret += hist_entry__fprintf(fp, pos, total_samples); 1464 ret += hist_entry__fprintf(fp, pos, total_samples);
@@ -1319,11 +1467,13 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1319 if (sort_order == default_sort_order && 1467 if (sort_order == default_sort_order &&
1320 parent_pattern == default_parent_pattern) { 1468 parent_pattern == default_parent_pattern) {
1321 fprintf(fp, "#\n"); 1469 fprintf(fp, "#\n");
1322 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");
1323 fprintf(fp, "#\n"); 1471 fprintf(fp, "#\n");
1324 } 1472 }
1325 fprintf(fp, "\n"); 1473 fprintf(fp, "\n");
1326 1474
1475 free(rem_sq_bracket);
1476
1327 return ret; 1477 return ret;
1328} 1478}
1329 1479
@@ -1377,11 +1527,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1377 more_data += sizeof(u64); 1527 more_data += sizeof(u64);
1378 } 1528 }
1379 1529
1380 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",
1381 (void *)(offset + head), 1531 (void *)(offset + head),
1382 (void *)(long)(event->header.size), 1532 (void *)(long)(event->header.size),
1383 event->header.misc, 1533 event->header.misc,
1384 event->ip.pid, 1534 event->ip.pid, event->ip.tid,
1385 (void *)(long)ip, 1535 (void *)(long)ip,
1386 (long long)period); 1536 (long long)period);
1387 1537
@@ -1441,10 +1591,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1441 if (show & show_mask) { 1591 if (show & show_mask) {
1442 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); 1592 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1443 1593
1444 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)))
1445 return 0; 1596 return 0;
1446 1597
1447 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name)) 1598 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
1448 return 0; 1599 return 0;
1449 1600
1450 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)) {
@@ -1463,10 +1614,11 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1463 struct thread *thread = threads__findnew(event->mmap.pid); 1614 struct thread *thread = threads__findnew(event->mmap.pid);
1464 struct map *map = map__new(&event->mmap); 1615 struct map *map = map__new(&event->mmap);
1465 1616
1466 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",
1467 (void *)(offset + head), 1618 (void *)(offset + head),
1468 (void *)(long)(event->header.size), 1619 (void *)(long)(event->header.size),
1469 event->mmap.pid, 1620 event->mmap.pid,
1621 event->mmap.tid,
1470 (void *)(long)event->mmap.start, 1622 (void *)(long)event->mmap.start,
1471 (void *)(long)event->mmap.len, 1623 (void *)(long)event->mmap.len,
1472 (void *)(long)event->mmap.pgoff, 1624 (void *)(long)event->mmap.pgoff,
@@ -1504,15 +1656,27 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1504} 1656}
1505 1657
1506static int 1658static int
1507process_fork_event(event_t *event, unsigned long offset, unsigned long head) 1659process_task_event(event_t *event, unsigned long offset, unsigned long head)
1508{ 1660{
1509 struct thread *thread = threads__findnew(event->fork.pid); 1661 struct thread *thread = threads__findnew(event->fork.pid);
1510 struct thread *parent = threads__findnew(event->fork.ppid); 1662 struct thread *parent = threads__findnew(event->fork.ppid);
1511 1663
1512 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 1664 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
1513 (void *)(offset + head), 1665 (void *)(offset + head),
1514 (void *)(long)(event->header.size), 1666 (void *)(long)(event->header.size),
1515 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;
1516 1680
1517 if (!thread || !parent || thread__fork(thread, parent)) { 1681 if (!thread || !parent || thread__fork(thread, parent)) {
1518 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 1682 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
@@ -1524,19 +1688,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1524} 1688}
1525 1689
1526static int 1690static int
1527process_period_event(event_t *event, unsigned long offset, unsigned long head)
1528{
1529 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
1530 (void *)(offset + head),
1531 (void *)(long)(event->header.size),
1532 event->period.time,
1533 event->period.id,
1534 event->period.sample_period);
1535
1536 return 0;
1537}
1538
1539static int
1540process_lost_event(event_t *event, unsigned long offset, unsigned long head) 1691process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1541{ 1692{
1542 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", 1693 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
@@ -1586,14 +1737,37 @@ static void trace_event(event_t *event)
1586 dprintf(".\n"); 1737 dprintf(".\n");
1587} 1738}
1588 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
1589static int 1759static int
1590process_read_event(event_t *event, unsigned long offset, unsigned long head) 1760process_read_event(event_t *event, unsigned long offset, unsigned long head)
1591{ 1761{
1592 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",
1593 (void *)(offset + head), 1765 (void *)(offset + head),
1594 (void *)(long)(event->header.size), 1766 (void *)(long)(event->header.size),
1595 event->read.pid, 1767 event->read.pid,
1596 event->read.tid, 1768 event->read.tid,
1769 attr ? __event_name(attr->type, attr->config)
1770 : "FAIL",
1597 event->read.value); 1771 event->read.value);
1598 1772
1599 return 0; 1773 return 0;
@@ -1615,10 +1789,8 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1615 return process_comm_event(event, offset, head); 1789 return process_comm_event(event, offset, head);
1616 1790
1617 case PERF_EVENT_FORK: 1791 case PERF_EVENT_FORK:
1618 return process_fork_event(event, offset, head); 1792 case PERF_EVENT_EXIT:
1619 1793 return process_task_event(event, offset, head);
1620 case PERF_EVENT_PERIOD:
1621 return process_period_event(event, offset, head);
1622 1794
1623 case PERF_EVENT_LOST: 1795 case PERF_EVENT_LOST:
1624 return process_lost_event(event, offset, head); 1796 return process_lost_event(event, offset, head);
@@ -1641,8 +1813,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1641 return 0; 1813 return 0;
1642} 1814}
1643 1815
1644static struct perf_header *header;
1645
1646static u64 perf_header__sample_type(void) 1816static u64 perf_header__sample_type(void)
1647{ 1817{
1648 u64 sample_type = 0; 1818 u64 sample_type = 0;
@@ -1687,6 +1857,11 @@ static int __cmd_report(void)
1687 exit(-1); 1857 exit(-1);
1688 } 1858 }
1689 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
1690 if (!stat.st_size) { 1865 if (!stat.st_size) {
1691 fprintf(stderr, "zero-sized file, nothing to do!\n"); 1866 fprintf(stderr, "zero-sized file, nothing to do!\n");
1692 exit(0); 1867 exit(0);
@@ -1710,6 +1885,13 @@ static int __cmd_report(void)
1710 " -g?\n"); 1885 " -g?\n");
1711 exit(-1); 1886 exit(-1);
1712 } 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 }
1713 } 1895 }
1714 1896
1715 if (load_kernel() < 0) { 1897 if (load_kernel() < 0) {
@@ -1848,6 +2030,13 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
1848 else if (!strncmp(tok, "fractal", strlen(arg))) 2030 else if (!strncmp(tok, "fractal", strlen(arg)))
1849 callchain_param.mode = CHAIN_GRAPH_REL; 2031 callchain_param.mode = CHAIN_GRAPH_REL;
1850 2032
2033 else if (!strncmp(tok, "none", strlen(arg))) {
2034 callchain_param.mode = CHAIN_NONE;
2035 callchain = 0;
2036
2037 return 0;
2038 }
2039
1851 else 2040 else
1852 return -1; 2041 return -1;
1853 2042
@@ -1881,8 +2070,11 @@ static const struct option options[] = {
1881 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 2070 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1882 "dump raw trace in ASCII"), 2071 "dump raw trace in ASCII"),
1883 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"),
1884 OPT_BOOLEAN('m', "modules", &modules, 2074 OPT_BOOLEAN('m', "modules", &modules,
1885 "load module symbols - WARNING: use only with -k and LIVE kernel"), 2075 "load module symbols - WARNING: use only with -k and LIVE kernel"),
2076 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
2077 "Show a column with the number of samples"),
1886 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 2078 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1887 "sort by key(s): pid, comm, dso, symbol, parent"), 2079 "sort by key(s): pid, comm, dso, symbol, parent"),
1888 OPT_BOOLEAN('P', "full-paths", &full_paths, 2080 OPT_BOOLEAN('P', "full-paths", &full_paths,
@@ -1891,15 +2083,21 @@ static const struct option options[] = {
1891 "regex filter to identify parent, see: '--sort parent'"), 2083 "regex filter to identify parent, see: '--sort parent'"),
1892 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 2084 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1893 "Only display entries with parent-match"), 2085 "Only display entries with parent-match"),
1894 OPT_CALLBACK_DEFAULT('c', "callchain", NULL, "output_type,min_percent", 2086 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
1895 "Display callchains using output_type and min percent threshold. " 2087 "Display callchains using output_type and min percent threshold. "
1896 "Default: flat,0", &parse_callchain_opt, callchain_default_opt), 2088 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1897 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 2089 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1898 "only consider symbols in these dsos"), 2090 "only consider symbols in these dsos"),
1899 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 2091 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1900 "only consider symbols in these comms"), 2092 "only consider symbols in these comms"),
1901 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 2093 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1902 "only consider these symbols"), 2094 "only consider these symbols"),
2095 OPT_STRING('w', "column-widths", &col_width_list_str,
2096 "width[,width...]",
2097 "don't try to adjust column width, use these fixed values"),
2098 OPT_STRING('t', "field-separator", &field_sep, "separator",
2099 "separator for columns, no spaces will be added between "
2100 "columns '.' is reserved."),
1903 OPT_END() 2101 OPT_END()
1904}; 2102};
1905 2103
@@ -1919,7 +2117,8 @@ static void setup_sorting(void)
1919} 2117}
1920 2118
1921static void setup_list(struct strlist **list, const char *list_str, 2119static void setup_list(struct strlist **list, const char *list_str,
1922 const char *list_name) 2120 struct sort_entry *se, const char *list_name,
2121 FILE *fp)
1923{ 2122{
1924 if (list_str) { 2123 if (list_str) {
1925 *list = strlist__new(true, list_str); 2124 *list = strlist__new(true, list_str);
@@ -1928,6 +2127,11 @@ static void setup_list(struct strlist **list, const char *list_str,
1928 list_name); 2127 list_name);
1929 exit(129); 2128 exit(129);
1930 } 2129 }
2130 if (strlist__nr_entries(*list) == 1) {
2131 fprintf(fp, "# %s: %s\n", list_name,
2132 strlist__entry(*list, 0)->s);
2133 se->elide = true;
2134 }
1931 } 2135 }
1932} 2136}
1933 2137
@@ -1941,9 +2145,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1941 2145
1942 setup_sorting(); 2146 setup_sorting();
1943 2147
1944 if (parent_pattern != default_parent_pattern) 2148 if (parent_pattern != default_parent_pattern) {
1945 sort_dimension__add("parent"); 2149 sort_dimension__add("parent");
1946 else 2150 sort_parent.elide = 1;
2151 } else
1947 exclude_other = 0; 2152 exclude_other = 0;
1948 2153
1949 /* 2154 /*
@@ -1952,11 +2157,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1952 if (argc) 2157 if (argc)
1953 usage_with_options(report_usage, options); 2158 usage_with_options(report_usage, options);
1954 2159
1955 setup_list(&dso_list, dso_list_str, "dso");
1956 setup_list(&comm_list, comm_list_str, "comm");
1957 setup_list(&sym_list, sym_list_str, "symbol");
1958
1959 setup_pager(); 2160 setup_pager();
1960 2161
2162 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
2163 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
2164 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
2165
2166 if (field_sep && *field_sep == '.') {
2167 fputs("'.' is the only non valid --field-separator argument\n",
2168 stderr);
2169 exit(129);
2170 }
2171
1961 return __cmd_report(); 2172 return __cmd_report();
1962} 2173}