aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-07-22 12:05:48 -0400
committerPeter Zijlstra <a.p.zijlstra@chello.nl>2009-07-22 12:05:48 -0400
commit1d2f37945d1b3a14086c5ea802486778b635cf97 (patch)
treeb40a1a596a29acc1511f661c27f284dd06b0bc9d /tools/perf/builtin-report.c
parent1483b19f8f5e8ad0c8816de368b099322dad4db5 (diff)
parentf1c6a58121f9846ac665b0fbd3cbab90ce8bcbac (diff)
Merge commit 'tip/perfcounters/core' into perf-counters-for-linus
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c227
1 files changed, 180 insertions, 47 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 4b980cce7055..a118bc77286d 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;
@@ -129,6 +132,33 @@ typedef union event_union {
129 struct read_event read; 132 struct read_event read;
130} event_t; 133} event_t;
131 134
135static int repsep_fprintf(FILE *fp, const char *fmt, ...)
136{
137 int n;
138 va_list ap;
139
140 va_start(ap, fmt);
141 if (!field_sep)
142 n = vfprintf(fp, fmt, ap);
143 else {
144 char *bf = NULL;
145 n = vasprintf(&bf, fmt, ap);
146 if (n > 0) {
147 char *sep = bf;
148 while (1) {
149 sep = strchr(sep, *field_sep);
150 if (sep == NULL)
151 break;
152 *sep = '.';
153 }
154 }
155 fputs(bf, fp);
156 free(bf);
157 }
158 va_end(ap);
159 return n;
160}
161
132static LIST_HEAD(dsos); 162static LIST_HEAD(dsos);
133static struct dso *kernel_dso; 163static struct dso *kernel_dso;
134static struct dso *vdso; 164static struct dso *vdso;
@@ -360,12 +390,28 @@ static struct thread *thread__new(pid_t pid)
360 return self; 390 return self;
361} 391}
362 392
393static unsigned int dsos__col_width,
394 comms__col_width,
395 threads__col_width;
396
363static int thread__set_comm(struct thread *self, const char *comm) 397static int thread__set_comm(struct thread *self, const char *comm)
364{ 398{
365 if (self->comm) 399 if (self->comm)
366 free(self->comm); 400 free(self->comm);
367 self->comm = strdup(comm); 401 self->comm = strdup(comm);
368 return self->comm ? 0 : -ENOMEM; 402 if (!self->comm)
403 return -ENOMEM;
404
405 if (!col_width_list_str && !field_sep &&
406 (!comm_list || strlist__has_entry(comm_list, comm))) {
407 unsigned int slen = strlen(comm);
408 if (slen > comms__col_width) {
409 comms__col_width = slen;
410 threads__col_width = slen + 6;
411 }
412 }
413
414 return 0;
369} 415}
370 416
371static size_t thread__fprintf(struct thread *self, FILE *fp) 417static size_t thread__fprintf(struct thread *self, FILE *fp)
@@ -536,7 +582,9 @@ struct sort_entry {
536 582
537 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 583 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
538 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 584 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
539 size_t (*print)(FILE *fp, struct hist_entry *); 585 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
586 unsigned int *width;
587 bool elide;
540}; 588};
541 589
542static int64_t cmp_null(void *l, void *r) 590static int64_t cmp_null(void *l, void *r)
@@ -558,15 +606,17 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
558} 606}
559 607
560static size_t 608static size_t
561sort__thread_print(FILE *fp, struct hist_entry *self) 609sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
562{ 610{
563 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid); 611 return repsep_fprintf(fp, "%*s:%5d", width - 6,
612 self->thread->comm ?: "", self->thread->pid);
564} 613}
565 614
566static struct sort_entry sort_thread = { 615static struct sort_entry sort_thread = {
567 .header = " Command: Pid", 616 .header = "Command: Pid",
568 .cmp = sort__thread_cmp, 617 .cmp = sort__thread_cmp,
569 .print = sort__thread_print, 618 .print = sort__thread_print,
619 .width = &threads__col_width,
570}; 620};
571 621
572/* --sort comm */ 622/* --sort comm */
@@ -590,16 +640,17 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
590} 640}
591 641
592static size_t 642static size_t
593sort__comm_print(FILE *fp, struct hist_entry *self) 643sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
594{ 644{
595 return fprintf(fp, "%16s", self->thread->comm); 645 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
596} 646}
597 647
598static struct sort_entry sort_comm = { 648static struct sort_entry sort_comm = {
599 .header = " Command", 649 .header = "Command",
600 .cmp = sort__comm_cmp, 650 .cmp = sort__comm_cmp,
601 .collapse = sort__comm_collapse, 651 .collapse = sort__comm_collapse,
602 .print = sort__comm_print, 652 .print = sort__comm_print,
653 .width = &comms__col_width,
603}; 654};
604 655
605/* --sort dso */ 656/* --sort dso */
@@ -617,18 +668,19 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
617} 668}
618 669
619static size_t 670static size_t
620sort__dso_print(FILE *fp, struct hist_entry *self) 671sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
621{ 672{
622 if (self->dso) 673 if (self->dso)
623 return fprintf(fp, "%-25s", self->dso->name); 674 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
624 675
625 return fprintf(fp, "%016llx ", (u64)self->ip); 676 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
626} 677}
627 678
628static struct sort_entry sort_dso = { 679static struct sort_entry sort_dso = {
629 .header = "Shared Object ", 680 .header = "Shared Object",
630 .cmp = sort__dso_cmp, 681 .cmp = sort__dso_cmp,
631 .print = sort__dso_print, 682 .print = sort__dso_print,
683 .width = &dsos__col_width,
632}; 684};
633 685
634/* --sort symbol */ 686/* --sort symbol */
@@ -648,22 +700,22 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
648} 700}
649 701
650static size_t 702static size_t
651sort__sym_print(FILE *fp, struct hist_entry *self) 703sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
652{ 704{
653 size_t ret = 0; 705 size_t ret = 0;
654 706
655 if (verbose) 707 if (verbose)
656 ret += fprintf(fp, "%#018llx ", (u64)self->ip); 708 ret += repsep_fprintf(fp, "%#018llx ", (u64)self->ip);
657 709
710 ret += repsep_fprintf(fp, "[%c] ", self->level);
658 if (self->sym) { 711 if (self->sym) {
659 ret += fprintf(fp, "[%c] %s", 712 ret += repsep_fprintf(fp, "%s", self->sym->name);
660 self->dso == kernel_dso ? 'k' :
661 self->dso == hypervisor_dso ? 'h' : '.', self->sym->name);
662 713
663 if (self->sym->module) 714 if (self->sym->module)
664 ret += fprintf(fp, "\t[%s]", self->sym->module->name); 715 ret += repsep_fprintf(fp, "\t[%s]",
716 self->sym->module->name);
665 } else { 717 } else {
666 ret += fprintf(fp, "%#016llx", (u64)self->ip); 718 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
667 } 719 }
668 720
669 return ret; 721 return ret;
@@ -690,19 +742,19 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
690} 742}
691 743
692static size_t 744static size_t
693sort__parent_print(FILE *fp, struct hist_entry *self) 745sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
694{ 746{
695 size_t ret = 0; 747 return repsep_fprintf(fp, "%-*s", width,
696 748 self->parent ? self->parent->name : "[other]");
697 ret += fprintf(fp, "%-20s", self->parent ? self->parent->name : "[other]");
698
699 return ret;
700} 749}
701 750
751static unsigned int parent_symbol__col_width;
752
702static struct sort_entry sort_parent = { 753static struct sort_entry sort_parent = {
703 .header = "Parent symbol ", 754 .header = "Parent symbol",
704 .cmp = sort__parent_cmp, 755 .cmp = sort__parent_cmp,
705 .print = sort__parent_print, 756 .print = sort__parent_print,
757 .width = &parent_symbol__col_width,
706}; 758};
707 759
708static int sort__need_collapse = 0; 760static int sort__need_collapse = 0;
@@ -967,17 +1019,25 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
967 return 0; 1019 return 0;
968 1020
969 if (total_samples) 1021 if (total_samples)
970 ret = percent_color_fprintf(fp, " %6.2f%%", 1022 ret = percent_color_fprintf(fp,
971 (self->count * 100.0) / total_samples); 1023 field_sep ? "%.2f" : " %6.2f%%",
1024 (self->count * 100.0) / total_samples);
972 else 1025 else
973 ret = fprintf(fp, "%12Ld ", self->count); 1026 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
1027
1028 if (show_nr_samples) {
1029 if (field_sep)
1030 fprintf(fp, "%c%lld", *field_sep, self->count);
1031 else
1032 fprintf(fp, "%11lld", self->count);
1033 }
974 1034
975 list_for_each_entry(se, &hist_entry__sort_list, list) { 1035 list_for_each_entry(se, &hist_entry__sort_list, list) {
976 if (exclude_other && (se == &sort_parent)) 1036 if (se->elide)
977 continue; 1037 continue;
978 1038
979 fprintf(fp, " "); 1039 fprintf(fp, "%s", field_sep ?: " ");
980 ret += se->print(fp, self); 1040 ret += se->print(fp, self, se->width ? *se->width : 0);
981 } 1041 }
982 1042
983 ret += fprintf(fp, "\n"); 1043 ret += fprintf(fp, "\n");
@@ -992,6 +1052,18 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
992 * 1052 *
993 */ 1053 */
994 1054
1055static void dso__calc_col_width(struct dso *self)
1056{
1057 if (!col_width_list_str && !field_sep &&
1058 (!dso_list || strlist__has_entry(dso_list, self->name))) {
1059 unsigned int slen = strlen(self->name);
1060 if (slen > dsos__col_width)
1061 dsos__col_width = slen;
1062 }
1063
1064 self->slen_calculated = 1;
1065}
1066
995static struct symbol * 1067static struct symbol *
996resolve_symbol(struct thread *thread, struct map **mapp, 1068resolve_symbol(struct thread *thread, struct map **mapp,
997 struct dso **dsop, u64 *ipp) 1069 struct dso **dsop, u64 *ipp)
@@ -1011,6 +1083,14 @@ resolve_symbol(struct thread *thread, struct map **mapp,
1011 1083
1012 map = thread__find_map(thread, ip); 1084 map = thread__find_map(thread, ip);
1013 if (map != NULL) { 1085 if (map != NULL) {
1086 /*
1087 * We have to do this here as we may have a dso
1088 * with no symbol hit that has a name longer than
1089 * the ones with symbols sampled.
1090 */
1091 if (!sort_dso.elide && !map->dso->slen_calculated)
1092 dso__calc_col_width(map->dso);
1093
1014 if (mapp) 1094 if (mapp)
1015 *mapp = map; 1095 *mapp = map;
1016got_map: 1096got_map:
@@ -1282,35 +1362,67 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1282 struct sort_entry *se; 1362 struct sort_entry *se;
1283 struct rb_node *nd; 1363 struct rb_node *nd;
1284 size_t ret = 0; 1364 size_t ret = 0;
1365 unsigned int width;
1366 char *col_width = col_width_list_str;
1285 1367
1286 fprintf(fp, "\n"); 1368 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"); 1369 fprintf(fp, "#\n");
1290 1370
1291 fprintf(fp, "# Overhead"); 1371 fprintf(fp, "# Overhead");
1372 if (show_nr_samples) {
1373 if (field_sep)
1374 fprintf(fp, "%cSamples", *field_sep);
1375 else
1376 fputs(" Samples ", fp);
1377 }
1292 list_for_each_entry(se, &hist_entry__sort_list, list) { 1378 list_for_each_entry(se, &hist_entry__sort_list, list) {
1293 if (exclude_other && (se == &sort_parent)) 1379 if (se->elide)
1380 continue;
1381 if (field_sep) {
1382 fprintf(fp, "%c%s", *field_sep, se->header);
1294 continue; 1383 continue;
1295 fprintf(fp, " %s", se->header); 1384 }
1385 width = strlen(se->header);
1386 if (se->width) {
1387 if (col_width_list_str) {
1388 if (col_width) {
1389 *se->width = atoi(col_width);
1390 col_width = strchr(col_width, ',');
1391 if (col_width)
1392 ++col_width;
1393 }
1394 }
1395 width = *se->width = max(*se->width, width);
1396 }
1397 fprintf(fp, " %*s", width, se->header);
1296 } 1398 }
1297 fprintf(fp, "\n"); 1399 fprintf(fp, "\n");
1298 1400
1401 if (field_sep)
1402 goto print_entries;
1403
1299 fprintf(fp, "# ........"); 1404 fprintf(fp, "# ........");
1405 if (show_nr_samples)
1406 fprintf(fp, " ..........");
1300 list_for_each_entry(se, &hist_entry__sort_list, list) { 1407 list_for_each_entry(se, &hist_entry__sort_list, list) {
1301 unsigned int i; 1408 unsigned int i;
1302 1409
1303 if (exclude_other && (se == &sort_parent)) 1410 if (se->elide)
1304 continue; 1411 continue;
1305 1412
1306 fprintf(fp, " "); 1413 fprintf(fp, " ");
1307 for (i = 0; i < strlen(se->header); i++) 1414 if (se->width)
1415 width = *se->width;
1416 else
1417 width = strlen(se->header);
1418 for (i = 0; i < width; i++)
1308 fprintf(fp, "."); 1419 fprintf(fp, ".");
1309 } 1420 }
1310 fprintf(fp, "\n"); 1421 fprintf(fp, "\n");
1311 1422
1312 fprintf(fp, "#\n"); 1423 fprintf(fp, "#\n");
1313 1424
1425print_entries:
1314 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { 1426 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1315 pos = rb_entry(nd, struct hist_entry, rb_node); 1427 pos = rb_entry(nd, struct hist_entry, rb_node);
1316 ret += hist_entry__fprintf(fp, pos, total_samples); 1428 ret += hist_entry__fprintf(fp, pos, total_samples);
@@ -1883,6 +1995,8 @@ static const struct option options[] = {
1883 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1995 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1884 OPT_BOOLEAN('m', "modules", &modules, 1996 OPT_BOOLEAN('m', "modules", &modules,
1885 "load module symbols - WARNING: use only with -k and LIVE kernel"), 1997 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1998 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1999 "Show a column with the number of samples"),
1886 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 2000 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1887 "sort by key(s): pid, comm, dso, symbol, parent"), 2001 "sort by key(s): pid, comm, dso, symbol, parent"),
1888 OPT_BOOLEAN('P', "full-paths", &full_paths, 2002 OPT_BOOLEAN('P', "full-paths", &full_paths,
@@ -1900,6 +2014,12 @@ static const struct option options[] = {
1900 "only consider symbols in these comms"), 2014 "only consider symbols in these comms"),
1901 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 2015 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1902 "only consider these symbols"), 2016 "only consider these symbols"),
2017 OPT_STRING('w', "column-widths", &col_width_list_str,
2018 "width[,width...]",
2019 "don't try to adjust column width, use these fixed values"),
2020 OPT_STRING('t', "field-separator", &field_sep, "separator",
2021 "separator for columns, no spaces will be added between "
2022 "columns '.' is reserved."),
1903 OPT_END() 2023 OPT_END()
1904}; 2024};
1905 2025
@@ -1919,7 +2039,8 @@ static void setup_sorting(void)
1919} 2039}
1920 2040
1921static void setup_list(struct strlist **list, const char *list_str, 2041static void setup_list(struct strlist **list, const char *list_str,
1922 const char *list_name) 2042 struct sort_entry *se, const char *list_name,
2043 FILE *fp)
1923{ 2044{
1924 if (list_str) { 2045 if (list_str) {
1925 *list = strlist__new(true, list_str); 2046 *list = strlist__new(true, list_str);
@@ -1928,6 +2049,11 @@ static void setup_list(struct strlist **list, const char *list_str,
1928 list_name); 2049 list_name);
1929 exit(129); 2050 exit(129);
1930 } 2051 }
2052 if (strlist__nr_entries(*list) == 1) {
2053 fprintf(fp, "# %s: %s\n", list_name,
2054 strlist__entry(*list, 0)->s);
2055 se->elide = true;
2056 }
1931 } 2057 }
1932} 2058}
1933 2059
@@ -1941,9 +2067,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1941 2067
1942 setup_sorting(); 2068 setup_sorting();
1943 2069
1944 if (parent_pattern != default_parent_pattern) 2070 if (parent_pattern != default_parent_pattern) {
1945 sort_dimension__add("parent"); 2071 sort_dimension__add("parent");
1946 else 2072 sort_parent.elide = 1;
2073 } else
1947 exclude_other = 0; 2074 exclude_other = 0;
1948 2075
1949 /* 2076 /*
@@ -1952,11 +2079,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1952 if (argc) 2079 if (argc)
1953 usage_with_options(report_usage, options); 2080 usage_with_options(report_usage, options);
1954 2081
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(); 2082 setup_pager();
1960 2083
2084 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
2085 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
2086 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
2087
2088 if (field_sep && *field_sep == '.') {
2089 fputs("'.' is the only non valid --field-separator argument\n",
2090 stderr);
2091 exit(129);
2092 }
2093
1961 return __cmd_report(); 2094 return __cmd_report();
1962} 2095}