blob: 7f85c6e159a46ee3778b682947ca409491fa4fd4 [file] [log] [blame]
Ingo Molnar8035e422009-06-06 15:19:13 +02001/*
2 * builtin-annotate.c
3 *
4 * Builtin annotate command: Analyze the perf.data input file,
5 * look up and read DSOs and symbol information and display
6 * a histogram of results, along various sorting keys.
7 */
8#include "builtin.h"
9
10#include "util/util.h"
11
12#include "util/color.h"
Arnaldo Carvalho de Melo5da50252009-07-01 14:46:08 -030013#include <linux/list.h>
Ingo Molnar8035e422009-06-06 15:19:13 +020014#include "util/cache.h"
Arnaldo Carvalho de Melo43cbcd82009-07-01 12:28:37 -030015#include <linux/rbtree.h>
Ingo Molnar8035e422009-06-06 15:19:13 +020016#include "util/symbol.h"
17#include "util/string.h"
18
19#include "perf.h"
Frederic Weisbecker8f288272009-08-16 22:05:48 +020020#include "util/debug.h"
Ingo Molnar8035e422009-06-06 15:19:13 +020021
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -020022#include "util/event.h"
Ingo Molnar8035e422009-06-06 15:19:13 +020023#include "util/parse-options.h"
24#include "util/parse-events.h"
Frederic Weisbecker6baa0a52009-08-14 12:21:53 +020025#include "util/thread.h"
John Kacurdd68ada2009-09-24 18:02:49 +020026#include "util/sort.h"
John Kacur3d1d07e2009-09-28 15:32:55 +020027#include "util/hist.h"
Ingo Molnar8035e422009-06-06 15:19:13 +020028
Ingo Molnar8035e422009-06-06 15:19:13 +020029static char const *input_name = "perf.data";
Ingo Molnar8035e422009-06-06 15:19:13 +020030
Peter Zijlstrafa6963b2009-08-19 11:18:26 +020031static int force;
Ingo Molnar8035e422009-06-06 15:19:13 +020032static int input;
Ingo Molnar8035e422009-06-06 15:19:13 +020033
Mike Galbraith42976482009-07-02 08:09:46 +020034static int full_paths;
35
Frederic Weisbecker301406b2009-06-13 00:11:21 +020036static int print_line;
37
Ingo Molnar8035e422009-06-06 15:19:13 +020038static unsigned long page_size;
39static unsigned long mmap_window = 32;
40
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -020041struct sym_hist {
42 u64 sum;
43 u64 ip[0];
44};
45
Frederic Weisbecker301406b2009-06-13 00:11:21 +020046struct sym_ext {
Frederic Weisbecker971738f2009-06-13 00:11:22 +020047 struct rb_node node;
Frederic Weisbecker301406b2009-06-13 00:11:21 +020048 double percent;
49 char *path;
50};
51
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -020052struct sym_priv {
53 struct sym_hist *hist;
54 struct sym_ext *ext;
55};
56
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -020057static struct symbol_conf symbol_conf = {
58 .priv_size = sizeof(struct sym_priv),
59 .try_vmlinux_path = true,
60};
61
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -020062static const char *sym_hist_filter;
63
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020064static int symbol_filter(struct map *map __used, struct symbol *sym)
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -020065{
Arnaldo Carvalho de Melo8f0b0372009-10-20 15:08:29 -020066 if (sym_hist_filter == NULL ||
67 strcmp(sym->name, sym_hist_filter) == 0) {
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020068 struct sym_priv *priv = symbol__priv(sym);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -020069 const int size = (sizeof(*priv->hist) +
70 (sym->end - sym->start) * sizeof(u64));
71
72 priv->hist = malloc(size);
73 if (priv->hist)
74 memset(priv->hist, 0, size);
75 return 0;
76 }
77 /*
78 * FIXME: We should really filter it out, as we don't want to go thru symbols
79 * we're not interested, and if a DSO ends up with no symbols, delete it too,
80 * but right now the kernel loading routines in symbol.c bail out if no symbols
81 * are found, fix it later.
82 */
83 return 0;
84}
Ingo Molnar8035e422009-06-06 15:19:13 +020085
Ingo Molnar8035e422009-06-06 15:19:13 +020086/*
87 * collect histogram counts
88 */
Paul Mackerras9cffa8d2009-06-19 22:21:42 +100089static void hist_hit(struct hist_entry *he, u64 ip)
Ingo Molnar0b73da32009-06-06 15:48:52 +020090{
91 unsigned int sym_size, offset;
92 struct symbol *sym = he->sym;
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -020093 struct sym_priv *priv;
94 struct sym_hist *h;
Ingo Molnar0b73da32009-06-06 15:48:52 +020095
96 he->count++;
97
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -020098 if (!sym || !he->map)
99 return;
100
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200101 priv = symbol__priv(sym);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200102 if (!priv->hist)
Ingo Molnar0b73da32009-06-06 15:48:52 +0200103 return;
104
105 sym_size = sym->end - sym->start;
106 offset = ip - sym->start;
107
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200108 if (verbose)
109 fprintf(stderr, "%s: ip=%Lx\n", __func__,
110 he->map->unmap_ip(he->map, ip));
111
Ingo Molnar0b73da32009-06-06 15:48:52 +0200112 if (offset >= sym_size)
113 return;
114
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200115 h = priv->hist;
116 h->sum++;
117 h->ip[offset]++;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200118
119 if (verbose >= 3)
120 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
Arjan van de Ven7d37a0c2009-06-06 20:36:38 +0200121 (void *)(unsigned long)he->sym->start,
Ingo Molnar0b73da32009-06-06 15:48:52 +0200122 he->sym->name,
Arjan van de Ven7d37a0c2009-06-06 20:36:38 +0200123 (void *)(unsigned long)ip, ip - he->sym->start,
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200124 h->ip[offset]);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200125}
Ingo Molnar8035e422009-06-06 15:19:13 +0200126
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200127static int hist_entry__add(struct addr_location *al, u64 count)
Ingo Molnar8035e422009-06-06 15:19:13 +0200128{
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300129 bool hit;
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200130 struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300131 if (he == NULL)
Ingo Molnar8035e422009-06-06 15:19:13 +0200132 return -ENOMEM;
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200133 hist_hit(he, al->addr);
Ingo Molnar8035e422009-06-06 15:19:13 +0200134 return 0;
135}
136
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200137static int process_sample_event(event_t *event)
Ingo Molnar8035e422009-06-06 15:19:13 +0200138{
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200139 struct addr_location al;
Frederic Weisbecker6baa0a52009-08-14 12:21:53 +0200140
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200141 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200142 event->ip.pid, (void *)(long)event->ip.ip);
Ingo Molnar8035e422009-06-06 15:19:13 +0200143
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200144 if (event__preprocess_sample(event, &al, symbol_filter) < 0) {
Ingo Molnar8035e422009-06-06 15:19:13 +0200145 fprintf(stderr, "problem processing %d event, skipping it.\n",
146 event->header.type);
147 return -1;
148 }
149
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200150 if (hist_entry__add(&al, 1)) {
Arnaldo Carvalho de Meloec218fc2009-10-03 20:30:48 -0300151 fprintf(stderr, "problem incrementing symbol count, "
152 "skipping event\n");
153 return -1;
Ingo Molnar8035e422009-06-06 15:19:13 +0200154 }
Ingo Molnar8035e422009-06-06 15:19:13 +0200155
156 return 0;
157}
158
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200159static int event__process(event_t *self)
Ingo Molnar8035e422009-06-06 15:19:13 +0200160{
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200161 switch (self->header.type) {
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200162 case PERF_RECORD_SAMPLE:
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200163 return process_sample_event(self);
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +0200164
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200165 case PERF_RECORD_MMAP:
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200166 return event__process_mmap(self);
Ingo Molnar8035e422009-06-06 15:19:13 +0200167
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200168 case PERF_RECORD_COMM:
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200169 return event__process_comm(self);
Ingo Molnar8035e422009-06-06 15:19:13 +0200170
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200171 case PERF_RECORD_FORK:
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200172 return event__process_task(self);
Ingo Molnar8035e422009-06-06 15:19:13 +0200173 /*
174 * We dont process them right now but they are fine:
175 */
176
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200177 case PERF_RECORD_THROTTLE:
178 case PERF_RECORD_UNTHROTTLE:
Ingo Molnar8035e422009-06-06 15:19:13 +0200179 return 0;
180
181 default:
182 return -1;
183 }
184
185 return 0;
186}
187
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200188static int parse_line(FILE *file, struct hist_entry *he, u64 len)
Ingo Molnar0b73da32009-06-06 15:48:52 +0200189{
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200190 struct symbol *sym = he->sym;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200191 char *line = NULL, *tmp, *tmp2;
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200192 static const char *prev_line;
193 static const char *prev_color;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200194 unsigned int offset;
195 size_t line_len;
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200196 u64 start;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200197 s64 line_ip;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200198 int ret;
199 char *c;
200
201 if (getline(&line, &line_len, file) < 0)
202 return -1;
203 if (!line)
204 return -1;
205
206 c = strchr(line, '\n');
207 if (c)
208 *c = 0;
209
210 line_ip = -1;
211 offset = 0;
212 ret = -2;
213
214 /*
215 * Strip leading spaces:
216 */
217 tmp = line;
218 while (*tmp) {
219 if (*tmp != ' ')
220 break;
221 tmp++;
222 }
223
224 if (*tmp) {
225 /*
226 * Parse hexa addresses followed by ':'
227 */
228 line_ip = strtoull(tmp, &tmp2, 16);
229 if (*tmp2 != ':')
230 line_ip = -1;
231 }
232
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200233 start = he->map->unmap_ip(he->map, sym->start);
234
Ingo Molnar0b73da32009-06-06 15:48:52 +0200235 if (line_ip != -1) {
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200236 const char *path = NULL;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200237 unsigned int hits = 0;
238 double percent = 0.0;
Ingo Molnar83a09442009-08-15 12:26:57 +0200239 const char *color;
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200240 struct sym_priv *priv = symbol__priv(sym);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200241 struct sym_ext *sym_ext = priv->ext;
242 struct sym_hist *h = priv->hist;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200243
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200244 offset = line_ip - start;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200245 if (offset < len)
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200246 hits = h->ip[offset];
Ingo Molnar0b73da32009-06-06 15:48:52 +0200247
Frederic Weisbeckerc17c2db2009-06-13 17:39:23 +0200248 if (offset < len && sym_ext) {
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200249 path = sym_ext[offset].path;
250 percent = sym_ext[offset].percent;
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200251 } else if (h->sum)
252 percent = 100.0 * hits / h->sum;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200253
Frederic Weisbecker1e11fd82009-07-02 20:14:34 +0200254 color = get_percent_color(percent);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200255
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200256 /*
257 * Also color the filename and line if needed, with
258 * the same color than the percentage. Don't print it
259 * twice for close colored ip with the same filename:line
260 */
261 if (path) {
262 if (!prev_line || strcmp(prev_line, path)
263 || color != prev_color) {
264 color_fprintf(stdout, color, " %s", path);
265 prev_line = path;
266 prev_color = color;
267 }
268 }
269
Ingo Molnar0b73da32009-06-06 15:48:52 +0200270 color_fprintf(stdout, color, " %7.2f", percent);
271 printf(" : ");
272 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line);
273 } else {
274 if (!*line)
275 printf(" :\n");
276 else
277 printf(" : %s\n", line);
278 }
279
280 return 0;
281}
282
Frederic Weisbecker971738f2009-06-13 00:11:22 +0200283static struct rb_root root_sym_ext;
284
285static void insert_source_line(struct sym_ext *sym_ext)
286{
287 struct sym_ext *iter;
288 struct rb_node **p = &root_sym_ext.rb_node;
289 struct rb_node *parent = NULL;
290
291 while (*p != NULL) {
292 parent = *p;
293 iter = rb_entry(parent, struct sym_ext, node);
294
295 if (sym_ext->percent > iter->percent)
296 p = &(*p)->rb_left;
297 else
298 p = &(*p)->rb_right;
299 }
300
301 rb_link_node(&sym_ext->node, parent, p);
302 rb_insert_color(&sym_ext->node, &root_sym_ext);
303}
304
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200305static void free_source_line(struct hist_entry *he, int len)
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200306{
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200307 struct sym_priv *priv = symbol__priv(he->sym);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200308 struct sym_ext *sym_ext = priv->ext;
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200309 int i;
310
311 if (!sym_ext)
312 return;
313
314 for (i = 0; i < len; i++)
315 free(sym_ext[i].path);
316 free(sym_ext);
317
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200318 priv->ext = NULL;
Frederic Weisbecker971738f2009-06-13 00:11:22 +0200319 root_sym_ext = RB_ROOT;
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200320}
321
322/* Get the filename:line for the colored entries */
Frederic Weisbeckerc17c2db2009-06-13 17:39:23 +0200323static void
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200324get_source_line(struct hist_entry *he, int len, const char *filename)
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200325{
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200326 struct symbol *sym = he->sym;
327 u64 start;
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200328 int i;
329 char cmd[PATH_MAX * 2];
330 struct sym_ext *sym_ext;
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200331 struct sym_priv *priv = symbol__priv(sym);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200332 struct sym_hist *h = priv->hist;
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200333
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200334 if (!h->sum)
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200335 return;
336
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200337 sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
338 if (!priv->ext)
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200339 return;
340
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200341 start = he->map->unmap_ip(he->map, sym->start);
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200342
343 for (i = 0; i < len; i++) {
344 char *path = NULL;
345 size_t line_len;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000346 u64 offset;
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200347 FILE *fp;
348
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200349 sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200350 if (sym_ext[i].percent <= 0.5)
351 continue;
352
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200353 offset = start + i;
Frederic Weisbeckerc17c2db2009-06-13 17:39:23 +0200354 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200355 fp = popen(cmd, "r");
356 if (!fp)
357 continue;
358
359 if (getline(&path, &line_len, fp) < 0 || !line_len)
360 goto next;
361
Frederic Weisbeckerc17c2db2009-06-13 17:39:23 +0200362 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200363 if (!sym_ext[i].path)
364 goto next;
365
366 strcpy(sym_ext[i].path, path);
Frederic Weisbecker971738f2009-06-13 00:11:22 +0200367 insert_source_line(&sym_ext[i]);
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200368
369 next:
370 pclose(fp);
371 }
372}
373
Ingo Molnar83a09442009-08-15 12:26:57 +0200374static void print_summary(const char *filename)
Frederic Weisbecker971738f2009-06-13 00:11:22 +0200375{
376 struct sym_ext *sym_ext;
377 struct rb_node *node;
378
379 printf("\nSorted summary for file %s\n", filename);
380 printf("----------------------------------------------\n\n");
381
382 if (RB_EMPTY_ROOT(&root_sym_ext)) {
383 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
384 return;
385 }
386
387 node = rb_first(&root_sym_ext);
388 while (node) {
389 double percent;
Ingo Molnar83a09442009-08-15 12:26:57 +0200390 const char *color;
Frederic Weisbecker971738f2009-06-13 00:11:22 +0200391 char *path;
392
393 sym_ext = rb_entry(node, struct sym_ext, node);
394 percent = sym_ext->percent;
Frederic Weisbecker1e11fd82009-07-02 20:14:34 +0200395 color = get_percent_color(percent);
Frederic Weisbecker971738f2009-06-13 00:11:22 +0200396 path = sym_ext->path;
397
398 color_fprintf(stdout, color, " %7.2f %s", percent, path);
399 node = rb_next(node);
400 }
401}
402
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200403static void annotate_sym(struct hist_entry *he)
Ingo Molnar0b73da32009-06-06 15:48:52 +0200404{
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200405 struct map *map = he->map;
406 struct dso *dso = map->dso;
407 struct symbol *sym = he->sym;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300408 const char *filename = dso->long_name, *d_filename;
409 u64 len;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200410 char command[PATH_MAX*2];
411 FILE *file;
412
413 if (!filename)
414 return;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200415
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200416 if (verbose)
417 fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n",
418 __func__, filename, sym->name,
419 map->unmap_ip(map, sym->start),
420 map->unmap_ip(map, sym->end));
421
Mike Galbraith42976482009-07-02 08:09:46 +0200422 if (full_paths)
423 d_filename = filename;
424 else
425 d_filename = basename(filename);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200426
Ingo Molnar0b73da32009-06-06 15:48:52 +0200427 len = sym->end - sym->start;
428
Frederic Weisbecker971738f2009-06-13 00:11:22 +0200429 if (print_line) {
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200430 get_source_line(he, len, filename);
Frederic Weisbecker971738f2009-06-13 00:11:22 +0200431 print_summary(filename);
432 }
433
434 printf("\n\n------------------------------------------------\n");
Mike Galbraith42976482009-07-02 08:09:46 +0200435 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
Frederic Weisbecker971738f2009-06-13 00:11:22 +0200436 printf("------------------------------------------------\n");
437
438 if (verbose >= 2)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300439 printf("annotating [%p] %30s : [%p] %30s\n",
440 dso, dso->long_name, sym, sym->name);
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200441
Mike Galbraith42976482009-07-02 08:09:46 +0200442 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200443 map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end),
444 filename, filename);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200445
446 if (verbose >= 3)
447 printf("doing: %s\n", command);
448
449 file = popen(command, "r");
450 if (!file)
451 return;
452
453 while (!feof(file)) {
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200454 if (parse_line(file, he, len) < 0)
Ingo Molnar0b73da32009-06-06 15:48:52 +0200455 break;
456 }
457
458 pclose(file);
Frederic Weisbecker971738f2009-06-13 00:11:22 +0200459 if (print_line)
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200460 free_source_line(he, len);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200461}
462
463static void find_annotations(void)
464{
465 struct rb_node *nd;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200466
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200467 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
468 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200469 struct sym_priv *priv;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200470
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200471 if (he->sym == NULL)
472 continue;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200473
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200474 priv = symbol__priv(he->sym);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200475 if (priv->hist == NULL)
476 continue;
477
478 annotate_sym(he);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200479 /*
480 * Since we have a hist_entry per IP for the same symbol, free
481 * he->sym->hist to signal we already processed this symbol.
482 */
483 free(priv->hist);
484 priv->hist = NULL;
Ingo Molnar0b73da32009-06-06 15:48:52 +0200485 }
Ingo Molnar0b73da32009-06-06 15:48:52 +0200486}
487
Ingo Molnar8035e422009-06-06 15:19:13 +0200488static int __cmd_annotate(void)
489{
490 int ret, rc = EXIT_FAILURE;
491 unsigned long offset = 0;
492 unsigned long head = 0;
Ingo Molnar83a09442009-08-15 12:26:57 +0200493 struct stat input_stat;
Ingo Molnar8035e422009-06-06 15:19:13 +0200494 event_t *event;
495 uint32_t size;
496 char *buf;
497
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300498 register_idle_thread();
Ingo Molnar8035e422009-06-06 15:19:13 +0200499
500 input = open(input_name, O_RDONLY);
501 if (input < 0) {
502 perror("failed to open file");
503 exit(-1);
504 }
505
Ingo Molnar83a09442009-08-15 12:26:57 +0200506 ret = fstat(input, &input_stat);
Ingo Molnar8035e422009-06-06 15:19:13 +0200507 if (ret < 0) {
508 perror("failed to stat file");
509 exit(-1);
510 }
511
Pierre Habouzit119e7a22009-08-27 09:59:02 +0200512 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
513 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
Peter Zijlstrafa6963b2009-08-19 11:18:26 +0200514 exit(-1);
515 }
516
Ingo Molnar83a09442009-08-15 12:26:57 +0200517 if (!input_stat.st_size) {
Ingo Molnar8035e422009-06-06 15:19:13 +0200518 fprintf(stderr, "zero-sized file, nothing to do!\n");
519 exit(0);
520 }
521
Ingo Molnar8035e422009-06-06 15:19:13 +0200522remap:
523 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
524 MAP_SHARED, input, offset);
525 if (buf == MAP_FAILED) {
526 perror("failed to mmap file");
527 exit(-1);
528 }
529
530more:
531 event = (event_t *)(buf + head);
532
533 size = event->header.size;
534 if (!size)
535 size = 8;
536
537 if (head + event->header.size >= page_size * mmap_window) {
538 unsigned long shift = page_size * (head / page_size);
Ingo Molnar83a09442009-08-15 12:26:57 +0200539 int munmap_ret;
Ingo Molnar8035e422009-06-06 15:19:13 +0200540
Ingo Molnar83a09442009-08-15 12:26:57 +0200541 munmap_ret = munmap(buf, page_size * mmap_window);
542 assert(munmap_ret == 0);
Ingo Molnar8035e422009-06-06 15:19:13 +0200543
544 offset += shift;
545 head -= shift;
546 goto remap;
547 }
548
549 size = event->header.size;
550
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200551 dump_printf("%p [%p]: event: %d\n",
Ingo Molnar8035e422009-06-06 15:19:13 +0200552 (void *)(offset + head),
553 (void *)(long)event->header.size,
554 event->header.type);
555
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200556 if (!size || event__process(event) < 0) {
Ingo Molnar8035e422009-06-06 15:19:13 +0200557
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200558 dump_printf("%p [%p]: skipping unknown header type: %d\n",
Ingo Molnar8035e422009-06-06 15:19:13 +0200559 (void *)(offset + head),
560 (void *)(long)(event->header.size),
561 event->header.type);
Ingo Molnar8035e422009-06-06 15:19:13 +0200562 /*
563 * assume we lost track of the stream, check alignment, and
564 * increment a single u64 in the hope to catch on again 'soon'.
565 */
566
567 if (unlikely(head & 7))
568 head &= ~7ULL;
569
570 size = 8;
571 }
572
573 head += size;
574
Ingo Molnar83a09442009-08-15 12:26:57 +0200575 if (offset + head < (unsigned long)input_stat.st_size)
Ingo Molnar8035e422009-06-06 15:19:13 +0200576 goto more;
577
578 rc = EXIT_SUCCESS;
579 close(input);
580
Ingo Molnar8035e422009-06-06 15:19:13 +0200581
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200582 if (dump_trace) {
583 event__print_totals();
Ingo Molnar8035e422009-06-06 15:19:13 +0200584 return 0;
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200585 }
Ingo Molnar8035e422009-06-06 15:19:13 +0200586
Arnaldo Carvalho de Meloda21d1b2009-10-07 10:49:00 -0300587 if (verbose > 3)
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300588 threads__fprintf(stdout);
Ingo Molnar8035e422009-06-06 15:19:13 +0200589
Arnaldo Carvalho de Meloda21d1b2009-10-07 10:49:00 -0300590 if (verbose > 2)
Ingo Molnar8035e422009-06-06 15:19:13 +0200591 dsos__fprintf(stdout);
592
593 collapse__resort();
Arnaldo Carvalho de Melo62daacb2009-11-27 16:29:22 -0200594 output__resort(event__total[0]);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200595
596 find_annotations();
Ingo Molnar8035e422009-06-06 15:19:13 +0200597
598 return rc;
599}
600
601static const char * const annotate_usage[] = {
602 "perf annotate [<options>] <command>",
603 NULL
604};
605
606static const struct option options[] = {
607 OPT_STRING('i', "input", &input_name, "file",
608 "input file name"),
Ingo Molnar23b87112009-06-06 21:25:29 +0200609 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
Ingo Molnar0b73da32009-06-06 15:48:52 +0200610 "symbol to annotate"),
Peter Zijlstrafa6963b2009-08-19 11:18:26 +0200611 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
Ingo Molnar8035e422009-06-06 15:19:13 +0200612 OPT_BOOLEAN('v', "verbose", &verbose,
613 "be more verbose (show symbol address, etc)"),
614 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
615 "dump raw trace in ASCII"),
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -0200616 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
617 "file", "vmlinux pathname"),
618 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
Mike Galbraith42976482009-07-02 08:09:46 +0200619 "load module symbols - WARNING: use only with -k and LIVE kernel"),
Frederic Weisbecker301406b2009-06-13 00:11:21 +0200620 OPT_BOOLEAN('l', "print-line", &print_line,
621 "print matching source lines (may be slow)"),
Mike Galbraith42976482009-07-02 08:09:46 +0200622 OPT_BOOLEAN('P', "full-paths", &full_paths,
623 "Don't shorten the displayed pathnames"),
Ingo Molnar8035e422009-06-06 15:19:13 +0200624 OPT_END()
625};
626
627static void setup_sorting(void)
628{
629 char *tmp, *tok, *str = strdup(sort_order);
630
631 for (tok = strtok_r(str, ", ", &tmp);
632 tok; tok = strtok_r(NULL, ", ", &tmp)) {
633 if (sort_dimension__add(tok) < 0) {
634 error("Unknown --sort key: `%s'", tok);
635 usage_with_options(annotate_usage, options);
636 }
637 }
638
639 free(str);
640}
641
Ingo Molnarf37a2912009-07-01 12:37:06 +0200642int cmd_annotate(int argc, const char **argv, const char *prefix __used)
Ingo Molnar8035e422009-06-06 15:19:13 +0200643{
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -0200644 if (symbol__init(&symbol_conf) < 0)
645 return -1;
Ingo Molnar8035e422009-06-06 15:19:13 +0200646
647 page_size = getpagesize();
648
649 argc = parse_options(argc, argv, options, annotate_usage, 0);
650
651 setup_sorting();
652
Ingo Molnar0b73da32009-06-06 15:48:52 +0200653 if (argc) {
654 /*
655 * Special case: if there's an argument left then assume tha
656 * it's a symbol filter:
657 */
658 if (argc > 1)
659 usage_with_options(annotate_usage, options);
660
661 sym_hist_filter = argv[0];
662 }
663
Ingo Molnar8035e422009-06-06 15:19:13 +0200664 setup_pager();
665
John Kacurdd68ada2009-09-24 18:02:49 +0200666 if (field_sep && *field_sep == '.') {
667 fputs("'.' is the only non valid --field-separator argument\n",
668 stderr);
669 exit(129);
670 }
671
Ingo Molnar8035e422009-06-06 15:19:13 +0200672 return __cmd_annotate();
673}