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.c219
1 files changed, 5 insertions, 214 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 95887804dc8e..6d9c92c3d7cb 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"
@@ -949,225 +950,15 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
949 } 950 }
950} 951}
951 952
952static int symbol__alloc_hist(struct symbol *self) 953int hist_entry__inc_addr_samples(struct hist_entry *he, u64 ip)
953{ 954{
954 struct sym_priv *priv = symbol__priv(self); 955 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, ip);
955 const int size = (sizeof(*priv->hist) +
956 (self->end - self->start) * sizeof(u64));
957
958 priv->hist = zalloc(size);
959 return priv->hist == NULL ? -1 : 0;
960}
961
962int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
963{
964 unsigned int sym_size, offset;
965 struct symbol *sym = self->ms.sym;
966 struct sym_priv *priv;
967 struct sym_hist *h;
968
969 if (!sym || !self->ms.map)
970 return 0;
971
972 priv = symbol__priv(sym);
973 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
974 return -ENOMEM;
975
976 sym_size = sym->end - sym->start;
977 offset = ip - sym->start;
978
979 pr_debug3("%s: ip=%#" PRIx64 "\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
980
981 if (offset >= sym_size)
982 return 0;
983
984 h = priv->hist;
985 h->sum++;
986 h->ip[offset]++;
987
988 pr_debug3("%#" PRIx64 " %s: period++ [ip: %#" PRIx64 ", %#" PRIx64
989 "] => %" PRIu64 "\n", self->ms.sym->start, self->ms.sym->name,
990 ip, ip - self->ms.sym->start, h->ip[offset]);
991 return 0;
992}
993
994static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
995{
996 struct objdump_line *self = malloc(sizeof(*self) + privsize);
997
998 if (self != NULL) {
999 self->offset = offset;
1000 self->line = line;
1001 }
1002
1003 return self;
1004}
1005
1006void objdump_line__free(struct objdump_line *self)
1007{
1008 free(self->line);
1009 free(self);
1010}
1011
1012static void objdump__add_line(struct list_head *head, struct objdump_line *line)
1013{
1014 list_add_tail(&line->node, head);
1015}
1016
1017struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
1018 struct objdump_line *pos)
1019{
1020 list_for_each_entry_continue(pos, head, node)
1021 if (pos->offset >= 0)
1022 return pos;
1023
1024 return NULL;
1025} 956}
1026 957
1027static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file, 958int hist_entry__annotate(struct hist_entry *he, struct list_head *head,
1028 struct list_head *head, size_t privsize)
1029{
1030 struct symbol *sym = self->ms.sym;
1031 struct objdump_line *objdump_line;
1032 char *line = NULL, *tmp, *tmp2, *c;
1033 size_t line_len;
1034 s64 line_ip, offset = -1;
1035
1036 if (getline(&line, &line_len, file) < 0)
1037 return -1;
1038
1039 if (!line)
1040 return -1;
1041
1042 while (line_len != 0 && isspace(line[line_len - 1]))
1043 line[--line_len] = '\0';
1044
1045 c = strchr(line, '\n');
1046 if (c)
1047 *c = 0;
1048
1049 line_ip = -1;
1050
1051 /*
1052 * Strip leading spaces:
1053 */
1054 tmp = line;
1055 while (*tmp) {
1056 if (*tmp != ' ')
1057 break;
1058 tmp++;
1059 }
1060
1061 if (*tmp) {
1062 /*
1063 * Parse hexa addresses followed by ':'
1064 */
1065 line_ip = strtoull(tmp, &tmp2, 16);
1066 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1067 line_ip = -1;
1068 }
1069
1070 if (line_ip != -1) {
1071 u64 start = map__rip_2objdump(self->ms.map, sym->start),
1072 end = map__rip_2objdump(self->ms.map, sym->end);
1073
1074 offset = line_ip - start;
1075 if (offset < 0 || (u64)line_ip > end)
1076 offset = -1;
1077 }
1078
1079 objdump_line = objdump_line__new(offset, line, privsize);
1080 if (objdump_line == NULL) {
1081 free(line);
1082 return -1;
1083 }
1084 objdump__add_line(head, objdump_line);
1085
1086 return 0;
1087}
1088
1089int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
1090 size_t privsize) 959 size_t privsize)
1091{ 960{
1092 struct symbol *sym = self->ms.sym; 961 return symbol__annotate(he->ms.sym, he->ms.map, head, privsize);
1093 struct map *map = self->ms.map;
1094 struct dso *dso = map->dso;
1095 char *filename = dso__build_id_filename(dso, NULL, 0);
1096 bool free_filename = true;
1097 char command[PATH_MAX * 2];
1098 FILE *file;
1099 int err = 0;
1100 u64 len;
1101 char symfs_filename[PATH_MAX];
1102
1103 if (filename) {
1104 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1105 symbol_conf.symfs, filename);
1106 }
1107
1108 if (filename == NULL) {
1109 if (dso->has_build_id) {
1110 pr_err("Can't annotate %s: not enough memory\n",
1111 sym->name);
1112 return -ENOMEM;
1113 }
1114 goto fallback;
1115 } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
1116 strstr(command, "[kernel.kallsyms]") ||
1117 access(symfs_filename, R_OK)) {
1118 free(filename);
1119fallback:
1120 /*
1121 * If we don't have build-ids or the build-id file isn't in the
1122 * cache, or is just a kallsyms file, well, lets hope that this
1123 * DSO is the same as when 'perf record' ran.
1124 */
1125 filename = dso->long_name;
1126 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1127 symbol_conf.symfs, filename);
1128 free_filename = false;
1129 }
1130
1131 if (dso->origin == DSO__ORIG_KERNEL) {
1132 if (dso->annotate_warned)
1133 goto out_free_filename;
1134 err = -ENOENT;
1135 dso->annotate_warned = 1;
1136 pr_err("Can't annotate %s: No vmlinux file was found in the "
1137 "path\n", sym->name);
1138 goto out_free_filename;
1139 }
1140
1141 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
1142 filename, sym->name, map->unmap_ip(map, sym->start),
1143 map->unmap_ip(map, sym->end));
1144
1145 len = sym->end - sym->start;
1146
1147 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1148 dso, dso->long_name, sym, sym->name);
1149
1150 snprintf(command, sizeof(command),
1151 "objdump --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
1152 map__rip_2objdump(map, sym->start),
1153 map__rip_2objdump(map, sym->end),
1154 symfs_filename, filename);
1155
1156 pr_debug("Executing: %s\n", command);
1157
1158 file = popen(command, "r");
1159 if (!file)
1160 goto out_free_filename;
1161
1162 while (!feof(file))
1163 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1164 break;
1165
1166 pclose(file);
1167out_free_filename:
1168 if (free_filename)
1169 free(filename);
1170 return err;
1171} 962}
1172 963
1173void hists__inc_nr_events(struct hists *self, u32 type) 964void hists__inc_nr_events(struct hists *self, u32 type)