aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/hist.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /tools/perf/util/hist.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'tools/perf/util/hist.c')
-rw-r--r--tools/perf/util/hist.c259
1 files changed, 42 insertions, 217 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index be22ae6ef055..627a02e03c57 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1,3 +1,4 @@
1#include "annotate.h"
1#include "util.h" 2#include "util.h"
2#include "build-id.h" 3#include "build-id.h"
3#include "hist.h" 4#include "hist.h"
@@ -49,6 +50,15 @@ static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
49 50
50 if (h->ms.sym) 51 if (h->ms.sym)
51 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen); 52 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
53 else {
54 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
55
56 if (hists__col_len(self, HISTC_DSO) < unresolved_col_width &&
57 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
58 !symbol_conf.dso_list)
59 hists__set_col_len(self, HISTC_DSO,
60 unresolved_col_width);
61 }
52 62
53 len = thread__comm_len(h->thread); 63 len = thread__comm_len(h->thread);
54 if (hists__new_col_len(self, HISTC_COMM, len)) 64 if (hists__new_col_len(self, HISTC_COMM, len))
@@ -87,7 +97,7 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self,
87 97
88static struct hist_entry *hist_entry__new(struct hist_entry *template) 98static struct hist_entry *hist_entry__new(struct hist_entry *template)
89{ 99{
90 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_node) : 0; 100 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
91 struct hist_entry *self = malloc(sizeof(*self) + callchain_size); 101 struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
92 102
93 if (self != NULL) { 103 if (self != NULL) {
@@ -211,7 +221,9 @@ void hist_entry__free(struct hist_entry *he)
211 * collapse the histogram 221 * collapse the histogram
212 */ 222 */
213 223
214static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he) 224static bool hists__collapse_insert_entry(struct hists *self,
225 struct rb_root *root,
226 struct hist_entry *he)
215{ 227{
216 struct rb_node **p = &root->rb_node; 228 struct rb_node **p = &root->rb_node;
217 struct rb_node *parent = NULL; 229 struct rb_node *parent = NULL;
@@ -226,6 +238,11 @@ static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
226 238
227 if (!cmp) { 239 if (!cmp) {
228 iter->period += he->period; 240 iter->period += he->period;
241 if (symbol_conf.use_callchain) {
242 callchain_cursor_reset(&self->callchain_cursor);
243 callchain_merge(&self->callchain_cursor, iter->callchain,
244 he->callchain);
245 }
229 hist_entry__free(he); 246 hist_entry__free(he);
230 return false; 247 return false;
231 } 248 }
@@ -260,7 +277,7 @@ void hists__collapse_resort(struct hists *self)
260 next = rb_next(&n->rb_node); 277 next = rb_next(&n->rb_node);
261 278
262 rb_erase(&n->rb_node, &self->entries); 279 rb_erase(&n->rb_node, &self->entries);
263 if (collapse__insert_entry(&tmp, n)) 280 if (hists__collapse_insert_entry(self, &tmp, n))
264 hists__inc_nr_entries(self, n); 281 hists__inc_nr_entries(self, n);
265 } 282 }
266 283
@@ -354,7 +371,7 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
354 371
355static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, 372static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
356 int depth, int depth_mask, int period, 373 int depth, int depth_mask, int period,
357 u64 total_samples, int hits, 374 u64 total_samples, u64 hits,
358 int left_margin) 375 int left_margin)
359{ 376{
360 int i; 377 int i;
@@ -423,7 +440,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
423 u64 cumul; 440 u64 cumul;
424 441
425 child = rb_entry(node, struct callchain_node, rb_node); 442 child = rb_entry(node, struct callchain_node, rb_node);
426 cumul = cumul_hits(child); 443 cumul = callchain_cumul_hits(child);
427 remaining -= cumul; 444 remaining -= cumul;
428 445
429 /* 446 /*
@@ -583,6 +600,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
583{ 600{
584 struct sort_entry *se; 601 struct sort_entry *se;
585 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; 602 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
603 u64 nr_events;
586 const char *sep = symbol_conf.field_sep; 604 const char *sep = symbol_conf.field_sep;
587 int ret; 605 int ret;
588 606
@@ -591,6 +609,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
591 609
592 if (pair_hists) { 610 if (pair_hists) {
593 period = self->pair ? self->pair->period : 0; 611 period = self->pair ? self->pair->period : 0;
612 nr_events = self->pair ? self->pair->nr_events : 0;
594 total = pair_hists->stats.total_period; 613 total = pair_hists->stats.total_period;
595 period_sys = self->pair ? self->pair->period_sys : 0; 614 period_sys = self->pair ? self->pair->period_sys : 0;
596 period_us = self->pair ? self->pair->period_us : 0; 615 period_us = self->pair ? self->pair->period_us : 0;
@@ -598,6 +617,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
598 period_guest_us = self->pair ? self->pair->period_guest_us : 0; 617 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
599 } else { 618 } else {
600 period = self->period; 619 period = self->period;
620 nr_events = self->nr_events;
601 total = session_total; 621 total = session_total;
602 period_sys = self->period_sys; 622 period_sys = self->period_sys;
603 period_us = self->period_us; 623 period_us = self->period_us;
@@ -634,13 +654,13 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
634 } 654 }
635 } 655 }
636 } else 656 } else
637 ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period); 657 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
638 658
639 if (symbol_conf.show_nr_samples) { 659 if (symbol_conf.show_nr_samples) {
640 if (sep) 660 if (sep)
641 ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period); 661 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
642 else 662 else
643 ret += snprintf(s + ret, size - ret, "%11lld", period); 663 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
644 } 664 }
645 665
646 if (pair_hists) { 666 if (pair_hists) {
@@ -942,216 +962,14 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
942 } 962 }
943} 963}
944 964
945static int symbol__alloc_hist(struct symbol *self) 965int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
946{
947 struct sym_priv *priv = symbol__priv(self);
948 const int size = (sizeof(*priv->hist) +
949 (self->end - self->start) * sizeof(u64));
950
951 priv->hist = zalloc(size);
952 return priv->hist == NULL ? -1 : 0;
953}
954
955int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
956{
957 unsigned int sym_size, offset;
958 struct symbol *sym = self->ms.sym;
959 struct sym_priv *priv;
960 struct sym_hist *h;
961
962 if (!sym || !self->ms.map)
963 return 0;
964
965 priv = symbol__priv(sym);
966 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
967 return -ENOMEM;
968
969 sym_size = sym->end - sym->start;
970 offset = ip - sym->start;
971
972 pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
973
974 if (offset >= sym_size)
975 return 0;
976
977 h = priv->hist;
978 h->sum++;
979 h->ip[offset]++;
980
981 pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
982 self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
983 return 0;
984}
985
986static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
987{
988 struct objdump_line *self = malloc(sizeof(*self) + privsize);
989
990 if (self != NULL) {
991 self->offset = offset;
992 self->line = line;
993 }
994
995 return self;
996}
997
998void objdump_line__free(struct objdump_line *self)
999{
1000 free(self->line);
1001 free(self);
1002}
1003
1004static void objdump__add_line(struct list_head *head, struct objdump_line *line)
1005{
1006 list_add_tail(&line->node, head);
1007}
1008
1009struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
1010 struct objdump_line *pos)
1011{
1012 list_for_each_entry_continue(pos, head, node)
1013 if (pos->offset >= 0)
1014 return pos;
1015
1016 return NULL;
1017}
1018
1019static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
1020 struct list_head *head, size_t privsize)
1021{ 966{
1022 struct symbol *sym = self->ms.sym; 967 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
1023 struct objdump_line *objdump_line;
1024 char *line = NULL, *tmp, *tmp2, *c;
1025 size_t line_len;
1026 s64 line_ip, offset = -1;
1027
1028 if (getline(&line, &line_len, file) < 0)
1029 return -1;
1030
1031 if (!line)
1032 return -1;
1033
1034 while (line_len != 0 && isspace(line[line_len - 1]))
1035 line[--line_len] = '\0';
1036
1037 c = strchr(line, '\n');
1038 if (c)
1039 *c = 0;
1040
1041 line_ip = -1;
1042
1043 /*
1044 * Strip leading spaces:
1045 */
1046 tmp = line;
1047 while (*tmp) {
1048 if (*tmp != ' ')
1049 break;
1050 tmp++;
1051 }
1052
1053 if (*tmp) {
1054 /*
1055 * Parse hexa addresses followed by ':'
1056 */
1057 line_ip = strtoull(tmp, &tmp2, 16);
1058 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1059 line_ip = -1;
1060 }
1061
1062 if (line_ip != -1) {
1063 u64 start = map__rip_2objdump(self->ms.map, sym->start),
1064 end = map__rip_2objdump(self->ms.map, sym->end);
1065
1066 offset = line_ip - start;
1067 if (offset < 0 || (u64)line_ip > end)
1068 offset = -1;
1069 }
1070
1071 objdump_line = objdump_line__new(offset, line, privsize);
1072 if (objdump_line == NULL) {
1073 free(line);
1074 return -1;
1075 }
1076 objdump__add_line(head, objdump_line);
1077
1078 return 0;
1079} 968}
1080 969
1081int hist_entry__annotate(struct hist_entry *self, struct list_head *head, 970int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1082 size_t privsize)
1083{ 971{
1084 struct symbol *sym = self->ms.sym; 972 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1085 struct map *map = self->ms.map;
1086 struct dso *dso = map->dso;
1087 char *filename = dso__build_id_filename(dso, NULL, 0);
1088 bool free_filename = true;
1089 char command[PATH_MAX * 2];
1090 FILE *file;
1091 int err = 0;
1092 u64 len;
1093
1094 if (filename == NULL) {
1095 if (dso->has_build_id) {
1096 pr_err("Can't annotate %s: not enough memory\n",
1097 sym->name);
1098 return -ENOMEM;
1099 }
1100 goto fallback;
1101 } else if (readlink(filename, command, sizeof(command)) < 0 ||
1102 strstr(command, "[kernel.kallsyms]") ||
1103 access(filename, R_OK)) {
1104 free(filename);
1105fallback:
1106 /*
1107 * If we don't have build-ids or the build-id file isn't in the
1108 * cache, or is just a kallsyms file, well, lets hope that this
1109 * DSO is the same as when 'perf record' ran.
1110 */
1111 filename = dso->long_name;
1112 free_filename = false;
1113 }
1114
1115 if (dso->origin == DSO__ORIG_KERNEL) {
1116 if (dso->annotate_warned)
1117 goto out_free_filename;
1118 err = -ENOENT;
1119 dso->annotate_warned = 1;
1120 pr_err("Can't annotate %s: No vmlinux file was found in the "
1121 "path\n", sym->name);
1122 goto out_free_filename;
1123 }
1124
1125 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
1126 filename, sym->name, map->unmap_ip(map, sym->start),
1127 map->unmap_ip(map, sym->end));
1128
1129 len = sym->end - sym->start;
1130
1131 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1132 dso, dso->long_name, sym, sym->name);
1133
1134 snprintf(command, sizeof(command),
1135 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
1136 map__rip_2objdump(map, sym->start),
1137 map__rip_2objdump(map, sym->end),
1138 filename, filename);
1139
1140 pr_debug("Executing: %s\n", command);
1141
1142 file = popen(command, "r");
1143 if (!file)
1144 goto out_free_filename;
1145
1146 while (!feof(file))
1147 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1148 break;
1149
1150 pclose(file);
1151out_free_filename:
1152 if (free_filename)
1153 free(filename);
1154 return err;
1155} 973}
1156 974
1157void hists__inc_nr_events(struct hists *self, u32 type) 975void hists__inc_nr_events(struct hists *self, u32 type)
@@ -1166,10 +984,17 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
1166 size_t ret = 0; 984 size_t ret = 0;
1167 985
1168 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 986 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1169 if (!event__name[i]) 987 const char *name;
988
989 if (self->stats.nr_events[i] == 0)
990 continue;
991
992 name = perf_event__name(i);
993 if (!strcmp(name, "UNKNOWN"))
1170 continue; 994 continue;
1171 ret += fprintf(fp, "%10s events: %10d\n", 995
1172 event__name[i], self->stats.nr_events[i]); 996 ret += fprintf(fp, "%16s events: %10d\n", name,
997 self->stats.nr_events[i]);
1173 } 998 }
1174 999
1175 return ret; 1000 return ret;