From e8ea1561952b04276cf4c02500e363de76c142aa Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 May 2012 12:28:55 -0300 Subject: [PATCH 1/8] perf annotate: Use raw form for register indirect call instructions callq *0x10(%rax) was being rendered in simplified mode as: callq *10 I.e. hexa, but without the 0x and omitting the register. In such cases just use the raw form. Reported-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-m91tv004h2m1fkfgu6ovx3hb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 6b4146b40a20e..9a020d1e01806 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -56,6 +56,12 @@ static int call__parse(struct ins_operands *ops) return ops->target.name == NULL ? -1 : 0; indirect_call: + tok = strchr(endptr, '('); + if (tok != NULL) { + ops->target.addr = 0; + return 0; + } + tok = strchr(endptr, '*'); if (tok == NULL) return -1; @@ -70,6 +76,9 @@ static int call__scnprintf(struct ins *ins, char *bf, size_t size, if (ops->target.name) return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name); + if (ops->target.addr == 0) + return ins__raw_scnprintf(ins, bf, size, ops); + return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr); } From 6de783b6f50f7f1db18a3fda0aa34b2e84b5771d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 May 2012 16:48:49 -0300 Subject: [PATCH 2/8] perf annotate: Resolve symbols using objdump comment This: mov 0x95bbb6(%rip),%ecx # ffffffff81ae8d04 Becomes: mov d_hash_shift,%ecx Ditto for many more instructions that take two operands. Requested-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-i5opbyai2x6mn9e5yjmhx9k6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 112 +++++++++++++++++++++++++++++++++++++ tools/perf/util/annotate.h | 8 ++- 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 9a020d1e01806..82c7f630f8a8b 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -122,6 +122,89 @@ bool ins__is_jump(const struct ins *ins) return ins->ops == &jump_ops; } +static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) +{ + char *endptr, *name, *t; + + if (strstr(raw, "(%rip)") == NULL) + return 0; + + *addrp = strtoull(comment, &endptr, 16); + name = strchr(endptr, '<'); + if (name == NULL) + return -1; + + name++; + + t = strchr(name, '>'); + if (t == NULL) + return 0; + + *t = '\0'; + *namep = strdup(name); + *t = '>'; + + return 0; +} + +static int mov__parse(struct ins_operands *ops) +{ + char *s = strchr(ops->raw, ','), *target, *comment, prev; + + if (s == NULL) + return -1; + + *s = '\0'; + ops->source.raw = strdup(ops->raw); + *s = ','; + + if (ops->source.raw == NULL) + return -1; + + target = ++s; + + while (s[0] != '\0' && !isspace(s[0])) + ++s; + prev = *s; + *s = '\0'; + + ops->target.raw = strdup(target); + *s = prev; + + if (ops->target.raw == NULL) + goto out_free_source; + + comment = strchr(s, '#'); + if (comment == NULL) + return 0; + + while (comment[0] != '\0' && isspace(comment[0])) + ++comment; + + comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); + comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); + + return 0; + +out_free_source: + free(ops->source.raw); + ops->source.raw = NULL; + return -1; +} + +static int mov__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops) +{ + return scnprintf(bf, size, "%-6.6s %s,%s", ins->name, + ops->source.name ?: ops->source.raw, + ops->target.name ?: ops->target.raw); +} + +static struct ins_ops mov_ops = { + .parse = mov__parse, + .scnprintf = mov__scnprintf, +}; + static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size, struct ins_operands *ops __used) { @@ -136,8 +219,20 @@ static struct ins_ops nop_ops = { * Must be sorted by name! */ 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, }, { .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 = "imul", .ops = &mov_ops, }, { .name = "ja", .ops = &jump_ops, }, { .name = "jae", .ops = &jump_ops, }, { .name = "jb", .ops = &jump_ops, }, @@ -173,9 +268,23 @@ static struct ins instructions[] = { { .name = "jrcxz", .ops = &jump_ops, }, { .name = "js", .ops = &jump_ops, }, { .name = "jz", .ops = &jump_ops, }, + { .name = "lea", .ops = &mov_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, }, }; static int ins__cmp(const void *name, const void *insp) @@ -323,6 +432,9 @@ void disasm_line__free(struct disasm_line *dl) { free(dl->line); free(dl->name); + free(dl->ops.source.raw); + free(dl->ops.source.name); + free(dl->ops.target.raw); free(dl->ops.target.name); free(dl); } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index bb0a9f27165b7..066d31d696dfb 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -13,10 +13,16 @@ struct ins; struct ins_operands { char *raw; struct { + char *raw; char *name; - u64 offset; u64 addr; + u64 offset; } target; + struct { + char *raw; + char *name; + u64 addr; + } source; }; struct ins_ops { From a43712c4720c8df4bad7d3760c67086168553b05 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 May 2012 17:21:09 -0300 Subject: [PATCH 3/8] perf annotate: Resolve symbols using objdump comment for single op ins Starting with inc, incl, dec, decl. Requested-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-jvh0jspefr5jyn0l7qko12st@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 82c7f630f8a8b..a6109dc3a81ea 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -205,6 +205,47 @@ static struct ins_ops mov_ops = { .scnprintf = mov__scnprintf, }; +static int dec__parse(struct ins_operands *ops) +{ + char *target, *comment, *s, prev; + + target = s = ops->raw; + + while (s[0] != '\0' && !isspace(s[0])) + ++s; + prev = *s; + *s = '\0'; + + ops->target.raw = strdup(target); + *s = prev; + + if (ops->target.raw == NULL) + return -1; + + comment = strchr(s, '#'); + if (comment == NULL) + return 0; + + while (comment[0] != '\0' && isspace(comment[0])) + ++comment; + + comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); + + return 0; +} + +static int dec__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops) +{ + return scnprintf(bf, size, "%-6.6s %s", ins->name, + ops->target.name ?: ops->target.raw); +} + +static struct ins_ops dec_ops = { + .parse = dec__parse, + .scnprintf = dec__scnprintf, +}; + static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size, struct ins_operands *ops __used) { @@ -232,7 +273,11 @@ static struct ins instructions[] = { { .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, }, From 7a997fe4019f556a81530d3a737d817a2b0d622f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 12 May 2012 13:15:34 -0300 Subject: [PATCH 4/8] perf annotate: Augment lock instruction output It just chops off the 'lock' and uses the ins__find, etc machinery to call instruction specific parsers/beautifiers. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-4913ba2dzakz5rivgumosqbh@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 127 ++++++++++++++++++++++++++++--------- tools/perf/util/annotate.h | 16 +++-- 2 files changed, 109 insertions(+), 34 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a6109dc3a81ea..1dce09874d938 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -18,6 +18,9 @@ const char *disassembler_style; +static struct ins *ins__find(const char *name); +static int disasm_line__parse(char *line, char **namep, char **rawp); + static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { @@ -147,6 +150,53 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) return 0; } +static int lock__parse(struct ins_operands *ops) +{ + char *name; + + ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); + if (ops->locked.ops == NULL) + return 0; + + if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) + goto out_free_ops; + + ops->locked.ins = ins__find(name); + if (ops->locked.ins == NULL) + goto out_free_ops; + + if (!ops->locked.ins->ops) + return 0; + + if (ops->locked.ins->ops->parse) + ops->locked.ins->ops->parse(ops->locked.ops); + + return 0; + +out_free_ops: + free(ops->locked.ops); + ops->locked.ops = NULL; + return 0; +} + +static int lock__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops) +{ + int printed; + + if (ops->locked.ins == NULL) + return ins__raw_scnprintf(ins, bf, size, ops); + + printed = scnprintf(bf, size, "%-6.6s ", ins->name); + return printed + ins__scnprintf(ops->locked.ins, bf + printed, + size - printed, ops->locked.ops); +} + +static struct ins_ops lock_ops = { + .parse = lock__parse, + .scnprintf = lock__scnprintf, +}; + static int mov__parse(struct ins_operands *ops) { char *s = strchr(ops->raw, ','), *target, *comment, prev; @@ -265,6 +315,7 @@ static struct ins instructions[] = { { .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, }, @@ -314,6 +365,7 @@ static struct ins instructions[] = { { .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, }, @@ -330,6 +382,7 @@ static struct ins instructions[] = { { .name = "test", .ops = &mov_ops, }, { .name = "testb", .ops = &mov_ops, }, { .name = "testl", .ops = &mov_ops, }, + { .name = "xadd", .ops = &mov_ops, }, }; static int ins__cmp(const void *name, const void *insp) @@ -420,6 +473,44 @@ static void disasm_line__init_ins(struct disasm_line *dl) dl->ins->ops->parse(&dl->ops); } +static int disasm_line__parse(char *line, char **namep, char **rawp) +{ + char *name = line, tmp; + + while (isspace(name[0])) + ++name; + + if (name[0] == '\0') + return -1; + + *rawp = name + 1; + + while ((*rawp)[0] != '\0' && !isspace((*rawp)[0])) + ++*rawp; + + tmp = (*rawp)[0]; + (*rawp)[0] = '\0'; + *namep = strdup(name); + + if (*namep == NULL) + goto out_free_name; + + (*rawp)[0] = tmp; + + if ((*rawp)[0] != '\0') { + (*rawp)++; + while (isspace((*rawp)[0])) + ++(*rawp); + } + + return 0; + +out_free_name: + free(*namep); + *namep = NULL; + return -1; +} + static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) { struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); @@ -431,35 +522,9 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs goto out_delete; if (offset != -1) { - char *name = dl->line, tmp; - - while (isspace(name[0])) - ++name; - - if (name[0] == '\0') - goto out_delete; - - dl->ops.raw = name + 1; - - while (dl->ops.raw[0] != '\0' && - !isspace(dl->ops.raw[0])) - ++dl->ops.raw; - - tmp = dl->ops.raw[0]; - dl->ops.raw[0] = '\0'; - dl->name = strdup(name); - - if (dl->name == NULL) + if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) goto out_free_line; - dl->ops.raw[0] = tmp; - - if (dl->ops.raw[0] != '\0') { - dl->ops.raw++; - while (isspace(dl->ops.raw[0])) - ++dl->ops.raw; - } - disasm_line__init_ins(dl); } } @@ -477,8 +542,12 @@ void disasm_line__free(struct disasm_line *dl) { free(dl->line); free(dl->name); - free(dl->ops.source.raw); - free(dl->ops.source.name); + if (dl->ins && dl->ins->ops == &lock_ops) { + free(dl->ops.locked.ops); + } else { + free(dl->ops.source.raw); + free(dl->ops.source.name); + } free(dl->ops.target.raw); free(dl->ops.target.name); free(dl); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 066d31d696dfb..b79d3260647c6 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -18,11 +18,17 @@ struct ins_operands { u64 addr; u64 offset; } target; - struct { - char *raw; - char *name; - u64 addr; - } source; + union { + struct { + char *raw; + char *name; + u64 addr; + } source; + struct { + struct ins *ins; + struct ins_operands *ops; + } locked; + }; }; struct ins_ops { From c46219ac34f0f365bac700ca6a10ef979c643233 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 12 May 2012 13:26:20 -0300 Subject: [PATCH 5/8] perf annotate: Introduce ->free() method in ins_ops So that we don't special case disasm_line__free, allowing each instruction class to provide an specialized destructor, like is needed for 'lock'. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-xxw4vs5n077tf35jsvjzylhb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 28 ++++++++++++++++++++-------- tools/perf/util/annotate.h | 1 + 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 1dce09874d938..8069dfb5ba777 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -21,6 +21,14 @@ const char *disassembler_style; static struct ins *ins__find(const char *name); static int disasm_line__parse(char *line, char **namep, char **rawp); +static void ins__delete(struct ins_operands *ops) +{ + free(ops->source.raw); + free(ops->source.name); + free(ops->target.raw); + free(ops->target.name); +} + static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { @@ -192,7 +200,15 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size, size - printed, ops->locked.ops); } +static void lock__delete(struct ins_operands *ops) +{ + free(ops->locked.ops); + free(ops->target.raw); + free(ops->target.name); +} + static struct ins_ops lock_ops = { + .free = lock__delete, .parse = lock__parse, .scnprintf = lock__scnprintf, }; @@ -542,14 +558,10 @@ void disasm_line__free(struct disasm_line *dl) { free(dl->line); free(dl->name); - if (dl->ins && dl->ins->ops == &lock_ops) { - free(dl->ops.locked.ops); - } else { - free(dl->ops.source.raw); - free(dl->ops.source.name); - } - free(dl->ops.target.raw); - free(dl->ops.target.name); + if (dl->ins && dl->ins->ops->free) + dl->ins->ops->free(&dl->ops); + else + ins__delete(&dl->ops); free(dl); } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index b79d3260647c6..78a5692dd718d 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -32,6 +32,7 @@ struct ins_operands { }; struct ins_ops { + void (*free)(struct ins_operands *ops); int (*parse)(struct ins_operands *ops); int (*scnprintf)(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); From 7d5b12f5a01d338d23874c7c242a74813a8848b2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 12 May 2012 13:40:52 -0300 Subject: [PATCH 6/8] perf annotate browser: Count the numbers of jump sources to a target Instead of simply marking an offset as a jump target. So that we can implement a new feature: showing "jumpy" targets, I.e. addresses that lots of places jump to. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-vc7b0u5yxgrubig0q61ayhxf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 06367c1df7201..446362677840c 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -16,7 +16,7 @@ struct browser_disasm_line { double percent; u32 idx; int idx_asm; - bool jump_target; + int jump_sources; }; struct annotate_browser { @@ -98,7 +98,7 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (!ab->use_offset) { printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); } else { - if (bdl->jump_target) { + if (bdl->jump_sources) { printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", ab->addr_width, addr); } else { @@ -707,7 +707,7 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser continue; bdlt = disasm_line__browser(dlt); - bdlt->jump_target = true; + ++bdlt->jump_sources; } } From 2402e4a936a02a24772c9823e1fd2085f0e8ec93 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 12 May 2012 16:21:53 -0300 Subject: [PATCH 7/8] perf annotate browser: Show 'jumpy' functions Just press 'J' and see how many places jump to jump targets. The hottest jump target appears in red, targets with more than one source have a different color than single source jump targets. Suggested-by: Arjan van de Ven Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-7452y0dmc02a20ooins7rn79@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 65 ++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 446362677840c..547bd352118d9 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -28,11 +28,16 @@ struct annotate_browser { u64 start; int nr_asm_entries; int nr_entries; + int max_jump_sources; + int nr_jumps; bool hide_src_code; bool use_offset; bool jump_arrows; + bool show_nr_jumps; bool searching_backwards; u8 addr_width; + u8 jumps_width; + u8 target_width; u8 min_addr_width; u8 max_addr_width; char search_bf[128]; @@ -55,6 +60,25 @@ static bool disasm_line__filter(struct ui_browser *browser, void *entry) return false; } +static int annotate_browser__jumps_percent_color(struct annotate_browser *browser, + int nr, bool current) +{ + if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed)) + return HE_COLORSET_SELECTED; + if (nr == browser->max_jump_sources) + return HE_COLORSET_TOP; + if (nr > 1) + return HE_COLORSET_MEDIUM; + return HE_COLORSET_NORMAL; +} + +static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser, + int nr, bool current) +{ + int color = annotate_browser__jumps_percent_color(browser, nr, current); + return ui_browser__set_color(&browser->b, color); +} + static void annotate_browser__write(struct ui_browser *self, void *entry, int row) { struct annotate_browser *ab = container_of(self, struct annotate_browser, b); @@ -99,8 +123,19 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr); } else { if (bdl->jump_sources) { + if (ab->show_nr_jumps) { + int prev; + printed = scnprintf(bf, sizeof(bf), "%*d ", + ab->jumps_width, + bdl->jump_sources); + prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources, + current_entry); + slsmg_write_nstring(bf, printed); + ui_browser__set_color(self, prev); + } + printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ", - ab->addr_width, addr); + ab->target_width, addr); } else { printed = scnprintf(bf, sizeof(bf), "%*s ", ab->addr_width, " "); @@ -615,13 +650,20 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, case 'o': self->use_offset = !self->use_offset; if (self->use_offset) - self->addr_width = self->min_addr_width; + self->target_width = self->min_addr_width; else - self->addr_width = self->max_addr_width; + self->target_width = self->max_addr_width; +update_addr_width: + self->addr_width = self->target_width; + if (self->show_nr_jumps) + self->addr_width += self->jumps_width + 1; continue; case 'j': self->jump_arrows = !self->jump_arrows; continue; + case 'J': + self->show_nr_jumps = !self->show_nr_jumps; + goto update_addr_width; case '/': if (annotate_browser__search(self, delay_secs)) { show_help: @@ -707,11 +749,23 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser continue; bdlt = disasm_line__browser(dlt); - ++bdlt->jump_sources; + if (++bdlt->jump_sources > browser->max_jump_sources) + browser->max_jump_sources = bdlt->jump_sources; + + ++browser->nr_jumps; } } +static inline int width_jumps(int n) +{ + if (n >= 100) + return 5; + if (n / 10) + return 2; + return 1; +} + int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, void(*timer)(void *arg), void *arg, int delay_secs) @@ -784,8 +838,9 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, annotate_browser__mark_jump_targets(&browser, size); - browser.addr_width = browser.min_addr_width = hex_width(size); + browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); browser.max_addr_width = hex_width(sym->end); + browser.jumps_width = width_jumps(browser.max_jump_sources); browser.b.nr_entries = browser.nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ From 54e7a4e88eed9ac423e22a259ec51a973fd59bab Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 12 May 2012 16:36:55 -0300 Subject: [PATCH 8/8] perf annotate browser: Add key bindings help window Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-1txmtzf71eqie5xcukbfxors@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 547bd352118d9..6e0ef79be1690 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -581,10 +581,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, struct rb_node *nd = NULL; struct map_symbol *ms = self->b.priv; struct symbol *sym = ms->sym; - const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, " - "H: Hottest line, ->/ENTER: Line action, " - "O: Offset view, " - "S: Source view"; + const char *help = "Press 'h' for help on key bindings"; int key; if (ui_browser__show(&self->b, sym->name, help) < 0) @@ -637,16 +634,30 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, else nd = self->curr_hot; break; - case 'H': + case K_F1: case 'h': + ui_browser__help_window(&self->b, + "UP/DOWN/PGUP\n" + "PGDN/SPACE Navigate\n" + "q/ESC/CTRL+C Exit\n\n" + "-> Go to target\n" + "<- Exit\n" + "h Cycle thru hottest instructions\n" + "j Toggle showing jump to target arrows\n" + "J Toggle showing number of jump sources on targets\n" + "n Search next string\n" + "o Toggle disassembler output/simplified view\n" + "s Toggle source code view\n" + "/ Search string\n" + "? Search previous string\n"); + continue; + case 'H': nd = self->curr_hot; break; - case 'S': case 's': if (annotate_browser__toggle_source(self)) ui_helpline__puts(help); continue; - case 'O': case 'o': self->use_offset = !self->use_offset; if (self->use_offset)