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.c380
1 files changed, 291 insertions, 89 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 4e5cc266311e..99274cec0adb 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
@@ -1504,15 +1653,27 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1504} 1653}
1505 1654
1506static int 1655static int
1507process_fork_event(event_t *event, unsigned long offset, unsigned long head) 1656process_task_event(event_t *event, unsigned long offset, unsigned long head)
1508{ 1657{
1509 struct thread *thread = threads__findnew(event->fork.pid); 1658 struct thread *thread = threads__findnew(event->fork.pid);
1510 struct thread *parent = threads__findnew(event->fork.ppid); 1659 struct thread *parent = threads__findnew(event->fork.ppid);
1511 1660
1512 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 1661 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
1513 (void *)(offset + head), 1662 (void *)(offset + head),
1514 (void *)(long)(event->header.size), 1663 (void *)(long)(event->header.size),
1515 event->fork.pid, event->fork.ppid); 1664 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1665 event->fork.pid, event->fork.tid,
1666 event->fork.ppid, event->fork.ptid);
1667
1668 /*
1669 * A thread clone will have the same PID for both
1670 * parent and child.
1671 */
1672 if (thread == parent)
1673 return 0;
1674
1675 if (event->header.type == PERF_EVENT_EXIT)
1676 return 0;
1516 1677
1517 if (!thread || !parent || thread__fork(thread, parent)) { 1678 if (!thread || !parent || thread__fork(thread, parent)) {
1518 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 1679 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
@@ -1524,19 +1685,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1524} 1685}
1525 1686
1526static int 1687static 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) 1688process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1541{ 1689{
1542 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", 1690 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
@@ -1586,14 +1734,37 @@ static void trace_event(event_t *event)
1586 dprintf(".\n"); 1734 dprintf(".\n");
1587} 1735}
1588 1736
1737static struct perf_header *header;
1738
1739static struct perf_counter_attr *perf_header__find_attr(u64 id)
1740{
1741 int i;
1742
1743 for (i = 0; i < header->attrs; i++) {
1744 struct perf_header_attr *attr = header->attr[i];
1745 int j;
1746
1747 for (j = 0; j < attr->ids; j++) {
1748 if (attr->id[j] == id)
1749 return &attr->attr;
1750 }
1751 }
1752
1753 return NULL;
1754}
1755
1589static int 1756static int
1590process_read_event(event_t *event, unsigned long offset, unsigned long head) 1757process_read_event(event_t *event, unsigned long offset, unsigned long head)
1591{ 1758{
1592 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %Lu\n", 1759 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
1760
1761 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
1593 (void *)(offset + head), 1762 (void *)(offset + head),
1594 (void *)(long)(event->header.size), 1763 (void *)(long)(event->header.size),
1595 event->read.pid, 1764 event->read.pid,
1596 event->read.tid, 1765 event->read.tid,
1766 attr ? __event_name(attr->type, attr->config)
1767 : "FAIL",
1597 event->read.value); 1768 event->read.value);
1598 1769
1599 return 0; 1770 return 0;
@@ -1615,10 +1786,8 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1615 return process_comm_event(event, offset, head); 1786 return process_comm_event(event, offset, head);
1616 1787
1617 case PERF_EVENT_FORK: 1788 case PERF_EVENT_FORK:
1618 return process_fork_event(event, offset, head); 1789 case PERF_EVENT_EXIT:
1619 1790 return process_task_event(event, offset, head);
1620 case PERF_EVENT_PERIOD:
1621 return process_period_event(event, offset, head);
1622 1791
1623 case PERF_EVENT_LOST: 1792 case PERF_EVENT_LOST:
1624 return process_lost_event(event, offset, head); 1793 return process_lost_event(event, offset, head);
@@ -1641,8 +1810,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1641 return 0; 1810 return 0;
1642} 1811}
1643 1812
1644static struct perf_header *header;
1645
1646static u64 perf_header__sample_type(void) 1813static u64 perf_header__sample_type(void)
1647{ 1814{
1648 u64 sample_type = 0; 1815 u64 sample_type = 0;
@@ -1710,6 +1877,13 @@ static int __cmd_report(void)
1710 " -g?\n"); 1877 " -g?\n");
1711 exit(-1); 1878 exit(-1);
1712 } 1879 }
1880 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1881 callchain = 1;
1882 if (register_callchain_param(&callchain_param) < 0) {
1883 fprintf(stderr, "Can't register callchain"
1884 " params\n");
1885 exit(-1);
1886 }
1713 } 1887 }
1714 1888
1715 if (load_kernel() < 0) { 1889 if (load_kernel() < 0) {
@@ -1848,6 +2022,13 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
1848 else if (!strncmp(tok, "fractal", strlen(arg))) 2022 else if (!strncmp(tok, "fractal", strlen(arg)))
1849 callchain_param.mode = CHAIN_GRAPH_REL; 2023 callchain_param.mode = CHAIN_GRAPH_REL;
1850 2024
2025 else if (!strncmp(tok, "none", strlen(arg))) {
2026 callchain_param.mode = CHAIN_NONE;
2027 callchain = 0;
2028
2029 return 0;
2030 }
2031
1851 else 2032 else
1852 return -1; 2033 return -1;
1853 2034
@@ -1883,6 +2064,8 @@ static const struct option options[] = {
1883 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 2064 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1884 OPT_BOOLEAN('m', "modules", &modules, 2065 OPT_BOOLEAN('m', "modules", &modules,
1885 "load module symbols - WARNING: use only with -k and LIVE kernel"), 2066 "load module symbols - WARNING: use only with -k and LIVE kernel"),
2067 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
2068 "Show a column with the number of samples"),
1886 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 2069 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1887 "sort by key(s): pid, comm, dso, symbol, parent"), 2070 "sort by key(s): pid, comm, dso, symbol, parent"),
1888 OPT_BOOLEAN('P', "full-paths", &full_paths, 2071 OPT_BOOLEAN('P', "full-paths", &full_paths,
@@ -1891,15 +2074,21 @@ static const struct option options[] = {
1891 "regex filter to identify parent, see: '--sort parent'"), 2074 "regex filter to identify parent, see: '--sort parent'"),
1892 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 2075 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1893 "Only display entries with parent-match"), 2076 "Only display entries with parent-match"),
1894 OPT_CALLBACK_DEFAULT('c', "callchain", NULL, "output_type,min_percent", 2077 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
1895 "Display callchains using output_type and min percent threshold. " 2078 "Display callchains using output_type and min percent threshold. "
1896 "Default: flat,0", &parse_callchain_opt, callchain_default_opt), 2079 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1897 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 2080 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1898 "only consider symbols in these dsos"), 2081 "only consider symbols in these dsos"),
1899 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 2082 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1900 "only consider symbols in these comms"), 2083 "only consider symbols in these comms"),
1901 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 2084 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1902 "only consider these symbols"), 2085 "only consider these symbols"),
2086 OPT_STRING('w', "column-widths", &col_width_list_str,
2087 "width[,width...]",
2088 "don't try to adjust column width, use these fixed values"),
2089 OPT_STRING('t', "field-separator", &field_sep, "separator",
2090 "separator for columns, no spaces will be added between "
2091 "columns '.' is reserved."),
1903 OPT_END() 2092 OPT_END()
1904}; 2093};
1905 2094
@@ -1919,7 +2108,8 @@ static void setup_sorting(void)
1919} 2108}
1920 2109
1921static void setup_list(struct strlist **list, const char *list_str, 2110static void setup_list(struct strlist **list, const char *list_str,
1922 const char *list_name) 2111 struct sort_entry *se, const char *list_name,
2112 FILE *fp)
1923{ 2113{
1924 if (list_str) { 2114 if (list_str) {
1925 *list = strlist__new(true, list_str); 2115 *list = strlist__new(true, list_str);
@@ -1928,6 +2118,11 @@ static void setup_list(struct strlist **list, const char *list_str,
1928 list_name); 2118 list_name);
1929 exit(129); 2119 exit(129);
1930 } 2120 }
2121 if (strlist__nr_entries(*list) == 1) {
2122 fprintf(fp, "# %s: %s\n", list_name,
2123 strlist__entry(*list, 0)->s);
2124 se->elide = true;
2125 }
1931 } 2126 }
1932} 2127}
1933 2128
@@ -1941,9 +2136,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1941 2136
1942 setup_sorting(); 2137 setup_sorting();
1943 2138
1944 if (parent_pattern != default_parent_pattern) 2139 if (parent_pattern != default_parent_pattern) {
1945 sort_dimension__add("parent"); 2140 sort_dimension__add("parent");
1946 else 2141 sort_parent.elide = 1;
2142 } else
1947 exclude_other = 0; 2143 exclude_other = 0;
1948 2144
1949 /* 2145 /*
@@ -1952,11 +2148,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1952 if (argc) 2148 if (argc)
1953 usage_with_options(report_usage, options); 2149 usage_with_options(report_usage, options);
1954 2150
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(); 2151 setup_pager();
1960 2152
2153 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
2154 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
2155 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
2156
2157 if (field_sep && *field_sep == '.') {
2158 fputs("'.' is the only non valid --field-separator argument\n",
2159 stderr);
2160 exit(129);
2161 }
2162
1961 return __cmd_report(); 2163 return __cmd_report();
1962} 2164}