aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/annotate.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-11-23 23:09:31 -0500
committerIngo Molnar <mingo@kernel.org>2016-11-23 23:09:31 -0500
commit47414424c53a70eceb0fc6e0a35a31a2b763d5b2 (patch)
tree07979aa784313ba03712df2b85a3b3f71f1733d6 /tools/perf/util/annotate.c
parent69e6cdd0cf16f645be39038e5ccc9379e3923d00 (diff)
parenta407b0678bc1c39d70af5fdbe6421c164b69a8c0 (diff)
Merge tag 'perf-core-for-mingo-20161123' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: New tool: - 'perf sched timehist' provides an analysis of scheduling events. Example usage: perf sched record -- sleep 1 perf sched timehist By default it shows the individual schedule events, including the wait time (time between sched-out and next sched-in events for the task), the task scheduling delay (time between wakeup and actually running) and run time for the task: time cpu task name wait time sch delay run time [tid/pid] (msec) (msec) (msec) -------- ------ ---------------- --------- --------- -------- 1.874569 [0011] gcc[31949] 0.014 0.000 1.148 1.874591 [0010] gcc[31951] 0.000 0.000 0.024 1.874603 [0010] migration/10[59] 3.350 0.004 0.011 1.874604 [0011] <idle> 1.148 0.000 0.035 1.874723 [0005] <idle> 0.016 0.000 1.383 1.874746 [0005] gcc[31949] 0.153 0.078 0.022 ... Times are in msec.usec. (David Ahern, Namhyung Kim) Improvements: - Make 'perf c2c report' support -f/--force, to allow skipping the ownership check for root users, for instance, just like the other tools (Jiri Olsa) - Allow sorting cachelines by total number of HITMs, in addition to local and remote numbers (Jiri Olsa) Fixes: - Make sure errors aren't suppressed by the TUI reset at the end of a 'perf c2c report' session (Jiri Olsa) Infrastructure changes: - Initial work on having the annotate code better support multiple architectures, including the ability to cross-annotate, i.e. to annotate perf.data files collected on an ARM system on a x86_64 workstation (Arnaldo Carvalho de Melo, Ravi Bangoria, Kim Phillips) - Use USECS_PER_SEC instead of hard coded number in libtraceevent (Steven Rostedt) - Add retrieval of preempt count and latency flags in libtraceevent (Steven Rostedt) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r--tools/perf/util/annotate.c251
1 files changed, 127 insertions, 124 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index aeb5a441bd74..095d90a9077f 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -18,17 +18,61 @@
18#include "annotate.h" 18#include "annotate.h"
19#include "evsel.h" 19#include "evsel.h"
20#include "block-range.h" 20#include "block-range.h"
21#include "arch/common.h"
21#include <regex.h> 22#include <regex.h>
22#include <pthread.h> 23#include <pthread.h>
23#include <linux/bitops.h> 24#include <linux/bitops.h>
25#include <sys/utsname.h>
24 26
25const char *disassembler_style; 27const char *disassembler_style;
26const char *objdump_path; 28const char *objdump_path;
27static regex_t file_lineno; 29static regex_t file_lineno;
28 30
29static struct ins *ins__find(const char *name); 31static struct ins *ins__find(struct arch *arch, const char *name);
30static int disasm_line__parse(char *line, char **namep, char **rawp); 32static int disasm_line__parse(char *line, char **namep, char **rawp);
31 33
34struct arch {
35 const char *name;
36 struct ins *instructions;
37 size_t nr_instructions;
38 bool sorted_instructions;
39 struct {
40 char comment_char;
41 char skip_functions_char;
42 } objdump;
43};
44
45static struct ins_ops call_ops;
46static struct ins_ops dec_ops;
47static struct ins_ops jump_ops;
48static struct ins_ops mov_ops;
49static struct ins_ops nop_ops;
50static struct ins_ops lock_ops;
51static struct ins_ops ret_ops;
52
53#include "arch/arm/annotate/instructions.c"
54#include "arch/x86/annotate/instructions.c"
55
56static struct arch architectures[] = {
57 {
58 .name = "arm",
59 .instructions = arm__instructions,
60 .nr_instructions = ARRAY_SIZE(arm__instructions),
61 .objdump = {
62 .comment_char = ';',
63 .skip_functions_char = '+',
64 },
65 },
66 {
67 .name = "x86",
68 .instructions = x86__instructions,
69 .nr_instructions = ARRAY_SIZE(x86__instructions),
70 .objdump = {
71 .comment_char = '#',
72 },
73 },
74};
75
32static void ins__delete(struct ins_operands *ops) 76static void ins__delete(struct ins_operands *ops)
33{ 77{
34 if (ops == NULL) 78 if (ops == NULL)
@@ -54,7 +98,7 @@ int ins__scnprintf(struct ins *ins, char *bf, size_t size,
54 return ins__raw_scnprintf(ins, bf, size, ops); 98 return ins__raw_scnprintf(ins, bf, size, ops);
55} 99}
56 100
57static int call__parse(struct ins_operands *ops, struct map *map) 101static int call__parse(struct arch *arch, struct ins_operands *ops, struct map *map)
58{ 102{
59 char *endptr, *tok, *name; 103 char *endptr, *tok, *name;
60 104
@@ -66,10 +110,9 @@ static int call__parse(struct ins_operands *ops, struct map *map)
66 110
67 name++; 111 name++;
68 112
69#ifdef __arm__ 113 if (arch->objdump.skip_functions_char &&
70 if (strchr(name, '+')) 114 strchr(name, arch->objdump.skip_functions_char))
71 return -1; 115 return -1;
72#endif
73 116
74 tok = strchr(name, '>'); 117 tok = strchr(name, '>');
75 if (tok == NULL) 118 if (tok == NULL)
@@ -118,7 +161,7 @@ bool ins__is_call(const struct ins *ins)
118 return ins->ops == &call_ops; 161 return ins->ops == &call_ops;
119} 162}
120 163
121static int jump__parse(struct ins_operands *ops, struct map *map __maybe_unused) 164static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused)
122{ 165{
123 const char *s = strchr(ops->raw, '+'); 166 const char *s = strchr(ops->raw, '+');
124 167
@@ -173,7 +216,7 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
173 return 0; 216 return 0;
174} 217}
175 218
176static int lock__parse(struct ins_operands *ops, struct map *map) 219static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map *map)
177{ 220{
178 char *name; 221 char *name;
179 222
@@ -184,7 +227,7 @@ static int lock__parse(struct ins_operands *ops, struct map *map)
184 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) 227 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
185 goto out_free_ops; 228 goto out_free_ops;
186 229
187 ops->locked.ins = ins__find(name); 230 ops->locked.ins = ins__find(arch, name);
188 free(name); 231 free(name);
189 232
190 if (ops->locked.ins == NULL) 233 if (ops->locked.ins == NULL)
@@ -194,7 +237,7 @@ static int lock__parse(struct ins_operands *ops, struct map *map)
194 return 0; 237 return 0;
195 238
196 if (ops->locked.ins->ops->parse && 239 if (ops->locked.ins->ops->parse &&
197 ops->locked.ins->ops->parse(ops->locked.ops, map) < 0) 240 ops->locked.ins->ops->parse(arch, ops->locked.ops, map) < 0)
198 goto out_free_ops; 241 goto out_free_ops;
199 242
200 return 0; 243 return 0;
@@ -237,7 +280,7 @@ static struct ins_ops lock_ops = {
237 .scnprintf = lock__scnprintf, 280 .scnprintf = lock__scnprintf,
238}; 281};
239 282
240static int mov__parse(struct ins_operands *ops, struct map *map __maybe_unused) 283static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map *map __maybe_unused)
241{ 284{
242 char *s = strchr(ops->raw, ','), *target, *comment, prev; 285 char *s = strchr(ops->raw, ','), *target, *comment, prev;
243 286
@@ -252,11 +295,7 @@ static int mov__parse(struct ins_operands *ops, struct map *map __maybe_unused)
252 return -1; 295 return -1;
253 296
254 target = ++s; 297 target = ++s;
255#ifdef __arm__ 298 comment = strchr(s, arch->objdump.comment_char);
256 comment = strchr(s, ';');
257#else
258 comment = strchr(s, '#');
259#endif
260 299
261 if (comment != NULL) 300 if (comment != NULL)
262 s = comment - 1; 301 s = comment - 1;
@@ -304,7 +343,7 @@ static struct ins_ops mov_ops = {
304 .scnprintf = mov__scnprintf, 343 .scnprintf = mov__scnprintf,
305}; 344};
306 345
307static int dec__parse(struct ins_operands *ops, struct map *map __maybe_unused) 346static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused)
308{ 347{
309 char *target, *comment, *s, prev; 348 char *target, *comment, *s, prev;
310 349
@@ -364,99 +403,6 @@ bool ins__is_ret(const struct ins *ins)
364 return ins->ops == &ret_ops; 403 return ins->ops == &ret_ops;
365} 404}
366 405
367static struct ins instructions[] = {
368 { .name = "add", .ops = &mov_ops, },
369 { .name = "addl", .ops = &mov_ops, },
370 { .name = "addq", .ops = &mov_ops, },
371 { .name = "addw", .ops = &mov_ops, },
372 { .name = "and", .ops = &mov_ops, },
373#ifdef __arm__
374 { .name = "b", .ops = &jump_ops, }, // might also be a call
375 { .name = "bcc", .ops = &jump_ops, },
376 { .name = "bcs", .ops = &jump_ops, },
377 { .name = "beq", .ops = &jump_ops, },
378 { .name = "bge", .ops = &jump_ops, },
379 { .name = "bgt", .ops = &jump_ops, },
380 { .name = "bhi", .ops = &jump_ops, },
381 { .name = "bl", .ops = &call_ops, },
382 { .name = "bls", .ops = &jump_ops, },
383 { .name = "blt", .ops = &jump_ops, },
384 { .name = "blx", .ops = &call_ops, },
385 { .name = "bne", .ops = &jump_ops, },
386#endif
387 { .name = "bts", .ops = &mov_ops, },
388 { .name = "call", .ops = &call_ops, },
389 { .name = "callq", .ops = &call_ops, },
390 { .name = "cmp", .ops = &mov_ops, },
391 { .name = "cmpb", .ops = &mov_ops, },
392 { .name = "cmpl", .ops = &mov_ops, },
393 { .name = "cmpq", .ops = &mov_ops, },
394 { .name = "cmpw", .ops = &mov_ops, },
395 { .name = "cmpxch", .ops = &mov_ops, },
396 { .name = "dec", .ops = &dec_ops, },
397 { .name = "decl", .ops = &dec_ops, },
398 { .name = "imul", .ops = &mov_ops, },
399 { .name = "inc", .ops = &dec_ops, },
400 { .name = "incl", .ops = &dec_ops, },
401 { .name = "ja", .ops = &jump_ops, },
402 { .name = "jae", .ops = &jump_ops, },
403 { .name = "jb", .ops = &jump_ops, },
404 { .name = "jbe", .ops = &jump_ops, },
405 { .name = "jc", .ops = &jump_ops, },
406 { .name = "jcxz", .ops = &jump_ops, },
407 { .name = "je", .ops = &jump_ops, },
408 { .name = "jecxz", .ops = &jump_ops, },
409 { .name = "jg", .ops = &jump_ops, },
410 { .name = "jge", .ops = &jump_ops, },
411 { .name = "jl", .ops = &jump_ops, },
412 { .name = "jle", .ops = &jump_ops, },
413 { .name = "jmp", .ops = &jump_ops, },
414 { .name = "jmpq", .ops = &jump_ops, },
415 { .name = "jna", .ops = &jump_ops, },
416 { .name = "jnae", .ops = &jump_ops, },
417 { .name = "jnb", .ops = &jump_ops, },
418 { .name = "jnbe", .ops = &jump_ops, },
419 { .name = "jnc", .ops = &jump_ops, },
420 { .name = "jne", .ops = &jump_ops, },
421 { .name = "jng", .ops = &jump_ops, },
422 { .name = "jnge", .ops = &jump_ops, },
423 { .name = "jnl", .ops = &jump_ops, },
424 { .name = "jnle", .ops = &jump_ops, },
425 { .name = "jno", .ops = &jump_ops, },
426 { .name = "jnp", .ops = &jump_ops, },
427 { .name = "jns", .ops = &jump_ops, },
428 { .name = "jnz", .ops = &jump_ops, },
429 { .name = "jo", .ops = &jump_ops, },
430 { .name = "jp", .ops = &jump_ops, },
431 { .name = "jpe", .ops = &jump_ops, },
432 { .name = "jpo", .ops = &jump_ops, },
433 { .name = "jrcxz", .ops = &jump_ops, },
434 { .name = "js", .ops = &jump_ops, },
435 { .name = "jz", .ops = &jump_ops, },
436 { .name = "lea", .ops = &mov_ops, },
437 { .name = "lock", .ops = &lock_ops, },
438 { .name = "mov", .ops = &mov_ops, },
439 { .name = "movb", .ops = &mov_ops, },
440 { .name = "movdqa",.ops = &mov_ops, },
441 { .name = "movl", .ops = &mov_ops, },
442 { .name = "movq", .ops = &mov_ops, },
443 { .name = "movslq", .ops = &mov_ops, },
444 { .name = "movzbl", .ops = &mov_ops, },
445 { .name = "movzwl", .ops = &mov_ops, },
446 { .name = "nop", .ops = &nop_ops, },
447 { .name = "nopl", .ops = &nop_ops, },
448 { .name = "nopw", .ops = &nop_ops, },
449 { .name = "or", .ops = &mov_ops, },
450 { .name = "orl", .ops = &mov_ops, },
451 { .name = "test", .ops = &mov_ops, },
452 { .name = "testb", .ops = &mov_ops, },
453 { .name = "testl", .ops = &mov_ops, },
454 { .name = "xadd", .ops = &mov_ops, },
455 { .name = "xbeginl", .ops = &jump_ops, },
456 { .name = "xbeginq", .ops = &jump_ops, },
457 { .name = "retq", .ops = &ret_ops, },
458};
459
460static int ins__key_cmp(const void *name, const void *insp) 406static int ins__key_cmp(const void *name, const void *insp)
461{ 407{
462 const struct ins *ins = insp; 408 const struct ins *ins = insp;
@@ -472,24 +418,58 @@ static int ins__cmp(const void *a, const void *b)
472 return strcmp(ia->name, ib->name); 418 return strcmp(ia->name, ib->name);
473} 419}
474 420
475static void ins__sort(void) 421static void ins__sort(struct arch *arch)
476{ 422{
477 const int nmemb = ARRAY_SIZE(instructions); 423 const int nmemb = arch->nr_instructions;
478 424
479 qsort(instructions, nmemb, sizeof(struct ins), ins__cmp); 425 qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp);
480} 426}
481 427
482static struct ins *ins__find(const char *name) 428static struct ins *ins__find(struct arch *arch, const char *name)
483{ 429{
484 const int nmemb = ARRAY_SIZE(instructions); 430 const int nmemb = arch->nr_instructions;
431
432 if (!arch->sorted_instructions) {
433 ins__sort(arch);
434 arch->sorted_instructions = true;
435 }
436
437 return bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp);
438}
439
440static int arch__key_cmp(const void *name, const void *archp)
441{
442 const struct arch *arch = archp;
443
444 return strcmp(name, arch->name);
445}
446
447static int arch__cmp(const void *a, const void *b)
448{
449 const struct arch *aa = a;
450 const struct arch *ab = b;
451
452 return strcmp(aa->name, ab->name);
453}
454
455static void arch__sort(void)
456{
457 const int nmemb = ARRAY_SIZE(architectures);
458
459 qsort(architectures, nmemb, sizeof(struct arch), arch__cmp);
460}
461
462static struct arch *arch__find(const char *name)
463{
464 const int nmemb = ARRAY_SIZE(architectures);
485 static bool sorted; 465 static bool sorted;
486 466
487 if (!sorted) { 467 if (!sorted) {
488 ins__sort(); 468 arch__sort();
489 sorted = true; 469 sorted = true;
490 } 470 }
491 471
492 return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp); 472 return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp);
493} 473}
494 474
495int symbol__alloc_hist(struct symbol *sym) 475int symbol__alloc_hist(struct symbol *sym)
@@ -709,9 +689,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
709 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); 689 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
710} 690}
711 691
712static void disasm_line__init_ins(struct disasm_line *dl, struct map *map) 692static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map)
713{ 693{
714 dl->ins = ins__find(dl->name); 694 dl->ins = ins__find(arch, dl->name);
715 695
716 if (dl->ins == NULL) 696 if (dl->ins == NULL)
717 return; 697 return;
@@ -719,7 +699,7 @@ static void disasm_line__init_ins(struct disasm_line *dl, struct map *map)
719 if (!dl->ins->ops) 699 if (!dl->ins->ops)
720 return; 700 return;
721 701
722 if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops, map) < 0) 702 if (dl->ins->ops->parse && dl->ins->ops->parse(arch, &dl->ops, map) < 0)
723 dl->ins = NULL; 703 dl->ins = NULL;
724} 704}
725 705
@@ -762,6 +742,7 @@ out_free_name:
762 742
763static struct disasm_line *disasm_line__new(s64 offset, char *line, 743static struct disasm_line *disasm_line__new(s64 offset, char *line,
764 size_t privsize, int line_nr, 744 size_t privsize, int line_nr,
745 struct arch *arch,
765 struct map *map) 746 struct map *map)
766{ 747{
767 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); 748 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
@@ -777,7 +758,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line,
777 if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) 758 if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
778 goto out_free_line; 759 goto out_free_line;
779 760
780 disasm_line__init_ins(dl, map); 761 disasm_line__init_ins(dl, arch, map);
781 } 762 }
782 } 763 }
783 764
@@ -1087,6 +1068,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
1087 * The ops.raw part will be parsed further according to type of the instruction. 1068 * The ops.raw part will be parsed further according to type of the instruction.
1088 */ 1069 */
1089static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, 1070static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
1071 struct arch *arch,
1090 FILE *file, size_t privsize, 1072 FILE *file, size_t privsize,
1091 int *line_nr) 1073 int *line_nr)
1092{ 1074{
@@ -1149,7 +1131,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
1149 parsed_line = tmp2 + 1; 1131 parsed_line = tmp2 + 1;
1150 } 1132 }
1151 1133
1152 dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, map); 1134 dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, arch, map);
1153 free(line); 1135 free(line);
1154 (*line_nr)++; 1136 (*line_nr)++;
1155 1137
@@ -1280,10 +1262,23 @@ fallback:
1280 return 0; 1262 return 0;
1281} 1263}
1282 1264
1283int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) 1265static const char *annotate__norm_arch(const char *arch_name)
1266{
1267 struct utsname uts;
1268
1269 if (!arch_name) { /* Assume we are annotating locally. */
1270 if (uname(&uts) < 0)
1271 return NULL;
1272 arch_name = uts.machine;
1273 }
1274 return normalize_arch((char *)arch_name);
1275}
1276
1277int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize)
1284{ 1278{
1285 struct dso *dso = map->dso; 1279 struct dso *dso = map->dso;
1286 char command[PATH_MAX * 2]; 1280 char command[PATH_MAX * 2];
1281 struct arch *arch = NULL;
1287 FILE *file; 1282 FILE *file;
1288 char symfs_filename[PATH_MAX]; 1283 char symfs_filename[PATH_MAX];
1289 struct kcore_extract kce; 1284 struct kcore_extract kce;
@@ -1297,6 +1292,14 @@ int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize)
1297 if (err) 1292 if (err)
1298 return err; 1293 return err;
1299 1294
1295 arch_name = annotate__norm_arch(arch_name);
1296 if (!arch_name)
1297 return -1;
1298
1299 arch = arch__find(arch_name);
1300 if (arch == NULL)
1301 return -ENOTSUP;
1302
1300 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, 1303 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
1301 symfs_filename, sym->name, map->unmap_ip(map, sym->start), 1304 symfs_filename, sym->name, map->unmap_ip(map, sym->start),
1302 map->unmap_ip(map, sym->end)); 1305 map->unmap_ip(map, sym->end));
@@ -1395,7 +1398,7 @@ int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize)
1395 1398
1396 nline = 0; 1399 nline = 0;
1397 while (!feof(file)) { 1400 while (!feof(file)) {
1398 if (symbol__parse_objdump_line(sym, map, file, privsize, 1401 if (symbol__parse_objdump_line(sym, map, arch, file, privsize,
1399 &lineno) < 0) 1402 &lineno) < 0)
1400 break; 1403 break;
1401 nline++; 1404 nline++;
@@ -1793,7 +1796,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
1793 struct rb_root source_line = RB_ROOT; 1796 struct rb_root source_line = RB_ROOT;
1794 u64 len; 1797 u64 len;
1795 1798
1796 if (symbol__disassemble(sym, map, 0) < 0) 1799 if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 0) < 0)
1797 return -1; 1800 return -1;
1798 1801
1799 len = symbol__size(sym); 1802 len = symbol__size(sym);