Messages in this thread | | | Date | Mon, 24 Jul 2017 14:39:53 -0300 | From | Arnaldo Carvalho de Melo <> | Subject | Re: [PATCH] perf report: Tag branch type/flag on "to" and tag cycles on "from" |
| |
Em Mon, Jul 24, 2017 at 07:09:07PM +0800, Jin Yao escreveu: > Current --branch-history LBR annotation displays confused > data. For example, each cycles report is duplicated on both > "from" and "to" entries.
Andi, can you take a look at this? An Acked-by you or Reviewed-by would be great to have,
- Arnaldo
> For example: > perf report --branch-history --no-children --stdio > > --2.32%--main div.c:39 (COND_BWD CROSS_2M predicted:49.7% cycles:1) > main div.c:44 (predicted:49.7% cycles:1) > main div.c:42 (RET CROSS_2M cycles:2) > compute_flag div.c:28 (cycles:2) > compute_flag div.c:27 (RET CROSS_2M cycles:1) > rand rand.c:28 (cycles:1) > rand rand.c:28 (RET CROSS_2M cycles:1) > __random random.c:298 (cycles:1) > __random random.c:297 (COND_BWD CROSS_2M cycles:1) > __random random.c:295 (cycles:1) > __random random.c:295 (COND_BWD CROSS_2M cycles:1) > __random random.c:295 (cycles:1) > __random random.c:295 (RET CROSS_2M cycles:9) > > The cycles should be tagged only on the "from". It's for > the code block that ends with "from", not for "to". > > Another issue is the "predicted:49.7%" is duplicated too > (tag on both "from" and "to"). > > This patch tags the branch type/flag on "to" and tag the > cycles on "from". > > For example: > > --2.32%--main div.c:39 (COND_BWD CROSS_2M predicted:49.7%) > main div.c:44 (cycles:1) > main div.c:42 (RET CROSS_2M) > compute_flag div.c:28 (cycles:2) > compute_flag div.c:27 (RET CROSS_2M) > rand rand.c:28 (cycles:1) > rand rand.c:28 (RET CROSS_2M) > __random random.c:298 (cycles:1) > __random random.c:297 (COND_BWD CROSS_2M) > __random random.c:295 (cycles:1) > __random random.c:295 (COND_BWD CROSS_2M) > __random random.c:295 (cycles:1) > __random random.c:295 (RET CROSS_2M) > | > --2.23%--__random_r random_r.c:392 (cycles:9) > > In this example, The "main div.c:39 (COND_BWD CROSS_2M predicted:49.7%)" > is "to" of branch and "main div.c:44 (cycles:1)" is "from" of branch. > It should be easier for understanding than before. > > Signed-off-by: Jin Yao <yao.jin@linux.intel.com> > --- > tools/perf/util/branch.h | 11 ++-- > tools/perf/util/callchain.c | 148 +++++++++++++++++++++++++++++++------------- > 2 files changed, 111 insertions(+), 48 deletions(-) > > diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h > index 686f2b6..1e3c7c5 100644 > --- a/tools/perf/util/branch.h > +++ b/tools/perf/util/branch.h > @@ -5,11 +5,12 @@ > #include "../perf.h" > > struct branch_type_stat { > - u64 counts[PERF_BR_MAX]; > - u64 cond_fwd; > - u64 cond_bwd; > - u64 cross_4k; > - u64 cross_2m; > + bool branch_to; > + u64 counts[PERF_BR_MAX]; > + u64 cond_fwd; > + u64 cond_bwd; > + u64 cross_4k; > + u64 cross_2m; > }; > > struct branch_flags; > diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c > index 22d413a..8c17ea6 100644 > --- a/tools/perf/util/callchain.c > +++ b/tools/perf/util/callchain.c > @@ -563,20 +563,33 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor) > if (cursor_node->branch) { > call->branch_count = 1; > > - if (cursor_node->branch_flags.predicted) > - call->predicted_count = 1; > - > - if (cursor_node->branch_flags.abort) > - call->abort_count = 1; > - > - call->cycles_count = cursor_node->branch_flags.cycles; > - call->iter_count = cursor_node->nr_loop_iter; > - call->samples_count = cursor_node->samples; > - > - branch_type_count(&call->brtype_stat, > - &cursor_node->branch_flags, > - cursor_node->branch_from, > - cursor_node->ip); > + if (cursor_node->branch_from) { > + /* > + * branch_from is set with value somewhere else > + * to imply it's "to" of a branch. > + */ > + call->brtype_stat.branch_to = true; > + > + if (cursor_node->branch_flags.predicted) > + call->predicted_count = 1; > + > + if (cursor_node->branch_flags.abort) > + call->abort_count = 1; > + > + branch_type_count(&call->brtype_stat, > + &cursor_node->branch_flags, > + cursor_node->branch_from, > + cursor_node->ip); > + } else { > + /* > + * It's "from" of a branch > + */ > + call->brtype_stat.branch_to = false; > + call->cycles_count = > + cursor_node->branch_flags.cycles; > + call->iter_count = cursor_node->nr_loop_iter; > + call->samples_count = cursor_node->samples; > + } > } > > list_add_tail(&call->list, &node->val); > @@ -685,20 +698,32 @@ static enum match_result match_chain(struct callchain_cursor_node *node, > if (node->branch) { > cnode->branch_count++; > > - if (node->branch_flags.predicted) > - cnode->predicted_count++; > - > - if (node->branch_flags.abort) > - cnode->abort_count++; > - > - cnode->cycles_count += node->branch_flags.cycles; > - cnode->iter_count += node->nr_loop_iter; > - cnode->samples_count += node->samples; > - > - branch_type_count(&cnode->brtype_stat, > - &node->branch_flags, > - node->branch_from, > - node->ip); > + if (node->branch_from) { > + /* > + * It's "to" of a branch > + */ > + cnode->brtype_stat.branch_to = true; > + > + if (node->branch_flags.predicted) > + cnode->predicted_count++; > + > + if (node->branch_flags.abort) > + cnode->abort_count++; > + > + branch_type_count(&cnode->brtype_stat, > + &node->branch_flags, > + node->branch_from, > + node->ip); > + } else { > + /* > + * It's "from" of a branch > + */ > + cnode->brtype_stat.branch_to = false; > + cnode->cycles_count += > + node->branch_flags.cycles; > + cnode->iter_count += node->nr_loop_iter; > + cnode->samples_count += node->samples; > + } > } > > return MATCH_EQ; > @@ -1235,27 +1260,26 @@ static int count_pri64_printf(int idx, const char *str, u64 value, char *bf, int > return printed; > } > > -static int count_float_printf(int idx, const char *str, float value, char *bf, int bfsize) > +static int count_float_printf(int idx, const char *str, float value, > + char *bf, int bfsize, float threshold) > { > int printed; > > + if (threshold != 0.0 && value < threshold) > + return 0; > + > printed = scnprintf(bf, bfsize, "%s%s:%.1f%%", (idx) ? " " : " (", str, value); > > return printed; > } > > -static int counts_str_build(char *bf, int bfsize, > - u64 branch_count, u64 predicted_count, > - u64 abort_count, u64 cycles_count, > - u64 iter_count, u64 samples_count, > - struct branch_type_stat *brtype_stat) > +static int branch_to_str(char *bf, int bfsize, > + u64 branch_count, u64 predicted_count, > + u64 abort_count, > + struct branch_type_stat *brtype_stat) > { > - u64 cycles; > int printed, i = 0; > > - if (branch_count == 0) > - return scnprintf(bf, bfsize, " (calltrace)"); > - > printed = branch_type_str(brtype_stat, bf, bfsize); > if (printed) > i++; > @@ -1263,15 +1287,29 @@ static int counts_str_build(char *bf, int bfsize, > if (predicted_count < branch_count) { > printed += count_float_printf(i++, "predicted", > predicted_count * 100.0 / branch_count, > - bf + printed, bfsize - printed); > + bf + printed, bfsize - printed, 0.0); > } > > if (abort_count) { > printed += count_float_printf(i++, "abort", > abort_count * 100.0 / branch_count, > - bf + printed, bfsize - printed); > + bf + printed, bfsize - printed, 0.1); > } > > + if (i) > + printed += scnprintf(bf + printed, bfsize - printed, ")"); > + > + return printed; > +} > + > +static int branch_from_str(char *bf, int bfsize, > + u64 branch_count, > + u64 cycles_count, u64 iter_count, > + u64 samples_count) > +{ > + int printed = 0, i = 0; > + u64 cycles; > + > cycles = cycles_count / branch_count; > if (cycles) { > printed += count_pri64_printf(i++, "cycles", > @@ -1286,10 +1324,34 @@ static int counts_str_build(char *bf, int bfsize, > } > > if (i) > - return scnprintf(bf + printed, bfsize - printed, ")"); > + printed += scnprintf(bf + printed, bfsize - printed, ")"); > > - bf[0] = 0; > - return 0; > + return printed; > +} > + > +static int counts_str_build(char *bf, int bfsize, > + u64 branch_count, u64 predicted_count, > + u64 abort_count, u64 cycles_count, > + u64 iter_count, u64 samples_count, > + struct branch_type_stat *brtype_stat) > +{ > + int printed; > + > + if (branch_count == 0) > + return scnprintf(bf, bfsize, " (calltrace)"); > + > + if (brtype_stat->branch_to) { > + printed = branch_to_str(bf, bfsize, branch_count, > + predicted_count, abort_count, brtype_stat); > + } else { > + printed = branch_from_str(bf, bfsize, branch_count, > + cycles_count, iter_count, samples_count); > + } > + > + if (!printed) > + bf[0] = 0; > + > + return printed; > } > > static int callchain_counts_printf(FILE *fp, char *bf, int bfsize, > -- > 2.7.4
| |