diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-02-04 06:45:46 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-02-05 09:28:21 -0500 |
commit | 78f7defedbb4da73b9a07635c357c1afcaa55c8f (patch) | |
tree | a4ddcb93682e17e986272b626ce94eb0ed35f8b7 /tools/perf/builtin-annotate.c | |
parent | 764328d3209dd81b02a55722556b07b6f35e3ca0 (diff) |
perf annotate: Move annotate functions to util/
They will be used by perf top, so that we have just one set of routines
to do annotation.
Rename "struct sym_priv" to "struct annotation", etc, to clarify this
code a bit.
Rename "struct sym_ext" to "struct source_line", to give it a meaningful
name, that clarifies that it is a the result of an addr2line call, that
is sorted by percentage one particular source code line appeared in the
annotation.
And since we're moving things around also rename 'sym_hist->ip' to
'sym_hist->addr' as we want to do data structure annotation at some
point.
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
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 | 255 |
1 files changed, 11 insertions, 244 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index cd9dec46c19f..9072ef44cfcb 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | #include "util/util.h" | 10 | #include "util/util.h" |
11 | 11 | ||
12 | #include "util/util.h" | ||
12 | #include "util/color.h" | 13 | #include "util/color.h" |
13 | #include <linux/list.h> | 14 | #include <linux/list.h> |
14 | #include "util/cache.h" | 15 | #include "util/cache.h" |
@@ -18,6 +19,7 @@ | |||
18 | #include "perf.h" | 19 | #include "perf.h" |
19 | #include "util/debug.h" | 20 | #include "util/debug.h" |
20 | 21 | ||
22 | #include "util/annotate.h" | ||
21 | #include "util/event.h" | 23 | #include "util/event.h" |
22 | #include "util/parse-options.h" | 24 | #include "util/parse-options.h" |
23 | #include "util/parse-events.h" | 25 | #include "util/parse-events.h" |
@@ -79,245 +81,10 @@ static int process_sample_event(union perf_event *event, | |||
79 | return 0; | 81 | return 0; |
80 | } | 82 | } |
81 | 83 | ||
82 | static int objdump_line__print(struct objdump_line *self, | ||
83 | struct list_head *head, | ||
84 | struct hist_entry *he, u64 len) | ||
85 | { | ||
86 | struct symbol *sym = he->ms.sym; | ||
87 | static const char *prev_line; | ||
88 | static const char *prev_color; | ||
89 | |||
90 | if (self->offset != -1) { | ||
91 | const char *path = NULL; | ||
92 | unsigned int hits = 0; | ||
93 | double percent = 0.0; | ||
94 | const char *color; | ||
95 | struct sym_priv *priv = symbol__priv(sym); | ||
96 | struct sym_ext *sym_ext = priv->ext; | ||
97 | struct sym_hist *h = priv->hist; | ||
98 | s64 offset = self->offset; | ||
99 | struct objdump_line *next = objdump__get_next_ip_line(head, self); | ||
100 | |||
101 | while (offset < (s64)len && | ||
102 | (next == NULL || offset < next->offset)) { | ||
103 | if (sym_ext) { | ||
104 | if (path == NULL) | ||
105 | path = sym_ext[offset].path; | ||
106 | percent += sym_ext[offset].percent; | ||
107 | } else | ||
108 | hits += h->ip[offset]; | ||
109 | |||
110 | ++offset; | ||
111 | } | ||
112 | |||
113 | if (sym_ext == NULL && h->sum) | ||
114 | percent = 100.0 * hits / h->sum; | ||
115 | |||
116 | color = get_percent_color(percent); | ||
117 | |||
118 | /* | ||
119 | * Also color the filename and line if needed, with | ||
120 | * the same color than the percentage. Don't print it | ||
121 | * twice for close colored ip with the same filename:line | ||
122 | */ | ||
123 | if (path) { | ||
124 | if (!prev_line || strcmp(prev_line, path) | ||
125 | || color != prev_color) { | ||
126 | color_fprintf(stdout, color, " %s", path); | ||
127 | prev_line = path; | ||
128 | prev_color = color; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | color_fprintf(stdout, color, " %7.2f", percent); | ||
133 | printf(" : "); | ||
134 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line); | ||
135 | } else { | ||
136 | if (!*self->line) | ||
137 | printf(" :\n"); | ||
138 | else | ||
139 | printf(" : %s\n", self->line); | ||
140 | } | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static struct rb_root root_sym_ext; | ||
146 | |||
147 | static void insert_source_line(struct sym_ext *sym_ext) | ||
148 | { | ||
149 | struct sym_ext *iter; | ||
150 | struct rb_node **p = &root_sym_ext.rb_node; | ||
151 | struct rb_node *parent = NULL; | ||
152 | |||
153 | while (*p != NULL) { | ||
154 | parent = *p; | ||
155 | iter = rb_entry(parent, struct sym_ext, node); | ||
156 | |||
157 | if (sym_ext->percent > iter->percent) | ||
158 | p = &(*p)->rb_left; | ||
159 | else | ||
160 | p = &(*p)->rb_right; | ||
161 | } | ||
162 | |||
163 | rb_link_node(&sym_ext->node, parent, p); | ||
164 | rb_insert_color(&sym_ext->node, &root_sym_ext); | ||
165 | } | ||
166 | |||
167 | static void free_source_line(struct hist_entry *he, int len) | ||
168 | { | ||
169 | struct sym_priv *priv = symbol__priv(he->ms.sym); | ||
170 | struct sym_ext *sym_ext = priv->ext; | ||
171 | int i; | ||
172 | |||
173 | if (!sym_ext) | ||
174 | return; | ||
175 | |||
176 | for (i = 0; i < len; i++) | ||
177 | free(sym_ext[i].path); | ||
178 | free(sym_ext); | ||
179 | |||
180 | priv->ext = NULL; | ||
181 | root_sym_ext = RB_ROOT; | ||
182 | } | ||
183 | |||
184 | /* Get the filename:line for the colored entries */ | ||
185 | static void | ||
186 | get_source_line(struct hist_entry *he, int len, const char *filename) | ||
187 | { | ||
188 | struct symbol *sym = he->ms.sym; | ||
189 | u64 start; | ||
190 | int i; | ||
191 | char cmd[PATH_MAX * 2]; | ||
192 | struct sym_ext *sym_ext; | ||
193 | struct sym_priv *priv = symbol__priv(sym); | ||
194 | struct sym_hist *h = priv->hist; | ||
195 | |||
196 | if (!h->sum) | ||
197 | return; | ||
198 | |||
199 | sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext)); | ||
200 | if (!priv->ext) | ||
201 | return; | ||
202 | |||
203 | start = he->ms.map->unmap_ip(he->ms.map, sym->start); | ||
204 | |||
205 | for (i = 0; i < len; i++) { | ||
206 | char *path = NULL; | ||
207 | size_t line_len; | ||
208 | u64 offset; | ||
209 | FILE *fp; | ||
210 | |||
211 | sym_ext[i].percent = 100.0 * h->ip[i] / h->sum; | ||
212 | if (sym_ext[i].percent <= 0.5) | ||
213 | continue; | ||
214 | |||
215 | offset = start + i; | ||
216 | sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); | ||
217 | fp = popen(cmd, "r"); | ||
218 | if (!fp) | ||
219 | continue; | ||
220 | |||
221 | if (getline(&path, &line_len, fp) < 0 || !line_len) | ||
222 | goto next; | ||
223 | |||
224 | sym_ext[i].path = malloc(sizeof(char) * line_len + 1); | ||
225 | if (!sym_ext[i].path) | ||
226 | goto next; | ||
227 | |||
228 | strcpy(sym_ext[i].path, path); | ||
229 | insert_source_line(&sym_ext[i]); | ||
230 | |||
231 | next: | ||
232 | pclose(fp); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | static void print_summary(const char *filename) | ||
237 | { | ||
238 | struct sym_ext *sym_ext; | ||
239 | struct rb_node *node; | ||
240 | |||
241 | printf("\nSorted summary for file %s\n", filename); | ||
242 | printf("----------------------------------------------\n\n"); | ||
243 | |||
244 | if (RB_EMPTY_ROOT(&root_sym_ext)) { | ||
245 | printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); | ||
246 | return; | ||
247 | } | ||
248 | |||
249 | node = rb_first(&root_sym_ext); | ||
250 | while (node) { | ||
251 | double percent; | ||
252 | const char *color; | ||
253 | char *path; | ||
254 | |||
255 | sym_ext = rb_entry(node, struct sym_ext, node); | ||
256 | percent = sym_ext->percent; | ||
257 | color = get_percent_color(percent); | ||
258 | path = sym_ext->path; | ||
259 | |||
260 | color_fprintf(stdout, color, " %7.2f %s", percent, path); | ||
261 | node = rb_next(node); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | static void hist_entry__print_hits(struct hist_entry *self) | ||
266 | { | ||
267 | struct symbol *sym = self->ms.sym; | ||
268 | struct sym_priv *priv = symbol__priv(sym); | ||
269 | struct sym_hist *h = priv->hist; | ||
270 | u64 len = sym->end - sym->start, offset; | ||
271 | |||
272 | for (offset = 0; offset < len; ++offset) | ||
273 | if (h->ip[offset] != 0) | ||
274 | printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2, | ||
275 | sym->start + offset, h->ip[offset]); | ||
276 | printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); | ||
277 | } | ||
278 | |||
279 | static int hist_entry__tty_annotate(struct hist_entry *he) | 84 | static int hist_entry__tty_annotate(struct hist_entry *he) |
280 | { | 85 | { |
281 | struct map *map = he->ms.map; | 86 | return symbol__tty_annotate(he->ms.sym, he->ms.map, |
282 | struct dso *dso = map->dso; | 87 | print_line, full_paths); |
283 | struct symbol *sym = he->ms.sym; | ||
284 | const char *filename = dso->long_name, *d_filename; | ||
285 | u64 len; | ||
286 | LIST_HEAD(head); | ||
287 | struct objdump_line *pos, *n; | ||
288 | |||
289 | if (hist_entry__annotate(he, &head, 0) < 0) | ||
290 | return -1; | ||
291 | |||
292 | if (full_paths) | ||
293 | d_filename = filename; | ||
294 | else | ||
295 | d_filename = basename(filename); | ||
296 | |||
297 | len = sym->end - sym->start; | ||
298 | |||
299 | if (print_line) { | ||
300 | get_source_line(he, len, filename); | ||
301 | print_summary(filename); | ||
302 | } | ||
303 | |||
304 | printf("\n\n------------------------------------------------\n"); | ||
305 | printf(" Percent | Source code & Disassembly of %s\n", d_filename); | ||
306 | printf("------------------------------------------------\n"); | ||
307 | |||
308 | if (verbose) | ||
309 | hist_entry__print_hits(he); | ||
310 | |||
311 | list_for_each_entry_safe(pos, n, &head, node) { | ||
312 | objdump_line__print(pos, &head, he, len); | ||
313 | list_del(&pos->node); | ||
314 | objdump_line__free(pos); | ||
315 | } | ||
316 | |||
317 | if (print_line) | ||
318 | free_source_line(he, len); | ||
319 | |||
320 | return 0; | ||
321 | } | 88 | } |
322 | 89 | ||
323 | static void hists__find_annotations(struct hists *self) | 90 | static void hists__find_annotations(struct hists *self) |
@@ -327,13 +94,13 @@ static void hists__find_annotations(struct hists *self) | |||
327 | 94 | ||
328 | while (nd) { | 95 | while (nd) { |
329 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); | 96 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); |
330 | struct sym_priv *priv; | 97 | struct annotation *notes; |
331 | 98 | ||
332 | if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) | 99 | if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) |
333 | goto find_next; | 100 | goto find_next; |
334 | 101 | ||
335 | priv = symbol__priv(he->ms.sym); | 102 | notes = symbol__annotation(he->ms.sym); |
336 | if (priv->hist == NULL) { | 103 | if (notes->histogram == NULL) { |
337 | find_next: | 104 | find_next: |
338 | if (key == KEY_LEFT) | 105 | if (key == KEY_LEFT) |
339 | nd = rb_prev(nd); | 106 | nd = rb_prev(nd); |
@@ -362,11 +129,11 @@ find_next: | |||
362 | nd = rb_next(nd); | 129 | nd = rb_next(nd); |
363 | /* | 130 | /* |
364 | * Since we have a hist_entry per IP for the same | 131 | * Since we have a hist_entry per IP for the same |
365 | * symbol, free he->ms.sym->hist to signal we already | 132 | * symbol, free he->ms.sym->histogram to signal we already |
366 | * processed this symbol. | 133 | * processed this symbol. |
367 | */ | 134 | */ |
368 | free(priv->hist); | 135 | free(notes->histogram); |
369 | priv->hist = NULL; | 136 | notes->histogram = NULL; |
370 | } | 137 | } |
371 | } | 138 | } |
372 | } | 139 | } |
@@ -454,7 +221,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) | |||
454 | 221 | ||
455 | setup_browser(true); | 222 | setup_browser(true); |
456 | 223 | ||
457 | symbol_conf.priv_size = sizeof(struct sym_priv); | 224 | symbol_conf.priv_size = sizeof(struct annotation); |
458 | symbol_conf.try_vmlinux_path = true; | 225 | symbol_conf.try_vmlinux_path = true; |
459 | 226 | ||
460 | if (symbol__init() < 0) | 227 | if (symbol__init() < 0) |