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 | ||