diff options
Diffstat (limited to 'tools/perf/util/hist.c')
-rw-r--r-- | tools/perf/util/hist.c | 219 |
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 | ||
952 | static int symbol__alloc_hist(struct symbol *self) | 953 | int 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 | |||
962 | int 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 | |||
994 | static 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 | |||
1006 | void objdump_line__free(struct objdump_line *self) | ||
1007 | { | ||
1008 | free(self->line); | ||
1009 | free(self); | ||
1010 | } | ||
1011 | |||
1012 | static void objdump__add_line(struct list_head *head, struct objdump_line *line) | ||
1013 | { | ||
1014 | list_add_tail(&line->node, head); | ||
1015 | } | ||
1016 | |||
1017 | struct 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 | ||
1027 | static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file, | 958 | int 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 | |||
1089 | int 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); | ||
1119 | fallback: | ||
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); | ||
1167 | out_free_filename: | ||
1168 | if (free_filename) | ||
1169 | free(filename); | ||
1170 | return err; | ||
1171 | } | 962 | } |
1172 | 963 | ||
1173 | void hists__inc_nr_events(struct hists *self, u32 type) | 964 | void hists__inc_nr_events(struct hists *self, u32 type) |