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