diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-05-11 22:18:06 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-05-11 22:23:20 -0400 |
commit | ef7b93a11904c6ba10604233d318d9e8ec88cddc (patch) | |
tree | 7ae6fa9cbe19be8fbbc18c8fdeb7edfdb7bdab60 /tools/perf/builtin-annotate.c | |
parent | 3798ed7bc7ade26d3f59506cd06288615dfc7585 (diff) |
perf report: Librarize the annotation code and use it in the newt browser
Now we don't anymore use popen to run 'perf annotate' for the selected
symbol, instead we collect per address samplings when processing samples
in 'perf report' if we're using the newt browser, then we use this data
directly to do annotation.
Done this way we can actually traverse the objdump_line objects
directly, matching the addresses to the collected samples and colouring
them appropriately using lower level slang routines.
The new ui_browser class will be reused for the main, callchain aware,
histogram browser, when it will be made generic and don't assume that
the objects are always instances of the objdump_line class maintained
using list_heads.
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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 | ||