aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/annotate.c
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2016-09-05 15:08:12 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-09-08 12:44:03 -0400
commit70fbe0574558e934f93bde26e4949c8c206bae43 (patch)
treece40ec348fa249f9b2b80cd75cf3b4a495538cf9 /tools/perf/util/annotate.c
parentd7e404af115bb4996afa4a0236020969ab007554 (diff)
perf annotate: Add branch stack / basic block
I wanted to know the hottest path through a function and figured the branch-stack (LBR) information should be able to help out with that. The below uses the branch-stack to create basic blocks and generate statistics from them. from to branch_i * ----> * | | block v * ----> * from to branch_i+1 The blocks are broken down into non-overlapping ranges, while tracking if the start of each range is an entry point and/or the end of a range is a branch. Each block iterates all ranges it covers (while splitting where required to exactly match the block) and increments the 'coverage' count. For the range including the branch we increment the taken counter, as well as the pred counter if flags.predicted. Using these number we can find if an instruction: - had coverage; given by: br->coverage / br->sym->max_coverage This metric ensures each symbol has a 100% spot, which reflects the observation that each symbol must have a most covered/hottest block. - is a branch target: br->is_target && br->start == add - for targets, how much of a branch's coverages comes from it: target->entry / branch->coverage - is a branch: br->is_branch && br->end == addr - for branches, how often it was taken: br->taken / br->coverage after all, all execution that didn't take the branch would have incremented the coverage and continued onward to a later branch. - for branches, how often it was predicted: br->pred / br->taken The coverage percentage is used to color the address and asm sections; for low (<1%) coverage we use NORMAL (uncolored), indicating that these instructions are not 'important'. For high coverage (>75%) we color the address RED. For each branch, we add an asm comment after the instruction with information on how often it was taken and predicted. Output looks like (sans color, which does loose a lot of the information :/) $ perf record --branch-filter u,any -e cycles:p ./branches 27 $ perf annotate branches Percent | Source code & Disassembly of branches for cycles:pu (217 samples) --------------------------------------------------------------------------------- : branches(): 0.00 : 40057a: push %rbp 0.00 : 40057b: mov %rsp,%rbp 0.00 : 40057e: sub $0x20,%rsp 0.00 : 400582: mov %rdi,-0x18(%rbp) 0.00 : 400586: mov %rsi,-0x20(%rbp) 0.00 : 40058a: mov -0x18(%rbp),%rax 0.00 : 40058e: mov %rax,-0x10(%rbp) 0.00 : 400592: movq $0x0,-0x8(%rbp) 0.00 : 40059a: jmpq 400656 <branches+0xdc> 1.84 : 40059f: mov -0x10(%rbp),%rax # +100.00% 3.23 : 4005a3: and $0x1,%eax 1.84 : 4005a6: test %rax,%rax 0.00 : 4005a9: je 4005bf <branches+0x45> # -54.50% (p:42.00%) 0.46 : 4005ab: mov 0x200bbe(%rip),%rax # 601170 <acc> 12.90 : 4005b2: add $0x1,%rax 2.30 : 4005b6: mov %rax,0x200bb3(%rip) # 601170 <acc> 0.46 : 4005bd: jmp 4005d1 <branches+0x57> # -100.00% (p:100.00%) 0.92 : 4005bf: mov 0x200baa(%rip),%rax # 601170 <acc> # +49.54% 13.82 : 4005c6: sub $0x1,%rax 0.46 : 4005ca: mov %rax,0x200b9f(%rip) # 601170 <acc> 2.30 : 4005d1: mov -0x10(%rbp),%rax # +50.46% 0.46 : 4005d5: mov %rax,%rdi 0.46 : 4005d8: callq 400526 <lfsr> # -100.00% (p:100.00%) 0.00 : 4005dd: mov %rax,-0x10(%rbp) # +100.00% 0.92 : 4005e1: mov -0x18(%rbp),%rax 0.00 : 4005e5: and $0x1,%eax 0.00 : 4005e8: test %rax,%rax 0.00 : 4005eb: je 4005ff <branches+0x85> # -100.00% (p:100.00%) 0.00 : 4005ed: mov 0x200b7c(%rip),%rax # 601170 <acc> 0.00 : 4005f4: shr $0x2,%rax 0.00 : 4005f8: mov %rax,0x200b71(%rip) # 601170 <acc> 0.00 : 4005ff: mov -0x10(%rbp),%rax # +100.00% 7.37 : 400603: and $0x1,%eax 3.69 : 400606: test %rax,%rax 0.00 : 400609: jne 400612 <branches+0x98> # -59.25% (p:42.99%) 1.84 : 40060b: mov $0x1,%eax 14.29 : 400610: jmp 400617 <branches+0x9d> # -100.00% (p:100.00%) 1.38 : 400612: mov $0x0,%eax # +57.65% 10.14 : 400617: test %al,%al # +42.35% 0.00 : 400619: je 40062f <branches+0xb5> # -57.65% (p:100.00%) 0.46 : 40061b: mov 0x200b4e(%rip),%rax # 601170 <acc> 2.76 : 400622: sub $0x1,%rax 0.00 : 400626: mov %rax,0x200b43(%rip) # 601170 <acc> 0.46 : 40062d: jmp 400641 <branches+0xc7> # -100.00% (p:100.00%) 0.92 : 40062f: mov 0x200b3a(%rip),%rax # 601170 <acc> # +56.13% 2.30 : 400636: add $0x1,%rax 0.92 : 40063a: mov %rax,0x200b2f(%rip) # 601170 <acc> 0.92 : 400641: mov -0x10(%rbp),%rax # +43.87% 2.30 : 400645: mov %rax,%rdi 0.00 : 400648: callq 400526 <lfsr> # -100.00% (p:100.00%) 0.00 : 40064d: mov %rax,-0x10(%rbp) # +100.00% 1.84 : 400651: addq $0x1,-0x8(%rbp) 0.92 : 400656: mov -0x8(%rbp),%rax 5.07 : 40065a: cmp -0x20(%rbp),%rax 0.00 : 40065e: jb 40059f <branches+0x25> # -100.00% (p:100.00%) 0.00 : 400664: nop 0.00 : 400665: leaveq 0.00 : 400666: retq (Note: the --branch-filter u,any was used to avoid spurious target and branch points due to interrupts/faults, they show up as very small -/+ annotations on 'weird' locations) Committer note: Please take a look at: http://vger.kernel.org/~acme/perf/annotate_basic_blocks.png To see the colors. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Anshuman Khandual <khandual@linux.vnet.ibm.com> Cc: David Carrillo-Cisneros <davidcc@google.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kan Liang <kan.liang@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Stephane Eranian <eranian@google.com> [ Moved sym->max_coverage to 'struct annotate', aka symbol__annotate(sym) ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r--tools/perf/util/annotate.c93
1 files changed, 91 insertions, 2 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 2ff6bd74e435..7a80c7362a03 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -17,6 +17,7 @@
17#include "debug.h" 17#include "debug.h"
18#include "annotate.h" 18#include "annotate.h"
19#include "evsel.h" 19#include "evsel.h"
20#include "block-range.h"
20#include <regex.h> 21#include <regex.h>
21#include <pthread.h> 22#include <pthread.h>
22#include <linux/bitops.h> 23#include <linux/bitops.h>
@@ -859,6 +860,89 @@ double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
859 return percent; 860 return percent;
860} 861}
861 862
863static const char *annotate__address_color(struct block_range *br)
864{
865 double cov = block_range__coverage(br);
866
867 if (cov >= 0) {
868 /* mark red for >75% coverage */
869 if (cov > 0.75)
870 return PERF_COLOR_RED;
871
872 /* mark dull for <1% coverage */
873 if (cov < 0.01)
874 return PERF_COLOR_NORMAL;
875 }
876
877 return PERF_COLOR_MAGENTA;
878}
879
880static const char *annotate__asm_color(struct block_range *br)
881{
882 double cov = block_range__coverage(br);
883
884 if (cov >= 0) {
885 /* mark dull for <1% coverage */
886 if (cov < 0.01)
887 return PERF_COLOR_NORMAL;
888 }
889
890 return PERF_COLOR_BLUE;
891}
892
893static void annotate__branch_printf(struct block_range *br, u64 addr)
894{
895 bool emit_comment = true;
896
897 if (!br)
898 return;
899
900#if 1
901 if (br->is_target && br->start == addr) {
902 struct block_range *branch = br;
903 double p;
904
905 /*
906 * Find matching branch to our target.
907 */
908 while (!branch->is_branch)
909 branch = block_range__next(branch);
910
911 p = 100 *(double)br->entry / branch->coverage;
912
913 if (p > 0.1) {
914 if (emit_comment) {
915 emit_comment = false;
916 printf("\t#");
917 }
918
919 /*
920 * The percentage of coverage joined at this target in relation
921 * to the next branch.
922 */
923 printf(" +%.2f%%", p);
924 }
925 }
926#endif
927 if (br->is_branch && br->end == addr) {
928 double p = 100*(double)br->taken / br->coverage;
929
930 if (p > 0.1) {
931 if (emit_comment) {
932 emit_comment = false;
933 printf("\t#");
934 }
935
936 /*
937 * The percentage of coverage leaving at this branch, and
938 * its prediction ratio.
939 */
940 printf(" -%.2f%% (p:%.2f%%)", p, 100*(double)br->pred / br->taken);
941 }
942 }
943}
944
945
862static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, 946static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
863 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, 947 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
864 int max_lines, struct disasm_line *queue) 948 int max_lines, struct disasm_line *queue)
@@ -878,6 +962,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
878 s64 offset = dl->offset; 962 s64 offset = dl->offset;
879 const u64 addr = start + offset; 963 const u64 addr = start + offset;
880 struct disasm_line *next; 964 struct disasm_line *next;
965 struct block_range *br;
881 966
882 next = disasm__get_next_ip_line(&notes->src->source, dl); 967 next = disasm__get_next_ip_line(&notes->src->source, dl);
883 968
@@ -947,8 +1032,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
947 } 1032 }
948 1033
949 printf(" : "); 1034 printf(" : ");
950 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); 1035
951 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); 1036 br = block_range__find(addr);
1037 color_fprintf(stdout, annotate__address_color(br), " %" PRIx64 ":", addr);
1038 color_fprintf(stdout, annotate__asm_color(br), "%s", dl->line);
1039 annotate__branch_printf(br, addr);
1040 printf("\n");
952 1041
953 if (ppercents != &percent) 1042 if (ppercents != &percent)
954 free(ppercents); 1043 free(ppercents);