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.c279
1 files changed, 201 insertions, 78 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 4e5cc266311e..ce4f28645e64 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -33,8 +33,10 @@ static char *vmlinux = NULL;
33 33
34static char default_sort_order[] = "comm,dso"; 34static char default_sort_order[] = "comm,dso";
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;
@@ -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 {
@@ -124,11 +121,37 @@ typedef union event_union {
124 struct mmap_event mmap; 121 struct mmap_event mmap;
125 struct comm_event comm; 122 struct comm_event comm;
126 struct fork_event fork; 123 struct fork_event fork;
127 struct period_event period;
128 struct lost_event lost; 124 struct lost_event lost;
129 struct read_event read; 125 struct read_event read;
130} event_t; 126} event_t;
131 127
128static int repsep_fprintf(FILE *fp, const char *fmt, ...)
129{
130 int n;
131 va_list ap;
132
133 va_start(ap, fmt);
134 if (!field_sep)
135 n = vfprintf(fp, fmt, ap);
136 else {
137 char *bf = NULL;
138 n = vasprintf(&bf, fmt, ap);
139 if (n > 0) {
140 char *sep = bf;
141 while (1) {
142 sep = strchr(sep, *field_sep);
143 if (sep == NULL)
144 break;
145 *sep = '.';
146 }
147 }
148 fputs(bf, fp);
149 free(bf);
150 }
151 va_end(ap);
152 return n;
153}
154
132static LIST_HEAD(dsos); 155static LIST_HEAD(dsos);
133static struct dso *kernel_dso; 156static struct dso *kernel_dso;
134static struct dso *vdso; 157static struct dso *vdso;
@@ -230,7 +253,7 @@ static int strcommon(const char *pathname)
230{ 253{
231 int n = 0; 254 int n = 0;
232 255
233 while (pathname[n] == cwd[n] && n < cwdlen) 256 while (n < cwdlen && pathname[n] == cwd[n])
234 ++n; 257 ++n;
235 258
236 return n; 259 return n;
@@ -360,12 +383,28 @@ static struct thread *thread__new(pid_t pid)
360 return self; 383 return self;
361} 384}
362 385
386static unsigned int dsos__col_width,
387 comms__col_width,
388 threads__col_width;
389
363static int thread__set_comm(struct thread *self, const char *comm) 390static int thread__set_comm(struct thread *self, const char *comm)
364{ 391{
365 if (self->comm) 392 if (self->comm)
366 free(self->comm); 393 free(self->comm);
367 self->comm = strdup(comm); 394 self->comm = strdup(comm);
368 return self->comm ? 0 : -ENOMEM; 395 if (!self->comm)
396 return -ENOMEM;
397
398 if (!col_width_list_str && !field_sep &&
399 (!comm_list || strlist__has_entry(comm_list, comm))) {
400 unsigned int slen = strlen(comm);
401 if (slen > comms__col_width) {
402 comms__col_width = slen;
403 threads__col_width = slen + 6;
404 }
405 }
406
407 return 0;
369} 408}
370 409
371static size_t thread__fprintf(struct thread *self, FILE *fp) 410static size_t thread__fprintf(struct thread *self, FILE *fp)
@@ -536,7 +575,9 @@ struct sort_entry {
536 575
537 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 576 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
538 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 577 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
539 size_t (*print)(FILE *fp, struct hist_entry *); 578 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
579 unsigned int *width;
580 bool elide;
540}; 581};
541 582
542static int64_t cmp_null(void *l, void *r) 583static int64_t cmp_null(void *l, void *r)
@@ -558,15 +599,17 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
558} 599}
559 600
560static size_t 601static size_t
561sort__thread_print(FILE *fp, struct hist_entry *self) 602sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
562{ 603{
563 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); 604 return repsep_fprintf(fp, "%*s:%5d", width - 6,
605 self->thread->comm ?: "", self->thread->pid);
564} 606}
565 607
566static struct sort_entry sort_thread = { 608static struct sort_entry sort_thread = {
567 .header = " Command: Pid", 609 .header = "Command: Pid",
568 .cmp = sort__thread_cmp, 610 .cmp = sort__thread_cmp,
569 .print = sort__thread_print, 611 .print = sort__thread_print,
612 .width = &threads__col_width,
570}; 613};
571 614
572/* --sort comm */ 615/* --sort comm */
@@ -590,16 +633,17 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
590} 633}
591 634
592static size_t 635static size_t
593sort__comm_print(FILE *fp, struct hist_entry *self) 636sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
594{ 637{
595 return fprintf(fp, "%16s", self->thread->comm); 638 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
596} 639}
597 640
598static struct sort_entry sort_comm = { 641static struct sort_entry sort_comm = {
599 .header = " Command", 642 .header = "Command",
600 .cmp = sort__comm_cmp, 643 .cmp = sort__comm_cmp,
601 .collapse = sort__comm_collapse, 644 .collapse = sort__comm_collapse,
602 .print = sort__comm_print, 645 .print = sort__comm_print,
646 .width = &comms__col_width,
603}; 647};
604 648
605/* --sort dso */ 649/* --sort dso */
@@ -617,18 +661,19 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
617} 661}
618 662
619static size_t 663static size_t
620sort__dso_print(FILE *fp, struct hist_entry *self) 664sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
621{ 665{
622 if (self->dso) 666 if (self->dso)
623 return fprintf(fp, "%-25s", self->dso->name); 667 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
624 668
625 return fprintf(fp, "%016llx ", (u64)self->ip); 669 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
626} 670}
627 671
628static struct sort_entry sort_dso = { 672static struct sort_entry sort_dso = {
629 .header = "Shared Object ", 673 .header = "Shared Object",
630 .cmp = sort__dso_cmp, 674 .cmp = sort__dso_cmp,
631 .print = sort__dso_print, 675 .print = sort__dso_print,
676 .width = &dsos__col_width,
632}; 677};
633 678
634/* --sort symbol */ 679/* --sort symbol */
@@ -648,22 +693,22 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
648} 693}
649 694
650static size_t 695static size_t
651sort__sym_print(FILE *fp, struct hist_entry *self) 696sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
652{ 697{
653 size_t ret = 0; 698 size_t ret = 0;
654 699
655 if (verbose) 700 if (verbose)
656 ret += fprintf(fp, "%#018llx ", (u64)self->ip); 701 ret += repsep_fprintf(fp, "%#018llx ", (u64)self->ip);
657 702
703 ret += repsep_fprintf(fp, "[%c] ", self->level);
658 if (self->sym) { 704 if (self->sym) {
659 ret += fprintf(fp, "[%c] %s", 705 ret += repsep_fprintf(fp, "%s", self->sym->name);
660 self->dso == kernel_dso ? 'k' :
661 self->dso == hypervisor_dso ? 'h' : '.', self->sym->name);
662 706
663 if (self->sym->module) 707 if (self->sym->module)
664 ret += fprintf(fp, "\t[%s]", self->sym->module->name); 708 ret += repsep_fprintf(fp, "\t[%s]",
709 self->sym->module->name);
665 } else { 710 } else {
666 ret += fprintf(fp, "%#016llx", (u64)self->ip); 711 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
667 } 712 }
668 713
669 return ret; 714 return ret;
@@ -690,19 +735,19 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
690} 735}
691 736
692static size_t 737static size_t
693sort__parent_print(FILE *fp, struct hist_entry *self) 738sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
694{ 739{
695 size_t ret = 0; 740 return repsep_fprintf(fp, "%-*s", width,
696 741 self->parent ? self->parent->name : "[other]");
697 ret += fprintf(fp, "%-20s", self->parent ? self->parent->name : "[other]");
698
699 return ret;
700} 742}
701 743
744static unsigned int parent_symbol__col_width;
745
702static struct sort_entry sort_parent = { 746static struct sort_entry sort_parent = {
703 .header = "Parent symbol ", 747 .header = "Parent symbol",
704 .cmp = sort__parent_cmp, 748 .cmp = sort__parent_cmp,
705 .print = sort__parent_print, 749 .print = sort__parent_print,
750 .width = &parent_symbol__col_width,
706}; 751};
707 752
708static int sort__need_collapse = 0; 753static int sort__need_collapse = 0;
@@ -967,17 +1012,25 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
967 return 0; 1012 return 0;
968 1013
969 if (total_samples) 1014 if (total_samples)
970 ret = percent_color_fprintf(fp, " %6.2f%%", 1015 ret = percent_color_fprintf(fp,
971 (self->count * 100.0) / total_samples); 1016 field_sep ? "%.2f" : " %6.2f%%",
1017 (self->count * 100.0) / total_samples);
972 else 1018 else
973 ret = fprintf(fp, "%12Ld ", self->count); 1019 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
1020
1021 if (show_nr_samples) {
1022 if (field_sep)
1023 fprintf(fp, "%c%lld", *field_sep, self->count);
1024 else
1025 fprintf(fp, "%11lld", self->count);
1026 }
974 1027
975 list_for_each_entry(se, &hist_entry__sort_list, list) { 1028 list_for_each_entry(se, &hist_entry__sort_list, list) {
976 if (exclude_other && (se == &sort_parent)) 1029 if (se->elide)
977 continue; 1030 continue;
978 1031
979 fprintf(fp, " "); 1032 fprintf(fp, "%s", field_sep ?: " ");
980 ret += se->print(fp, self); 1033 ret += se->print(fp, self, se->width ? *se->width : 0);
981 } 1034 }
982 1035
983 ret += fprintf(fp, "\n"); 1036 ret += fprintf(fp, "\n");
@@ -992,6 +1045,18 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
992 * 1045 *
993 */ 1046 */
994 1047
1048static void dso__calc_col_width(struct dso *self)
1049{
1050 if (!col_width_list_str && !field_sep &&
1051 (!dso_list || strlist__has_entry(dso_list, self->name))) {
1052 unsigned int slen = strlen(self->name);
1053 if (slen > dsos__col_width)
1054 dsos__col_width = slen;
1055 }
1056
1057 self->slen_calculated = 1;
1058}
1059
995static struct symbol * 1060static struct symbol *
996resolve_symbol(struct thread *thread, struct map **mapp, 1061resolve_symbol(struct thread *thread, struct map **mapp,
997 struct dso **dsop, u64 *ipp) 1062 struct dso **dsop, u64 *ipp)
@@ -1011,6 +1076,14 @@ resolve_symbol(struct thread *thread, struct map **mapp,
1011 1076
1012 map = thread__find_map(thread, ip); 1077 map = thread__find_map(thread, ip);
1013 if (map != NULL) { 1078 if (map != NULL) {
1079 /*
1080 * We have to do this here as we may have a dso
1081 * with no symbol hit that has a name longer than
1082 * the ones with symbols sampled.
1083 */
1084 if (!sort_dso.elide && !map->dso->slen_calculated)
1085 dso__calc_col_width(map->dso);
1086
1014 if (mapp) 1087 if (mapp)
1015 *mapp = map; 1088 *mapp = map;
1016got_map: 1089got_map:
@@ -1282,35 +1355,67 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1282 struct sort_entry *se; 1355 struct sort_entry *se;
1283 struct rb_node *nd; 1356 struct rb_node *nd;
1284 size_t ret = 0; 1357 size_t ret = 0;
1358 unsigned int width;
1359 char *col_width = col_width_list_str;
1285 1360
1286 fprintf(fp, "\n"); 1361 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
1287 fprintf(fp, "#\n");
1288 fprintf(fp, "# (%Ld samples)\n", (u64)total_samples);
1289 fprintf(fp, "#\n"); 1362 fprintf(fp, "#\n");
1290 1363
1291 fprintf(fp, "# Overhead"); 1364 fprintf(fp, "# Overhead");
1365 if (show_nr_samples) {
1366 if (field_sep)
1367 fprintf(fp, "%cSamples", *field_sep);
1368 else
1369 fputs(" Samples ", fp);
1370 }
1292 list_for_each_entry(se, &hist_entry__sort_list, list) { 1371 list_for_each_entry(se, &hist_entry__sort_list, list) {
1293 if (exclude_other && (se == &sort_parent)) 1372 if (se->elide)
1294 continue; 1373 continue;
1295 fprintf(fp, " %s", se->header); 1374 if (field_sep) {
1375 fprintf(fp, "%c%s", *field_sep, se->header);
1376 continue;
1377 }
1378 width = strlen(se->header);
1379 if (se->width) {
1380 if (col_width_list_str) {
1381 if (col_width) {
1382 *se->width = atoi(col_width);
1383 col_width = strchr(col_width, ',');
1384 if (col_width)
1385 ++col_width;
1386 }
1387 }
1388 width = *se->width = max(*se->width, width);
1389 }
1390 fprintf(fp, " %*s", width, se->header);
1296 } 1391 }
1297 fprintf(fp, "\n"); 1392 fprintf(fp, "\n");
1298 1393
1394 if (field_sep)
1395 goto print_entries;
1396
1299 fprintf(fp, "# ........"); 1397 fprintf(fp, "# ........");
1398 if (show_nr_samples)
1399 fprintf(fp, " ..........");
1300 list_for_each_entry(se, &hist_entry__sort_list, list) { 1400 list_for_each_entry(se, &hist_entry__sort_list, list) {
1301 unsigned int i; 1401 unsigned int i;
1302 1402
1303 if (exclude_other && (se == &sort_parent)) 1403 if (se->elide)
1304 continue; 1404 continue;
1305 1405
1306 fprintf(fp, " "); 1406 fprintf(fp, " ");
1307 for (i = 0; i < strlen(se->header); i++) 1407 if (se->width)
1408 width = *se->width;
1409 else
1410 width = strlen(se->header);
1411 for (i = 0; i < width; i++)
1308 fprintf(fp, "."); 1412 fprintf(fp, ".");
1309 } 1413 }
1310 fprintf(fp, "\n"); 1414 fprintf(fp, "\n");
1311 1415
1312 fprintf(fp, "#\n"); 1416 fprintf(fp, "#\n");
1313 1417
1418print_entries:
1314 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { 1419 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1315 pos = rb_entry(nd, struct hist_entry, rb_node); 1420 pos = rb_entry(nd, struct hist_entry, rb_node);
1316 ret += hist_entry__fprintf(fp, pos, total_samples); 1421 ret += hist_entry__fprintf(fp, pos, total_samples);
@@ -1504,15 +1609,27 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1504} 1609}
1505 1610
1506static int 1611static int
1507process_fork_event(event_t *event, unsigned long offset, unsigned long head) 1612process_task_event(event_t *event, unsigned long offset, unsigned long head)
1508{ 1613{
1509 struct thread *thread = threads__findnew(event->fork.pid); 1614 struct thread *thread = threads__findnew(event->fork.pid);
1510 struct thread *parent = threads__findnew(event->fork.ppid); 1615 struct thread *parent = threads__findnew(event->fork.ppid);
1511 1616
1512 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 1617 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
1513 (void *)(offset + head), 1618 (void *)(offset + head),
1514 (void *)(long)(event->header.size), 1619 (void *)(long)(event->header.size),
1515 event->fork.pid, event->fork.ppid); 1620 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1621 event->fork.pid, event->fork.tid,
1622 event->fork.ppid, event->fork.ptid);
1623
1624 /*
1625 * A thread clone will have the same PID for both
1626 * parent and child.
1627 */
1628 if (thread == parent)
1629 return 0;
1630
1631 if (event->header.type == PERF_EVENT_EXIT)
1632 return 0;
1516 1633
1517 if (!thread || !parent || thread__fork(thread, parent)) { 1634 if (!thread || !parent || thread__fork(thread, parent)) {
1518 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 1635 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
@@ -1524,19 +1641,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1524} 1641}
1525 1642
1526static int 1643static 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) 1644process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1541{ 1645{
1542 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", 1646 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
@@ -1615,10 +1719,8 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1615 return process_comm_event(event, offset, head); 1719 return process_comm_event(event, offset, head);
1616 1720
1617 case PERF_EVENT_FORK: 1721 case PERF_EVENT_FORK:
1618 return process_fork_event(event, offset, head); 1722 case PERF_EVENT_EXIT:
1619 1723 return process_task_event(event, offset, head);
1620 case PERF_EVENT_PERIOD:
1621 return process_period_event(event, offset, head);
1622 1724
1623 case PERF_EVENT_LOST: 1725 case PERF_EVENT_LOST:
1624 return process_lost_event(event, offset, head); 1726 return process_lost_event(event, offset, head);
@@ -1883,6 +1985,8 @@ static const struct option options[] = {
1883 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1985 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1884 OPT_BOOLEAN('m', "modules", &modules, 1986 OPT_BOOLEAN('m', "modules", &modules,
1885 "load module symbols - WARNING: use only with -k and LIVE kernel"), 1987 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1988 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1989 "Show a column with the number of samples"),
1886 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1990 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1887 "sort by key(s): pid, comm, dso, symbol, parent"), 1991 "sort by key(s): pid, comm, dso, symbol, parent"),
1888 OPT_BOOLEAN('P', "full-paths", &full_paths, 1992 OPT_BOOLEAN('P', "full-paths", &full_paths,
@@ -1891,15 +1995,21 @@ static const struct option options[] = {
1891 "regex filter to identify parent, see: '--sort parent'"), 1995 "regex filter to identify parent, see: '--sort parent'"),
1892 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 1996 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1893 "Only display entries with parent-match"), 1997 "Only display entries with parent-match"),
1894 OPT_CALLBACK_DEFAULT('c', "callchain", NULL, "output_type,min_percent", 1998 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
1895 "Display callchains using output_type and min percent threshold. " 1999 "Display callchains using output_type and min percent threshold. "
1896 "Default: flat,0", &parse_callchain_opt, callchain_default_opt), 2000 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1897 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 2001 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1898 "only consider symbols in these dsos"), 2002 "only consider symbols in these dsos"),
1899 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 2003 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1900 "only consider symbols in these comms"), 2004 "only consider symbols in these comms"),
1901 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 2005 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1902 "only consider these symbols"), 2006 "only consider these symbols"),
2007 OPT_STRING('w', "column-widths", &col_width_list_str,
2008 "width[,width...]",
2009 "don't try to adjust column width, use these fixed values"),
2010 OPT_STRING('t', "field-separator", &field_sep, "separator",
2011 "separator for columns, no spaces will be added between "
2012 "columns '.' is reserved."),
1903 OPT_END() 2013 OPT_END()
1904}; 2014};
1905 2015
@@ -1919,7 +2029,8 @@ static void setup_sorting(void)
1919} 2029}
1920 2030
1921static void setup_list(struct strlist **list, const char *list_str, 2031static void setup_list(struct strlist **list, const char *list_str,
1922 const char *list_name) 2032 struct sort_entry *se, const char *list_name,
2033 FILE *fp)
1923{ 2034{
1924 if (list_str) { 2035 if (list_str) {
1925 *list = strlist__new(true, list_str); 2036 *list = strlist__new(true, list_str);
@@ -1928,6 +2039,11 @@ static void setup_list(struct strlist **list, const char *list_str,
1928 list_name); 2039 list_name);
1929 exit(129); 2040 exit(129);
1930 } 2041 }
2042 if (strlist__nr_entries(*list) == 1) {
2043 fprintf(fp, "# %s: %s\n", list_name,
2044 strlist__entry(*list, 0)->s);
2045 se->elide = true;
2046 }
1931 } 2047 }
1932} 2048}
1933 2049
@@ -1941,9 +2057,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1941 2057
1942 setup_sorting(); 2058 setup_sorting();
1943 2059
1944 if (parent_pattern != default_parent_pattern) 2060 if (parent_pattern != default_parent_pattern) {
1945 sort_dimension__add("parent"); 2061 sort_dimension__add("parent");
1946 else 2062 sort_parent.elide = 1;
2063 } else
1947 exclude_other = 0; 2064 exclude_other = 0;
1948 2065
1949 /* 2066 /*
@@ -1952,11 +2069,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1952 if (argc) 2069 if (argc)
1953 usage_with_options(report_usage, options); 2070 usage_with_options(report_usage, options);
1954 2071
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(); 2072 setup_pager();
1960 2073
2074 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
2075 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
2076 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
2077
2078 if (field_sep && *field_sep == '.') {
2079 fputs("'.' is the only non valid --field-separator argument\n",
2080 stderr);
2081 exit(129);
2082 }
2083
1961 return __cmd_report(); 2084 return __cmd_report();
1962} 2085}