aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-annotate.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-annotate.c')
-rw-r--r--tools/perf/builtin-annotate.c240
1 files changed, 161 insertions, 79 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 593ff25006de..5ec5de995872 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -53,32 +53,20 @@ struct sym_priv {
53 53
54static const char *sym_hist_filter; 54static const char *sym_hist_filter;
55 55
56static int symbol_filter(struct map *map __used, struct symbol *sym) 56static int sym__alloc_hist(struct symbol *self)
57{ 57{
58 if (sym_hist_filter == NULL || 58 struct sym_priv *priv = symbol__priv(self);
59 strcmp(sym->name, sym_hist_filter) == 0) { 59 const int size = (sizeof(*priv->hist) +
60 struct sym_priv *priv = symbol__priv(sym); 60 (self->end - self->start) * sizeof(u64));
61 const int size = (sizeof(*priv->hist) +
62 (sym->end - sym->start) * sizeof(u64));
63 61
64 priv->hist = malloc(size); 62 priv->hist = zalloc(size);
65 if (priv->hist) 63 return priv->hist == NULL ? -1 : 0;
66 memset(priv->hist, 0, size);
67 return 0;
68 }
69 /*
70 * FIXME: We should really filter it out, as we don't want to go thru symbols
71 * we're not interested, and if a DSO ends up with no symbols, delete it too,
72 * but right now the kernel loading routines in symbol.c bail out if no symbols
73 * are found, fix it later.
74 */
75 return 0;
76} 64}
77 65
78/* 66/*
79 * collect histogram counts 67 * collect histogram counts
80 */ 68 */
81static void hist_hit(struct hist_entry *he, u64 ip) 69static int annotate__hist_hit(struct hist_entry *he, u64 ip)
82{ 70{
83 unsigned int sym_size, offset; 71 unsigned int sym_size, offset;
84 struct symbol *sym = he->sym; 72 struct symbol *sym = he->sym;
@@ -88,83 +76,127 @@ static void hist_hit(struct hist_entry *he, u64 ip)
88 he->count++; 76 he->count++;
89 77
90 if (!sym || !he->map) 78 if (!sym || !he->map)
91 return; 79 return 0;
92 80
93 priv = symbol__priv(sym); 81 priv = symbol__priv(sym);
94 if (!priv->hist) 82 if (priv->hist == NULL && sym__alloc_hist(sym) < 0)
95 return; 83 return -ENOMEM;
96 84
97 sym_size = sym->end - sym->start; 85 sym_size = sym->end - sym->start;
98 offset = ip - sym->start; 86 offset = ip - sym->start;
99 87
100 if (verbose) 88 pr_debug3("%s: ip=%#Lx\n", __func__, he->map->unmap_ip(he->map, ip));
101 fprintf(stderr, "%s: ip=%Lx\n", __func__,
102 he->map->unmap_ip(he->map, ip));
103 89
104 if (offset >= sym_size) 90 if (offset >= sym_size)
105 return; 91 return 0;
106 92
107 h = priv->hist; 93 h = priv->hist;
108 h->sum++; 94 h->sum++;
109 h->ip[offset]++; 95 h->ip[offset]++;
110 96
111 if (verbose >= 3) 97 pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", he->sym->start,
112 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", 98 he->sym->name, ip, ip - he->sym->start, h->ip[offset]);
113 (void *)(unsigned long)he->sym->start, 99 return 0;
114 he->sym->name,
115 (void *)(unsigned long)ip, ip - he->sym->start,
116 h->ip[offset]);
117} 100}
118 101
119static int perf_session__add_hist_entry(struct perf_session *self, 102static int perf_session__add_hist_entry(struct perf_session *self,
120 struct addr_location *al, u64 count) 103 struct addr_location *al, u64 count)
121{ 104{
122 bool hit; 105 bool hit;
123 struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL, 106 struct hist_entry *he;
124 count, &hit); 107
108 if (sym_hist_filter != NULL &&
109 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
110 /* We're only interested in a symbol named sym_hist_filter */
111 if (al->sym != NULL) {
112 rb_erase(&al->sym->rb_node,
113 &al->map->dso->symbols[al->map->type]);
114 symbol__delete(al->sym);
115 }
116 return 0;
117 }
118
119 he = __perf_session__add_hist_entry(self, al, NULL, count, &hit);
125 if (he == NULL) 120 if (he == NULL)
126 return -ENOMEM; 121 return -ENOMEM;
127 hist_hit(he, al->addr); 122
128 return 0; 123 return annotate__hist_hit(he, al->addr);
129} 124}
130 125
131static int process_sample_event(event_t *event, struct perf_session *session) 126static int process_sample_event(event_t *event, struct perf_session *session)
132{ 127{
133 struct addr_location al; 128 struct addr_location al;
134 129
135 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 130 dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
136 event->ip.pid, (void *)(long)event->ip.ip); 131 event->ip.pid, event->ip.ip);
137 132
138 if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) { 133 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
139 fprintf(stderr, "problem processing %d event, skipping it.\n", 134 pr_warning("problem processing %d event, skipping it.\n",
140 event->header.type); 135 event->header.type);
141 return -1; 136 return -1;
142 } 137 }
143 138
144 if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) { 139 if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) {
145 fprintf(stderr, "problem incrementing symbol count, " 140 pr_warning("problem incrementing symbol count, "
146 "skipping event\n"); 141 "skipping event\n");
147 return -1; 142 return -1;
148 } 143 }
149 144
150 return 0; 145 return 0;
151} 146}
152 147
153static int parse_line(FILE *file, struct hist_entry *he, u64 len) 148struct objdump_line {
149 struct list_head node;
150 s64 offset;
151 char *line;
152};
153
154static struct objdump_line *objdump_line__new(s64 offset, char *line)
155{
156 struct objdump_line *self = malloc(sizeof(*self));
157
158 if (self != NULL) {
159 self->offset = offset;
160 self->line = line;
161 }
162
163 return self;
164}
165
166static void objdump_line__free(struct objdump_line *self)
167{
168 free(self->line);
169 free(self);
170}
171
172static void objdump__add_line(struct list_head *head, struct objdump_line *line)
173{
174 list_add_tail(&line->node, head);
175}
176
177static struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
178 struct objdump_line *pos)
179{
180 list_for_each_entry_continue(pos, head, node)
181 if (pos->offset >= 0)
182 return pos;
183
184 return NULL;
185}
186
187static int parse_line(FILE *file, struct hist_entry *he,
188 struct list_head *head)
154{ 189{
155 struct symbol *sym = he->sym; 190 struct symbol *sym = he->sym;
191 struct objdump_line *objdump_line;
156 char *line = NULL, *tmp, *tmp2; 192 char *line = NULL, *tmp, *tmp2;
157 static const char *prev_line;
158 static const char *prev_color;
159 unsigned int offset;
160 size_t line_len; 193 size_t line_len;
161 u64 start; 194 s64 line_ip, offset = -1;
162 s64 line_ip;
163 int ret;
164 char *c; 195 char *c;
165 196
166 if (getline(&line, &line_len, file) < 0) 197 if (getline(&line, &line_len, file) < 0)
167 return -1; 198 return -1;
199
168 if (!line) 200 if (!line)
169 return -1; 201 return -1;
170 202
@@ -173,8 +205,6 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
173 *c = 0; 205 *c = 0;
174 206
175 line_ip = -1; 207 line_ip = -1;
176 offset = 0;
177 ret = -2;
178 208
179 /* 209 /*
180 * Strip leading spaces: 210 * Strip leading spaces:
@@ -195,9 +225,30 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
195 line_ip = -1; 225 line_ip = -1;
196 } 226 }
197 227
198 start = he->map->unmap_ip(he->map, sym->start);
199
200 if (line_ip != -1) { 228 if (line_ip != -1) {
229 u64 start = map__rip_2objdump(he->map, sym->start);
230 offset = line_ip - start;
231 }
232
233 objdump_line = objdump_line__new(offset, line);
234 if (objdump_line == NULL) {
235 free(line);
236 return -1;
237 }
238 objdump__add_line(head, objdump_line);
239
240 return 0;
241}
242
243static int objdump_line__print(struct objdump_line *self,
244 struct list_head *head,
245 struct hist_entry *he, u64 len)
246{
247 struct symbol *sym = he->sym;
248 static const char *prev_line;
249 static const char *prev_color;
250
251 if (self->offset != -1) {
201 const char *path = NULL; 252 const char *path = NULL;
202 unsigned int hits = 0; 253 unsigned int hits = 0;
203 double percent = 0.0; 254 double percent = 0.0;
@@ -205,15 +256,22 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
205 struct sym_priv *priv = symbol__priv(sym); 256 struct sym_priv *priv = symbol__priv(sym);
206 struct sym_ext *sym_ext = priv->ext; 257 struct sym_ext *sym_ext = priv->ext;
207 struct sym_hist *h = priv->hist; 258 struct sym_hist *h = priv->hist;
259 s64 offset = self->offset;
260 struct objdump_line *next = objdump__get_next_ip_line(head, self);
261
262 while (offset < (s64)len &&
263 (next == NULL || offset < next->offset)) {
264 if (sym_ext) {
265 if (path == NULL)
266 path = sym_ext[offset].path;
267 percent += sym_ext[offset].percent;
268 } else
269 hits += h->ip[offset];
270
271 ++offset;
272 }
208 273
209 offset = line_ip - start; 274 if (sym_ext == NULL && h->sum)
210 if (offset < len)
211 hits = h->ip[offset];
212
213 if (offset < len && sym_ext) {
214 path = sym_ext[offset].path;
215 percent = sym_ext[offset].percent;
216 } else if (h->sum)
217 percent = 100.0 * hits / h->sum; 275 percent = 100.0 * hits / h->sum;
218 276
219 color = get_percent_color(percent); 277 color = get_percent_color(percent);
@@ -234,12 +292,12 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
234 292
235 color_fprintf(stdout, color, " %7.2f", percent); 293 color_fprintf(stdout, color, " %7.2f", percent);
236 printf(" : "); 294 printf(" : ");
237 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); 295 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
238 } else { 296 } else {
239 if (!*line) 297 if (!*self->line)
240 printf(" :\n"); 298 printf(" :\n");
241 else 299 else
242 printf(" : %s\n", line); 300 printf(" : %s\n", self->line);
243 } 301 }
244 302
245 return 0; 303 return 0;
@@ -365,6 +423,20 @@ static void print_summary(const char *filename)
365 } 423 }
366} 424}
367 425
426static void hist_entry__print_hits(struct hist_entry *self)
427{
428 struct symbol *sym = self->sym;
429 struct sym_priv *priv = symbol__priv(sym);
430 struct sym_hist *h = priv->hist;
431 u64 len = sym->end - sym->start, offset;
432
433 for (offset = 0; offset < len; ++offset)
434 if (h->ip[offset] != 0)
435 printf("%*Lx: %Lu\n", BITS_PER_LONG / 2,
436 sym->start + offset, h->ip[offset]);
437 printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum);
438}
439
368static void annotate_sym(struct hist_entry *he) 440static void annotate_sym(struct hist_entry *he)
369{ 441{
370 struct map *map = he->map; 442 struct map *map = he->map;
@@ -374,15 +446,15 @@ static void annotate_sym(struct hist_entry *he)
374 u64 len; 446 u64 len;
375 char command[PATH_MAX*2]; 447 char command[PATH_MAX*2];
376 FILE *file; 448 FILE *file;
449 LIST_HEAD(head);
450 struct objdump_line *pos, *n;
377 451
378 if (!filename) 452 if (!filename)
379 return; 453 return;
380 454
381 if (verbose) 455 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
382 fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n", 456 filename, sym->name, map->unmap_ip(map, sym->start),
383 __func__, filename, sym->name, 457 map->unmap_ip(map, sym->end));
384 map->unmap_ip(map, sym->start),
385 map->unmap_ip(map, sym->end));
386 458
387 if (full_paths) 459 if (full_paths)
388 d_filename = filename; 460 d_filename = filename;
@@ -405,7 +477,8 @@ static void annotate_sym(struct hist_entry *he)
405 dso, dso->long_name, sym, sym->name); 477 dso, dso->long_name, sym, sym->name);
406 478
407 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", 479 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
408 map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end), 480 map__rip_2objdump(map, sym->start),
481 map__rip_2objdump(map, sym->end),
409 filename, filename); 482 filename, filename);
410 483
411 if (verbose >= 3) 484 if (verbose >= 3)
@@ -416,11 +489,21 @@ static void annotate_sym(struct hist_entry *he)
416 return; 489 return;
417 490
418 while (!feof(file)) { 491 while (!feof(file)) {
419 if (parse_line(file, he, len) < 0) 492 if (parse_line(file, he, &head) < 0)
420 break; 493 break;
421 } 494 }
422 495
423 pclose(file); 496 pclose(file);
497
498 if (verbose)
499 hist_entry__print_hits(he);
500
501 list_for_each_entry_safe(pos, n, &head, node) {
502 objdump_line__print(pos, &head, he, len);
503 list_del(&pos->node);
504 objdump_line__free(pos);
505 }
506
424 if (print_line) 507 if (print_line)
425 free_source_line(he, len); 508 free_source_line(he, len);
426} 509}
@@ -451,10 +534,10 @@ static void perf_session__find_annotations(struct perf_session *self)
451} 534}
452 535
453static struct perf_event_ops event_ops = { 536static struct perf_event_ops event_ops = {
454 .process_sample_event = process_sample_event, 537 .sample = process_sample_event,
455 .process_mmap_event = event__process_mmap, 538 .mmap = event__process_mmap,
456 .process_comm_event = event__process_comm, 539 .comm = event__process_comm,
457 .process_fork_event = event__process_task, 540 .fork = event__process_task,
458}; 541};
459 542
460static int __cmd_annotate(void) 543static int __cmd_annotate(void)
@@ -542,9 +625,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
542 setup_pager(); 625 setup_pager();
543 626
544 if (field_sep && *field_sep == '.') { 627 if (field_sep && *field_sep == '.') {
545 fputs("'.' is the only non valid --field-separator argument\n", 628 pr_err("'.' is the only non valid --field-separator argument\n");
546 stderr); 629 return -1;
547 exit(129);
548 } 630 }
549 631
550 return __cmd_annotate(); 632 return __cmd_annotate();