diff options
Diffstat (limited to 'tools/perf/builtin-annotate.c')
| -rw-r--r-- | tools/perf/builtin-annotate.c | 198 |
1 files changed, 2 insertions, 196 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 3940964161b3..fd1b786c8f35 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -34,68 +34,8 @@ static bool full_paths; | |||
| 34 | 34 | ||
| 35 | static bool print_line; | 35 | static bool print_line; |
| 36 | 36 | ||
| 37 | struct sym_hist { | ||
| 38 | u64 sum; | ||
| 39 | u64 ip[0]; | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct sym_ext { | ||
| 43 | struct rb_node node; | ||
| 44 | double percent; | ||
| 45 | char *path; | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct sym_priv { | ||
| 49 | struct sym_hist *hist; | ||
| 50 | struct sym_ext *ext; | ||
| 51 | }; | ||
| 52 | |||
| 53 | static const char *sym_hist_filter; | 37 | static const char *sym_hist_filter; |
| 54 | 38 | ||
| 55 | static int sym__alloc_hist(struct symbol *self) | ||
| 56 | { | ||
| 57 | struct sym_priv *priv = symbol__priv(self); | ||
| 58 | const int size = (sizeof(*priv->hist) + | ||
| 59 | (self->end - self->start) * sizeof(u64)); | ||
| 60 | |||
| 61 | priv->hist = zalloc(size); | ||
| 62 | return priv->hist == NULL ? -1 : 0; | ||
| 63 | } | ||
| 64 | |||
| 65 | /* | ||
| 66 | * collect histogram counts | ||
| 67 | */ | ||
| 68 | static int annotate__hist_hit(struct hist_entry *he, u64 ip) | ||
| 69 | { | ||
| 70 | unsigned int sym_size, offset; | ||
| 71 | struct symbol *sym = he->ms.sym; | ||
| 72 | struct sym_priv *priv; | ||
| 73 | struct sym_hist *h; | ||
| 74 | |||
| 75 | if (!sym || !he->ms.map) | ||
| 76 | return 0; | ||
| 77 | |||
| 78 | priv = symbol__priv(sym); | ||
| 79 | if (priv->hist == NULL && sym__alloc_hist(sym) < 0) | ||
| 80 | return -ENOMEM; | ||
| 81 | |||
| 82 | sym_size = sym->end - sym->start; | ||
| 83 | offset = ip - sym->start; | ||
| 84 | |||
| 85 | pr_debug3("%s: ip=%#Lx\n", __func__, he->ms.map->unmap_ip(he->ms.map, ip)); | ||
| 86 | |||
| 87 | if (offset >= sym_size) | ||
| 88 | return 0; | ||
| 89 | |||
| 90 | h = priv->hist; | ||
| 91 | h->sum++; | ||
| 92 | h->ip[offset]++; | ||
| 93 | |||
| 94 | pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", he->ms.sym->start, | ||
| 95 | he->ms.sym->name, ip, ip - he->ms.sym->start, h->ip[offset]); | ||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int hists__add_entry(struct hists *self, struct addr_location *al) | 39 | static int hists__add_entry(struct hists *self, struct addr_location *al) |
| 100 | { | 40 | { |
| 101 | struct hist_entry *he; | 41 | struct hist_entry *he; |
| @@ -115,7 +55,7 @@ static int hists__add_entry(struct hists *self, struct addr_location *al) | |||
| 115 | if (he == NULL) | 55 | if (he == NULL) |
| 116 | return -ENOMEM; | 56 | return -ENOMEM; |
| 117 | 57 | ||
| 118 | return annotate__hist_hit(he, al->addr); | 58 | return hist_entry__inc_addr_samples(he, al->addr); |
| 119 | } | 59 | } |
| 120 | 60 | ||
| 121 | static int process_sample_event(event_t *event, struct perf_session *session) | 61 | static int process_sample_event(event_t *event, struct perf_session *session) |
| @@ -140,101 +80,6 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 140 | return 0; | 80 | return 0; |
| 141 | } | 81 | } |
| 142 | 82 | ||
| 143 | struct objdump_line { | ||
| 144 | struct list_head node; | ||
| 145 | s64 offset; | ||
| 146 | char *line; | ||
| 147 | }; | ||
| 148 | |||
| 149 | static struct objdump_line *objdump_line__new(s64 offset, char *line) | ||
| 150 | { | ||
| 151 | struct objdump_line *self = malloc(sizeof(*self)); | ||
| 152 | |||
| 153 | if (self != NULL) { | ||
| 154 | self->offset = offset; | ||
| 155 | self->line = line; | ||
| 156 | } | ||
| 157 | |||
| 158 | return self; | ||
| 159 | } | ||
| 160 | |||
| 161 | static void objdump_line__free(struct objdump_line *self) | ||
| 162 | { | ||
| 163 | free(self->line); | ||
| 164 | free(self); | ||
| 165 | } | ||
| 166 | |||
| 167 | static void objdump__add_line(struct list_head *head, struct objdump_line *line) | ||
| 168 | { | ||
| 169 | list_add_tail(&line->node, head); | ||
| 170 | } | ||
| 171 | |||
| 172 | static struct objdump_line *objdump__get_next_ip_line(struct list_head *head, | ||
| 173 | struct objdump_line *pos) | ||
| 174 | { | ||
| 175 | list_for_each_entry_continue(pos, head, node) | ||
| 176 | if (pos->offset >= 0) | ||
| 177 | return pos; | ||
| 178 | |||
| 179 | return NULL; | ||
| 180 | } | ||
| 181 | |||
| 182 | static int parse_line(FILE *file, struct hist_entry *he, | ||
| 183 | struct list_head *head) | ||
| 184 | { | ||
| 185 | struct symbol *sym = he->ms.sym; | ||
| 186 | struct objdump_line *objdump_line; | ||
| 187 | char *line = NULL, *tmp, *tmp2; | ||
| 188 | size_t line_len; | ||
| 189 | s64 line_ip, offset = -1; | ||
| 190 | char *c; | ||
| 191 | |||
| 192 | if (getline(&line, &line_len, file) < 0) | ||
| 193 | return -1; | ||
| 194 | |||
| 195 | if (!line) | ||
| 196 | return -1; | ||
| 197 | |||
| 198 | c = strchr(line, '\n'); | ||
| 199 | if (c) | ||
| 200 | *c = 0; | ||
| 201 | |||
| 202 | line_ip = -1; | ||
| 203 | |||
| 204 | /* | ||
| 205 | * Strip leading spaces: | ||
| 206 | */ | ||
| 207 | tmp = line; | ||
| 208 | while (*tmp) { | ||
| 209 | if (*tmp != ' ') | ||
| 210 | break; | ||
| 211 | tmp++; | ||
| 212 | } | ||
| 213 | |||
| 214 | if (*tmp) { | ||
| 215 | /* | ||
| 216 | * Parse hexa addresses followed by ':' | ||
| 217 | */ | ||
| 218 | line_ip = strtoull(tmp, &tmp2, 16); | ||
| 219 | if (*tmp2 != ':') | ||
| 220 | line_ip = -1; | ||
| 221 | } | ||
| 222 | |||
| 223 | if (line_ip != -1) { | ||
| 224 | u64 start = map__rip_2objdump(he->ms.map, sym->start); | ||
| 225 | offset = line_ip - start; | ||
| 226 | } | ||
| 227 | |||
| 228 | objdump_line = objdump_line__new(offset, line); | ||
| 229 | if (objdump_line == NULL) { | ||
| 230 | free(line); | ||
| 231 | return -1; | ||
| 232 | } | ||
| 233 | objdump__add_line(head, objdump_line); | ||
| 234 | |||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | |||
| 238 | static int objdump_line__print(struct objdump_line *self, | 83 | static int objdump_line__print(struct objdump_line *self, |
| 239 | struct list_head *head, | 84 | struct list_head *head, |
| 240 | struct hist_entry *he, u64 len) | 85 | struct hist_entry *he, u64 len) |
| @@ -439,27 +284,11 @@ static void annotate_sym(struct hist_entry *he) | |||
| 439 | struct symbol *sym = he->ms.sym; | 284 | struct symbol *sym = he->ms.sym; |
| 440 | const char *filename = dso->long_name, *d_filename; | 285 | const char *filename = dso->long_name, *d_filename; |
| 441 | u64 len; | 286 | u64 len; |
| 442 | char command[PATH_MAX*2]; | ||
| 443 | FILE *file; | ||
| 444 | LIST_HEAD(head); | 287 | LIST_HEAD(head); |
| 445 | struct objdump_line *pos, *n; | 288 | struct objdump_line *pos, *n; |
| 446 | 289 | ||
| 447 | if (!filename) | 290 | if (hist_entry__annotate(he, &head) < 0) |
| 448 | return; | ||
| 449 | |||
| 450 | if (dso->origin == DSO__ORIG_KERNEL) { | ||
| 451 | if (dso->annotate_warned) | ||
| 452 | return; | ||
| 453 | dso->annotate_warned = 1; | ||
| 454 | pr_err("Can't annotate %s: No vmlinux file was found in the " | ||
| 455 | "path:\n", sym->name); | ||
| 456 | vmlinux_path__fprintf(stderr); | ||
| 457 | return; | 291 | return; |
| 458 | } | ||
| 459 | |||
| 460 | pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__, | ||
| 461 | filename, sym->name, map->unmap_ip(map, sym->start), | ||
| 462 | map->unmap_ip(map, sym->end)); | ||
| 463 | 292 | ||
| 464 | if (full_paths) | 293 | if (full_paths) |
| 465 | d_filename = filename; | 294 | d_filename = filename; |
| @@ -477,29 +306,6 @@ static void annotate_sym(struct hist_entry *he) | |||
| 477 | printf(" Percent | Source code & Disassembly of %s\n", d_filename); | 306 | printf(" Percent | Source code & Disassembly of %s\n", d_filename); |
| 478 | printf("------------------------------------------------\n"); | 307 | printf("------------------------------------------------\n"); |
| 479 | 308 | ||
| 480 | if (verbose >= 2) | ||
| 481 | printf("annotating [%p] %30s : [%p] %30s\n", | ||
| 482 | dso, dso->long_name, sym, sym->name); | ||
| 483 | |||
| 484 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", | ||
| 485 | map__rip_2objdump(map, sym->start), | ||
| 486 | map__rip_2objdump(map, sym->end), | ||
| 487 | filename, filename); | ||
| 488 | |||
| 489 | if (verbose >= 3) | ||
| 490 | printf("doing: %s\n", command); | ||
| 491 | |||
| 492 | file = popen(command, "r"); | ||
| 493 | if (!file) | ||
| 494 | return; | ||
| 495 | |||
| 496 | while (!feof(file)) { | ||
| 497 | if (parse_line(file, he, &head) < 0) | ||
| 498 | break; | ||
| 499 | } | ||
| 500 | |||
| 501 | pclose(file); | ||
| 502 | |||
| 503 | if (verbose) | 309 | if (verbose) |
| 504 | hist_entry__print_hits(he); | 310 | hist_entry__print_hits(he); |
| 505 | 311 | ||
