aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-02-26 09:23:14 -0500
committerIngo Molnar <mingo@elte.hu>2010-02-26 09:42:49 -0500
commit48fb4fdd6b667ebeccbc6cde0a8a5a148d5c6b68 (patch)
treed724279780a2a9217f2b2b4c4ba2329bf2d1e30e /tools/perf
parent6667661df4bc76083edf1e08831c20f64429709d (diff)
perf annotate: Handle samples not at objdump output addr boundaries
Without this patch we get this for need_resched: [root@mica ~]# perf annotate need_resched ------------------------------------------------ Percent | Source code & Disassembly of vmlinux ------------------------------------------------ : : : Disassembly of section .text: : : ffffffff810095ed <need_resched>: : return (state & TASK_INTERRUPTIBLE) || __fatal_signal_pending(p); : } : : static inline int need_resched(void) : { 0.00 : ffffffff810095ed: 55 push %rbp : return unlikely(test_thread_flag(TIF_NEED_RESCHED)); 0.00 : ffffffff810095ee: be 03 00 00 00 mov $0x3,%esi : : static inline struct thread_info *current_thread_info(void) : { : struct thread_info *ti; : ti = (void *)(percpu_read_stable(kernel_stack) + 0.00 : ffffffff810095f3: 65 48 8b 3c 25 48 b5 mov %gs:0xb548,%rdi 0.00 : ffffffff810095fa: 00 00 : return (state & TASK_INTERRUPTIBLE) || __fatal_signal_pending(p); : } : : static inline int need_resched(void) : { 0.00 : ffffffff810095fc: 48 89 e5 mov %rsp,%rbp : return unlikely(test_thread_flag(TIF_NEED_RESCHED)); 0.00 : ffffffff810095ff: 48 81 ef d8 1f 00 00 sub $0x1fd8,%rdi 0.00 : ffffffff81009606: e8 9d ff ff ff callq ffffffff810095a8 <test_ti_thread_flag> : } 0.00 : ffffffff8100960b: c9 leaveq 0.00 : ffffffff8100960c: 85 c0 test %eax,%eax 0.00 : ffffffff8100960e: 0f 95 c0 setne %al 0.00 : ffffffff81009611: 0f b6 c0 movzbl %al,%eax : Disassembly of section .vsyscall_0: : Disassembly of section .vsyscall_fn: : Disassembly of section .vsyscall_1: : Disassembly of section .vsyscall_2: : Disassembly of section .init.text: : Disassembly of section .altinstr_replacement: : Disassembly of section .exit.text: [root@mica ~]# But from the 'perf report' result we know that there are hits for need_resched on a 4 way machine mostly doing nothing, so after adding code to show what is in each hist offset and collapsing IP hits for what happens between objdump lines we get, for the same perf.data file: [root@mica ~]# perf annotate -v need_resched ------------------------------------------------ Percent | Source code & Disassembly of vmlinux ------------------------------------------------ : : : Disassembly of section .text: : : ffffffff810095ed <need_resched>: : return (state & TASK_INTERRUPTIBLE) || __fatal_signal_pending(p); : } : : static inline int need_resched(void) : { 0.00 : ffffffff810095ed: 55 push %rbp : return unlikely(test_thread_flag(TIF_NEED_RESCHED)); 52.78 : ffffffff810095ee: be 03 00 00 00 mov $0x3,%esi : : static inline struct thread_info *current_thread_info(void) : { : struct thread_info *ti; : ti = (void *)(percpu_read_stable(kernel_stack) + 0.00 : ffffffff810095f3: 65 48 8b 3c 25 48 b5 mov %gs:0xb548,%rdi 0.00 : ffffffff810095fa: 00 00 : return (state & TASK_INTERRUPTIBLE) || __fatal_signal_pending(p); : } : : static inline int need_resched(void) : { 0.00 : ffffffff810095fc: 48 89 e5 mov %rsp,%rbp : return unlikely(test_thread_flag(TIF_NEED_RESCHED)); 9.72 : ffffffff810095ff: 48 81 ef d8 1f 00 00 sub $0x1fd8,%rdi 0.00 : ffffffff81009606: e8 9d ff ff ff callq ffffffff810095a8 <test_ti_thread_flag> : } 0.00 : ffffffff8100960b: c9 leaveq 0.00 : ffffffff8100960c: 85 c0 test %eax,%eax 37.50 : ffffffff8100960e: 0f 95 c0 setne %al 0.00 : ffffffff81009611: 0f b6 c0 movzbl %al,%eax : Disassembly of section .vsyscall_0: : Disassembly of section .vsyscall_fn: : Disassembly of section .vsyscall_1: : Disassembly of section .vsyscall_2: : Disassembly of section .init.text: : Disassembly of section .altinstr_replacement: : Disassembly of section .exit.text: [root@mica ~]# And now 'perf annotate -v', verbose mode, will show the hits per precise IP, so that one can make sense of the attribution to each objdumop line: [root@mica ~]# perf annotate -v need_resched Looking at the vmlinux_path (5 entries long) Using /lib/modules/2.6.33-rc8-tip-00784-g3471df5-dirty/build/vmlinux for symbols annotate_sym: filename=/lib/modules/2.6.33-rc8-tip-00784-g3471df5-dirty/build/vmlinux, sym=need_resched, start=0xffffffff810095ed, end=0xffffffff81009614 ------------------------------------------------ Percent | Source code & Disassembly of vmlinux ------------------------------------------------ ffffffff810095f1: 152 ffffffff81009603: 28 ffffffff8100960f: 55 ffffffff81009610: 53 h->sum: 288 <SNIP same annotation> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: David Miller <davem@davemloft.net> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> LKML-Reference: <1267194194-15670-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/builtin-annotate.c135
1 files changed, 112 insertions, 23 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index e47dd1587e39..5ec5de995872 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -145,21 +145,58 @@ static int process_sample_event(event_t *event, struct perf_session *session)
145 return 0; 145 return 0;
146} 146}
147 147
148static 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)
149{ 189{
150 struct symbol *sym = he->sym; 190 struct symbol *sym = he->sym;
191 struct objdump_line *objdump_line;
151 char *line = NULL, *tmp, *tmp2; 192 char *line = NULL, *tmp, *tmp2;
152 static const char *prev_line;
153 static const char *prev_color;
154 unsigned int offset;
155 size_t line_len; 193 size_t line_len;
156 u64 start; 194 s64 line_ip, offset = -1;
157 s64 line_ip;
158 int ret;
159 char *c; 195 char *c;
160 196
161 if (getline(&line, &line_len, file) < 0) 197 if (getline(&line, &line_len, file) < 0)
162 return -1; 198 return -1;
199
163 if (!line) 200 if (!line)
164 return -1; 201 return -1;
165 202
@@ -168,8 +205,6 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
168 *c = 0; 205 *c = 0;
169 206
170 line_ip = -1; 207 line_ip = -1;
171 offset = 0;
172 ret = -2;
173 208
174 /* 209 /*
175 * Strip leading spaces: 210 * Strip leading spaces:
@@ -190,9 +225,30 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
190 line_ip = -1; 225 line_ip = -1;
191 } 226 }
192 227
193 start = map__rip_2objdump(he->map, sym->start);
194
195 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) {
196 const char *path = NULL; 252 const char *path = NULL;
197 unsigned int hits = 0; 253 unsigned int hits = 0;
198 double percent = 0.0; 254 double percent = 0.0;
@@ -200,15 +256,22 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
200 struct sym_priv *priv = symbol__priv(sym); 256 struct sym_priv *priv = symbol__priv(sym);
201 struct sym_ext *sym_ext = priv->ext; 257 struct sym_ext *sym_ext = priv->ext;
202 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 }
203 273
204 offset = line_ip - start; 274 if (sym_ext == NULL && h->sum)
205 if (offset < len)
206 hits = h->ip[offset];
207
208 if (offset < len && sym_ext) {
209 path = sym_ext[offset].path;
210 percent = sym_ext[offset].percent;
211 } else if (h->sum)
212 percent = 100.0 * hits / h->sum; 275 percent = 100.0 * hits / h->sum;
213 276
214 color = get_percent_color(percent); 277 color = get_percent_color(percent);
@@ -229,12 +292,12 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
229 292
230 color_fprintf(stdout, color, " %7.2f", percent); 293 color_fprintf(stdout, color, " %7.2f", percent);
231 printf(" : "); 294 printf(" : ");
232 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); 295 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
233 } else { 296 } else {
234 if (!*line) 297 if (!*self->line)
235 printf(" :\n"); 298 printf(" :\n");
236 else 299 else
237 printf(" : %s\n", line); 300 printf(" : %s\n", self->line);
238 } 301 }
239 302
240 return 0; 303 return 0;
@@ -360,6 +423,20 @@ static void print_summary(const char *filename)
360 } 423 }
361} 424}
362 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
363static void annotate_sym(struct hist_entry *he) 440static void annotate_sym(struct hist_entry *he)
364{ 441{
365 struct map *map = he->map; 442 struct map *map = he->map;
@@ -369,6 +446,8 @@ static void annotate_sym(struct hist_entry *he)
369 u64 len; 446 u64 len;
370 char command[PATH_MAX*2]; 447 char command[PATH_MAX*2];
371 FILE *file; 448 FILE *file;
449 LIST_HEAD(head);
450 struct objdump_line *pos, *n;
372 451
373 if (!filename) 452 if (!filename)
374 return; 453 return;
@@ -410,11 +489,21 @@ static void annotate_sym(struct hist_entry *he)
410 return; 489 return;
411 490
412 while (!feof(file)) { 491 while (!feof(file)) {
413 if (parse_line(file, he, len) < 0) 492 if (parse_line(file, he, &head) < 0)
414 break; 493 break;
415 } 494 }
416 495
417 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
418 if (print_line) 507 if (print_line)
419 free_source_line(he, len); 508 free_source_line(he, len);
420} 509}