aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/hist.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/hist.c')
-rw-r--r--tools/perf/util/hist.c250
1 files changed, 29 insertions, 221 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index df51560f16f7..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))
@@ -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,8 +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;
229 if (symbol_conf.use_callchain) 241 if (symbol_conf.use_callchain) {
230 callchain_merge(iter->callchain, he->callchain); 242 callchain_cursor_reset(&self->callchain_cursor);
243 callchain_merge(&self->callchain_cursor, iter->callchain,
244 he->callchain);
245 }
231 hist_entry__free(he); 246 hist_entry__free(he);
232 return false; 247 return false;
233 } 248 }
@@ -262,7 +277,7 @@ void hists__collapse_resort(struct hists *self)
262 next = rb_next(&n->rb_node); 277 next = rb_next(&n->rb_node);
263 278
264 rb_erase(&n->rb_node, &self->entries); 279 rb_erase(&n->rb_node, &self->entries);
265 if (collapse__insert_entry(&tmp, n)) 280 if (hists__collapse_insert_entry(self, &tmp, n))
266 hists__inc_nr_entries(self, n); 281 hists__inc_nr_entries(self, n);
267 } 282 }
268 283
@@ -425,7 +440,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
425 u64 cumul; 440 u64 cumul;
426 441
427 child = rb_entry(node, struct callchain_node, rb_node); 442 child = rb_entry(node, struct callchain_node, rb_node);
428 cumul = cumul_hits(child); 443 cumul = callchain_cumul_hits(child);
429 remaining -= cumul; 444 remaining -= cumul;
430 445
431 /* 446 /*
@@ -947,225 +962,14 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
947 } 962 }
948} 963}
949 964
950static int symbol__alloc_hist(struct symbol *self) 965int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
951{
952 struct sym_priv *priv = symbol__priv(self);
953 const int size = (sizeof(*priv->hist) +
954 (self->end - self->start) * sizeof(u64));
955
956 priv->hist = zalloc(size);
957 return priv->hist == NULL ? -1 : 0;
958}
959
960int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
961{
962 unsigned int sym_size, offset;
963 struct symbol *sym = self->ms.sym;
964 struct sym_priv *priv;
965 struct sym_hist *h;
966
967 if (!sym || !self->ms.map)
968 return 0;
969
970 priv = symbol__priv(sym);
971 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
972 return -ENOMEM;
973
974 sym_size = sym->end - sym->start;
975 offset = ip - sym->start;
976
977 pr_debug3("%s: ip=%#" PRIx64 "\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
978
979 if (offset >= sym_size)
980 return 0;
981
982 h = priv->hist;
983 h->sum++;
984 h->ip[offset]++;
985
986 pr_debug3("%#" PRIx64 " %s: period++ [ip: %#" PRIx64 ", %#" PRIx64
987 "] => %" PRIu64 "\n", self->ms.sym->start, self->ms.sym->name,
988 ip, ip - self->ms.sym->start, h->ip[offset]);
989 return 0;
990}
991
992static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
993{
994 struct objdump_line *self = malloc(sizeof(*self) + privsize);
995
996 if (self != NULL) {
997 self->offset = offset;
998 self->line = line;
999 }
1000
1001 return self;
1002}
1003
1004void objdump_line__free(struct objdump_line *self)
1005{
1006 free(self->line);
1007 free(self);
1008}
1009
1010static void objdump__add_line(struct list_head *head, struct objdump_line *line)
1011{
1012 list_add_tail(&line->node, head);
1013}
1014
1015struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
1016 struct objdump_line *pos)
1017{
1018 list_for_each_entry_continue(pos, head, node)
1019 if (pos->offset >= 0)
1020 return pos;
1021
1022 return NULL;
1023}
1024
1025static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
1026 struct list_head *head, size_t privsize)
1027{ 966{
1028 struct symbol *sym = self->ms.sym; 967 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
1029 struct objdump_line *objdump_line;
1030 char *line = NULL, *tmp, *tmp2, *c;
1031 size_t line_len;
1032 s64 line_ip, offset = -1;
1033
1034 if (getline(&line, &line_len, file) < 0)
1035 return -1;
1036
1037 if (!line)
1038 return -1;
1039
1040 while (line_len != 0 && isspace(line[line_len - 1]))
1041 line[--line_len] = '\0';
1042
1043 c = strchr(line, '\n');
1044 if (c)
1045 *c = 0;
1046
1047 line_ip = -1;
1048
1049 /*
1050 * Strip leading spaces:
1051 */
1052 tmp = line;
1053 while (*tmp) {
1054 if (*tmp != ' ')
1055 break;
1056 tmp++;
1057 }
1058
1059 if (*tmp) {
1060 /*
1061 * Parse hexa addresses followed by ':'
1062 */
1063 line_ip = strtoull(tmp, &tmp2, 16);
1064 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1065 line_ip = -1;
1066 }
1067
1068 if (line_ip != -1) {
1069 u64 start = map__rip_2objdump(self->ms.map, sym->start),
1070 end = map__rip_2objdump(self->ms.map, sym->end);
1071
1072 offset = line_ip - start;
1073 if (offset < 0 || (u64)line_ip > end)
1074 offset = -1;
1075 }
1076
1077 objdump_line = objdump_line__new(offset, line, privsize);
1078 if (objdump_line == NULL) {
1079 free(line);
1080 return -1;
1081 }
1082 objdump__add_line(head, objdump_line);
1083
1084 return 0;
1085} 968}
1086 969
1087int hist_entry__annotate(struct hist_entry *self, struct list_head *head, 970int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1088 size_t privsize)
1089{ 971{
1090 struct symbol *sym = self->ms.sym; 972 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1091 struct map *map = self->ms.map;
1092 struct dso *dso = map->dso;
1093 char *filename = dso__build_id_filename(dso, NULL, 0);
1094 bool free_filename = true;
1095 char command[PATH_MAX * 2];
1096 FILE *file;
1097 int err = 0;
1098 u64 len;
1099 char symfs_filename[PATH_MAX];
1100
1101 if (filename) {
1102 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1103 symbol_conf.symfs, filename);
1104 }
1105
1106 if (filename == NULL) {
1107 if (dso->has_build_id) {
1108 pr_err("Can't annotate %s: not enough memory\n",
1109 sym->name);
1110 return -ENOMEM;
1111 }
1112 goto fallback;
1113 } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
1114 strstr(command, "[kernel.kallsyms]") ||
1115 access(symfs_filename, R_OK)) {
1116 free(filename);
1117fallback:
1118 /*
1119 * If we don't have build-ids or the build-id file isn't in the
1120 * cache, or is just a kallsyms file, well, lets hope that this
1121 * DSO is the same as when 'perf record' ran.
1122 */
1123 filename = dso->long_name;
1124 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1125 symbol_conf.symfs, filename);
1126 free_filename = false;
1127 }
1128
1129 if (dso->origin == DSO__ORIG_KERNEL) {
1130 if (dso->annotate_warned)
1131 goto out_free_filename;
1132 err = -ENOENT;
1133 dso->annotate_warned = 1;
1134 pr_err("Can't annotate %s: No vmlinux file was found in the "
1135 "path\n", sym->name);
1136 goto out_free_filename;
1137 }
1138
1139 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
1140 filename, sym->name, map->unmap_ip(map, sym->start),
1141 map->unmap_ip(map, sym->end));
1142
1143 len = sym->end - sym->start;
1144
1145 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1146 dso, dso->long_name, sym, sym->name);
1147
1148 snprintf(command, sizeof(command),
1149 "objdump --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
1150 map__rip_2objdump(map, sym->start),
1151 map__rip_2objdump(map, sym->end),
1152 symfs_filename, filename);
1153
1154 pr_debug("Executing: %s\n", command);
1155
1156 file = popen(command, "r");
1157 if (!file)
1158 goto out_free_filename;
1159
1160 while (!feof(file))
1161 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1162 break;
1163
1164 pclose(file);
1165out_free_filename:
1166 if (free_filename)
1167 free(filename);
1168 return err;
1169} 973}
1170 974
1171void hists__inc_nr_events(struct hists *self, u32 type) 975void hists__inc_nr_events(struct hists *self, u32 type)
@@ -1180,8 +984,12 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
1180 size_t ret = 0; 984 size_t ret = 0;
1181 985
1182 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 986 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1183 const char *name = event__get_event_name(i); 987 const char *name;
988
989 if (self->stats.nr_events[i] == 0)
990 continue;
1184 991
992 name = perf_event__name(i);
1185 if (!strcmp(name, "UNKNOWN")) 993 if (!strcmp(name, "UNKNOWN"))
1186 continue; 994 continue;
1187 995