aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-annotate.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-02-04 06:45:46 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-02-05 09:28:21 -0500
commit78f7defedbb4da73b9a07635c357c1afcaa55c8f (patch)
treea4ddcb93682e17e986272b626ce94eb0ed35f8b7 /tools/perf/builtin-annotate.c
parent764328d3209dd81b02a55722556b07b6f35e3ca0 (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.c255
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
82static 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
145static struct rb_root root_sym_ext;
146
147static 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
167static 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 */
185static void
186get_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
236static 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
265static 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
279static int hist_entry__tty_annotate(struct hist_entry *he) 84static 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
323static void hists__find_annotations(struct hists *self) 90static 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) {
337find_next: 104find_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)