perf annotate: Add per arch instructions annotate handlers
authorArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 17 Nov 2016 15:31:51 +0000 (12:31 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 17 Nov 2016 20:31:59 +0000 (17:31 -0300)
Another step in supporting cross annotation.

The arch specific tables are put in:

   tools/perf/arch/$ARCH/annotation/instructions.c

which, so far, just plug instructions to a bunch of parsers/formatters,
but may have more as the need arises.

This is an alternative implementation to a previous attempt made by Ravi
Bangoria.

Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Chris Riyder <chris.ryder@arm.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kim Phillips <kim.phillips@arm.com>
Cc: Markus Trippelsdorf <markus@trippelsdorf.de>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Cc: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: Taeung Song <treeze.taeung@gmail.com>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-g3wt282lfa51j4qd0813e3az@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/arch/arm/annotate/instructions.c [new file with mode: 0644]
tools/perf/arch/x86/annotate/instructions.c [new file with mode: 0644]
tools/perf/util/annotate.c

diff --git a/tools/perf/arch/arm/annotate/instructions.c b/tools/perf/arch/arm/annotate/instructions.c
new file mode 100644 (file)
index 0000000..d67b8aa
--- /dev/null
@@ -0,0 +1,90 @@
+static struct ins arm__instructions[] = {
+       { .name = "add",        .ops = &mov_ops,  },
+       { .name = "addl",       .ops = &mov_ops,  },
+       { .name = "addq",       .ops = &mov_ops,  },
+       { .name = "addw",       .ops = &mov_ops,  },
+       { .name = "and",        .ops = &mov_ops,  },
+       { .name = "b",          .ops = &jump_ops, }, // might also be a call
+       { .name = "bcc",        .ops = &jump_ops, },
+       { .name = "bcs",        .ops = &jump_ops, },
+       { .name = "beq",        .ops = &jump_ops, },
+       { .name = "bge",        .ops = &jump_ops, },
+       { .name = "bgt",        .ops = &jump_ops, },
+       { .name = "bhi",        .ops = &jump_ops, },
+       { .name = "bl",         .ops = &call_ops, },
+       { .name = "bls",        .ops = &jump_ops, },
+       { .name = "blt",        .ops = &jump_ops, },
+       { .name = "blx",        .ops = &call_ops, },
+       { .name = "bne",        .ops = &jump_ops, },
+       { .name = "bts",        .ops = &mov_ops,  },
+       { .name = "call",       .ops = &call_ops, },
+       { .name = "callq",      .ops = &call_ops, },
+       { .name = "cmp",        .ops = &mov_ops,  },
+       { .name = "cmpb",       .ops = &mov_ops,  },
+       { .name = "cmpl",       .ops = &mov_ops,  },
+       { .name = "cmpq",       .ops = &mov_ops,  },
+       { .name = "cmpw",       .ops = &mov_ops,  },
+       { .name = "cmpxch",     .ops = &mov_ops,  },
+       { .name = "dec",        .ops = &dec_ops,  },
+       { .name = "decl",       .ops = &dec_ops,  },
+       { .name = "imul",       .ops = &mov_ops,  },
+       { .name = "inc",        .ops = &dec_ops,  },
+       { .name = "incl",       .ops = &dec_ops,  },
+       { .name = "ja",         .ops = &jump_ops, },
+       { .name = "jae",        .ops = &jump_ops, },
+       { .name = "jb",         .ops = &jump_ops, },
+       { .name = "jbe",        .ops = &jump_ops, },
+       { .name = "jc",         .ops = &jump_ops, },
+       { .name = "jcxz",       .ops = &jump_ops, },
+       { .name = "je",         .ops = &jump_ops, },
+       { .name = "jecxz",      .ops = &jump_ops, },
+       { .name = "jg",         .ops = &jump_ops, },
+       { .name = "jge",        .ops = &jump_ops, },
+       { .name = "jl",         .ops = &jump_ops, },
+       { .name = "jle",        .ops = &jump_ops, },
+       { .name = "jmp",        .ops = &jump_ops, },
+       { .name = "jmpq",       .ops = &jump_ops, },
+       { .name = "jna",        .ops = &jump_ops, },
+       { .name = "jnae",       .ops = &jump_ops, },
+       { .name = "jnb",        .ops = &jump_ops, },
+       { .name = "jnbe",       .ops = &jump_ops, },
+       { .name = "jnc",        .ops = &jump_ops, },
+       { .name = "jne",        .ops = &jump_ops, },
+       { .name = "jng",        .ops = &jump_ops, },
+       { .name = "jnge",       .ops = &jump_ops, },
+       { .name = "jnl",        .ops = &jump_ops, },
+       { .name = "jnle",       .ops = &jump_ops, },
+       { .name = "jno",        .ops = &jump_ops, },
+       { .name = "jnp",        .ops = &jump_ops, },
+       { .name = "jns",        .ops = &jump_ops, },
+       { .name = "jnz",        .ops = &jump_ops, },
+       { .name = "jo",         .ops = &jump_ops, },
+       { .name = "jp",         .ops = &jump_ops, },
+       { .name = "jpe",        .ops = &jump_ops, },
+       { .name = "jpo",        .ops = &jump_ops, },
+       { .name = "jrcxz",      .ops = &jump_ops, },
+       { .name = "js",         .ops = &jump_ops, },
+       { .name = "jz",         .ops = &jump_ops, },
+       { .name = "lea",        .ops = &mov_ops,  },
+       { .name = "lock",       .ops = &lock_ops, },
+       { .name = "mov",        .ops = &mov_ops,  },
+       { .name = "movb",       .ops = &mov_ops,  },
+       { .name = "movdqa",     .ops = &mov_ops,  },
+       { .name = "movl",       .ops = &mov_ops,  },
+       { .name = "movq",       .ops = &mov_ops,  },
+       { .name = "movslq",     .ops = &mov_ops,  },
+       { .name = "movzbl",     .ops = &mov_ops,  },
+       { .name = "movzwl",     .ops = &mov_ops,  },
+       { .name = "nop",        .ops = &nop_ops,  },
+       { .name = "nopl",       .ops = &nop_ops,  },
+       { .name = "nopw",       .ops = &nop_ops,  },
+       { .name = "or",         .ops = &mov_ops,  },
+       { .name = "orl",        .ops = &mov_ops,  },
+       { .name = "test",       .ops = &mov_ops,  },
+       { .name = "testb",      .ops = &mov_ops,  },
+       { .name = "testl",      .ops = &mov_ops,  },
+       { .name = "xadd",       .ops = &mov_ops,  },
+       { .name = "xbeginl",    .ops = &jump_ops, },
+       { .name = "xbeginq",    .ops = &jump_ops, },
+       { .name = "retq",       .ops = &ret_ops,  },
+};
diff --git a/tools/perf/arch/x86/annotate/instructions.c b/tools/perf/arch/x86/annotate/instructions.c
new file mode 100644 (file)
index 0000000..c1625f2
--- /dev/null
@@ -0,0 +1,78 @@
+static struct ins x86__instructions[] = {
+       { .name = "add",        .ops = &mov_ops,  },
+       { .name = "addl",       .ops = &mov_ops,  },
+       { .name = "addq",       .ops = &mov_ops,  },
+       { .name = "addw",       .ops = &mov_ops,  },
+       { .name = "and",        .ops = &mov_ops,  },
+       { .name = "bts",        .ops = &mov_ops,  },
+       { .name = "call",       .ops = &call_ops, },
+       { .name = "callq",      .ops = &call_ops, },
+       { .name = "cmp",        .ops = &mov_ops,  },
+       { .name = "cmpb",       .ops = &mov_ops,  },
+       { .name = "cmpl",       .ops = &mov_ops,  },
+       { .name = "cmpq",       .ops = &mov_ops,  },
+       { .name = "cmpw",       .ops = &mov_ops,  },
+       { .name = "cmpxch",     .ops = &mov_ops,  },
+       { .name = "dec",        .ops = &dec_ops,  },
+       { .name = "decl",       .ops = &dec_ops,  },
+       { .name = "imul",       .ops = &mov_ops,  },
+       { .name = "inc",        .ops = &dec_ops,  },
+       { .name = "incl",       .ops = &dec_ops,  },
+       { .name = "ja",         .ops = &jump_ops, },
+       { .name = "jae",        .ops = &jump_ops, },
+       { .name = "jb",         .ops = &jump_ops, },
+       { .name = "jbe",        .ops = &jump_ops, },
+       { .name = "jc",         .ops = &jump_ops, },
+       { .name = "jcxz",       .ops = &jump_ops, },
+       { .name = "je",         .ops = &jump_ops, },
+       { .name = "jecxz",      .ops = &jump_ops, },
+       { .name = "jg",         .ops = &jump_ops, },
+       { .name = "jge",        .ops = &jump_ops, },
+       { .name = "jl",         .ops = &jump_ops, },
+       { .name = "jle",        .ops = &jump_ops, },
+       { .name = "jmp",        .ops = &jump_ops, },
+       { .name = "jmpq",       .ops = &jump_ops, },
+       { .name = "jna",        .ops = &jump_ops, },
+       { .name = "jnae",       .ops = &jump_ops, },
+       { .name = "jnb",        .ops = &jump_ops, },
+       { .name = "jnbe",       .ops = &jump_ops, },
+       { .name = "jnc",        .ops = &jump_ops, },
+       { .name = "jne",        .ops = &jump_ops, },
+       { .name = "jng",        .ops = &jump_ops, },
+       { .name = "jnge",       .ops = &jump_ops, },
+       { .name = "jnl",        .ops = &jump_ops, },
+       { .name = "jnle",       .ops = &jump_ops, },
+       { .name = "jno",        .ops = &jump_ops, },
+       { .name = "jnp",        .ops = &jump_ops, },
+       { .name = "jns",        .ops = &jump_ops, },
+       { .name = "jnz",        .ops = &jump_ops, },
+       { .name = "jo",         .ops = &jump_ops, },
+       { .name = "jp",         .ops = &jump_ops, },
+       { .name = "jpe",        .ops = &jump_ops, },
+       { .name = "jpo",        .ops = &jump_ops, },
+       { .name = "jrcxz",      .ops = &jump_ops, },
+       { .name = "js",         .ops = &jump_ops, },
+       { .name = "jz",         .ops = &jump_ops, },
+       { .name = "lea",        .ops = &mov_ops,  },
+       { .name = "lock",       .ops = &lock_ops, },
+       { .name = "mov",        .ops = &mov_ops,  },
+       { .name = "movb",       .ops = &mov_ops,  },
+       { .name = "movdqa",     .ops = &mov_ops,  },
+       { .name = "movl",       .ops = &mov_ops,  },
+       { .name = "movq",       .ops = &mov_ops,  },
+       { .name = "movslq",     .ops = &mov_ops,  },
+       { .name = "movzbl",     .ops = &mov_ops,  },
+       { .name = "movzwl",     .ops = &mov_ops,  },
+       { .name = "nop",        .ops = &nop_ops,  },
+       { .name = "nopl",       .ops = &nop_ops,  },
+       { .name = "nopw",       .ops = &nop_ops,  },
+       { .name = "or",         .ops = &mov_ops,  },
+       { .name = "orl",        .ops = &mov_ops,  },
+       { .name = "test",       .ops = &mov_ops,  },
+       { .name = "testb",      .ops = &mov_ops,  },
+       { .name = "testl",      .ops = &mov_ops,  },
+       { .name = "xadd",       .ops = &mov_ops,  },
+       { .name = "xbeginl",    .ops = &jump_ops, },
+       { .name = "xbeginq",    .ops = &jump_ops, },
+       { .name = "retq",       .ops = &ret_ops,  },
+};
index 7276976..095d90a 100644 (file)
@@ -28,20 +28,36 @@ const char  *disassembler_style;
 const char     *objdump_path;
 static regex_t  file_lineno;
 
-static struct ins *ins__find(const char *name);
+static struct ins *ins__find(struct arch *arch, const char *name);
 static int disasm_line__parse(char *line, char **namep, char **rawp);
 
 struct arch {
        const char      *name;
+       struct ins      *instructions;
+       size_t          nr_instructions;
+       bool            sorted_instructions;
        struct          {
                char comment_char;
                char skip_functions_char;
        } objdump;
 };
 
+static struct ins_ops call_ops;
+static struct ins_ops dec_ops;
+static struct ins_ops jump_ops;
+static struct ins_ops mov_ops;
+static struct ins_ops nop_ops;
+static struct ins_ops lock_ops;
+static struct ins_ops ret_ops;
+
+#include "arch/arm/annotate/instructions.c"
+#include "arch/x86/annotate/instructions.c"
+
 static struct arch architectures[] = {
        {
                .name = "arm",
+               .instructions = arm__instructions,
+               .nr_instructions = ARRAY_SIZE(arm__instructions),
                .objdump =  {
                        .comment_char = ';',
                        .skip_functions_char = '+',
@@ -49,6 +65,8 @@ static struct arch architectures[] = {
        },
        {
                .name = "x86",
+               .instructions = x86__instructions,
+               .nr_instructions = ARRAY_SIZE(x86__instructions),
                .objdump =  {
                        .comment_char = '#',
                },
@@ -209,7 +227,7 @@ static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map *
        if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
                goto out_free_ops;
 
-       ops->locked.ins = ins__find(name);
+       ops->locked.ins = ins__find(arch, name);
        free(name);
 
        if (ops->locked.ins == NULL)
@@ -385,99 +403,6 @@ bool ins__is_ret(const struct ins *ins)
        return ins->ops == &ret_ops;
 }
 
-static struct ins instructions[] = {
-       { .name = "add",   .ops  = &mov_ops, },
-       { .name = "addl",  .ops  = &mov_ops, },
-       { .name = "addq",  .ops  = &mov_ops, },
-       { .name = "addw",  .ops  = &mov_ops, },
-       { .name = "and",   .ops  = &mov_ops, },
-#ifdef __arm__
-       { .name = "b",     .ops  = &jump_ops, }, // might also be a call
-       { .name = "bcc",   .ops  = &jump_ops, },
-       { .name = "bcs",   .ops  = &jump_ops, },
-       { .name = "beq",   .ops  = &jump_ops, },
-       { .name = "bge",   .ops  = &jump_ops, },
-       { .name = "bgt",   .ops  = &jump_ops, },
-       { .name = "bhi",   .ops  = &jump_ops, },
-       { .name = "bl",    .ops  = &call_ops, },
-       { .name = "bls",   .ops  = &jump_ops, },
-       { .name = "blt",   .ops  = &jump_ops, },
-       { .name = "blx",   .ops  = &call_ops, },
-       { .name = "bne",   .ops  = &jump_ops, },
-#endif
-       { .name = "bts",   .ops  = &mov_ops, },
-       { .name = "call",  .ops  = &call_ops, },
-       { .name = "callq", .ops  = &call_ops, },
-       { .name = "cmp",   .ops  = &mov_ops, },
-       { .name = "cmpb",  .ops  = &mov_ops, },
-       { .name = "cmpl",  .ops  = &mov_ops, },
-       { .name = "cmpq",  .ops  = &mov_ops, },
-       { .name = "cmpw",  .ops  = &mov_ops, },
-       { .name = "cmpxch", .ops  = &mov_ops, },
-       { .name = "dec",   .ops  = &dec_ops, },
-       { .name = "decl",  .ops  = &dec_ops, },
-       { .name = "imul",  .ops  = &mov_ops, },
-       { .name = "inc",   .ops  = &dec_ops, },
-       { .name = "incl",  .ops  = &dec_ops, },
-       { .name = "ja",    .ops  = &jump_ops, },
-       { .name = "jae",   .ops  = &jump_ops, },
-       { .name = "jb",    .ops  = &jump_ops, },
-       { .name = "jbe",   .ops  = &jump_ops, },
-       { .name = "jc",    .ops  = &jump_ops, },
-       { .name = "jcxz",  .ops  = &jump_ops, },
-       { .name = "je",    .ops  = &jump_ops, },
-       { .name = "jecxz", .ops  = &jump_ops, },
-       { .name = "jg",    .ops  = &jump_ops, },
-       { .name = "jge",   .ops  = &jump_ops, },
-       { .name = "jl",    .ops  = &jump_ops, },
-       { .name = "jle",   .ops  = &jump_ops, },
-       { .name = "jmp",   .ops  = &jump_ops, },
-       { .name = "jmpq",  .ops  = &jump_ops, },
-       { .name = "jna",   .ops  = &jump_ops, },
-       { .name = "jnae",  .ops  = &jump_ops, },
-       { .name = "jnb",   .ops  = &jump_ops, },
-       { .name = "jnbe",  .ops  = &jump_ops, },
-       { .name = "jnc",   .ops  = &jump_ops, },
-       { .name = "jne",   .ops  = &jump_ops, },
-       { .name = "jng",   .ops  = &jump_ops, },
-       { .name = "jnge",  .ops  = &jump_ops, },
-       { .name = "jnl",   .ops  = &jump_ops, },
-       { .name = "jnle",  .ops  = &jump_ops, },
-       { .name = "jno",   .ops  = &jump_ops, },
-       { .name = "jnp",   .ops  = &jump_ops, },
-       { .name = "jns",   .ops  = &jump_ops, },
-       { .name = "jnz",   .ops  = &jump_ops, },
-       { .name = "jo",    .ops  = &jump_ops, },
-       { .name = "jp",    .ops  = &jump_ops, },
-       { .name = "jpe",   .ops  = &jump_ops, },
-       { .name = "jpo",   .ops  = &jump_ops, },
-       { .name = "jrcxz", .ops  = &jump_ops, },
-       { .name = "js",    .ops  = &jump_ops, },
-       { .name = "jz",    .ops  = &jump_ops, },
-       { .name = "lea",   .ops  = &mov_ops, },
-       { .name = "lock",  .ops  = &lock_ops, },
-       { .name = "mov",   .ops  = &mov_ops, },
-       { .name = "movb",  .ops  = &mov_ops, },
-       { .name = "movdqa",.ops  = &mov_ops, },
-       { .name = "movl",  .ops  = &mov_ops, },
-       { .name = "movq",  .ops  = &mov_ops, },
-       { .name = "movslq", .ops  = &mov_ops, },
-       { .name = "movzbl", .ops  = &mov_ops, },
-       { .name = "movzwl", .ops  = &mov_ops, },
-       { .name = "nop",   .ops  = &nop_ops, },
-       { .name = "nopl",  .ops  = &nop_ops, },
-       { .name = "nopw",  .ops  = &nop_ops, },
-       { .name = "or",    .ops  = &mov_ops, },
-       { .name = "orl",   .ops  = &mov_ops, },
-       { .name = "test",  .ops  = &mov_ops, },
-       { .name = "testb", .ops  = &mov_ops, },
-       { .name = "testl", .ops  = &mov_ops, },
-       { .name = "xadd",  .ops  = &mov_ops, },
-       { .name = "xbeginl", .ops  = &jump_ops, },
-       { .name = "xbeginq", .ops  = &jump_ops, },
-       { .name = "retq",  .ops  = &ret_ops, },
-};
-
 static int ins__key_cmp(const void *name, const void *insp)
 {
        const struct ins *ins = insp;
@@ -493,24 +418,23 @@ static int ins__cmp(const void *a, const void *b)
        return strcmp(ia->name, ib->name);
 }
 
-static void ins__sort(void)
+static void ins__sort(struct arch *arch)
 {
-       const int nmemb = ARRAY_SIZE(instructions);
+       const int nmemb = arch->nr_instructions;
 
-       qsort(instructions, nmemb, sizeof(struct ins), ins__cmp);
+       qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp);
 }
 
-static struct ins *ins__find(const char *name)
+static struct ins *ins__find(struct arch *arch, const char *name)
 {
-       const int nmemb = ARRAY_SIZE(instructions);
-       static bool sorted;
+       const int nmemb = arch->nr_instructions;
 
-       if (!sorted) {
-               ins__sort();
-               sorted = true;
+       if (!arch->sorted_instructions) {
+               ins__sort(arch);
+               arch->sorted_instructions = true;
        }
 
-       return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp);
+       return bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp);
 }
 
 static int arch__key_cmp(const void *name, const void *archp)
@@ -767,7 +691,7 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
 
 static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map)
 {
-       dl->ins = ins__find(dl->name);
+       dl->ins = ins__find(arch, dl->name);
 
        if (dl->ins == NULL)
                return;