perf report: Calculate and return the branch flag counting
authorJin Yao <yao.jin@linux.intel.com>
Mon, 31 Oct 2016 01:19:51 +0000 (09:19 +0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 14 Nov 2016 16:25:58 +0000 (13:25 -0300)
Create some branch counters in per callchain list entry. Each counter
is for a branch flag. For example, predicted_count counts all the
*predicted* branches. The counters get updated by processing the
callchain cursor nodes.

It also provides functions to retrieve or print the values of counters
in callchain list.

Besides the counting for branch flags, it also counts and returns the
average number of iterations.

Signed-off-by: Yao Jin <yao.jin@linux.intel.com>
Acked-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Linux-kernel@vger.kernel.org
Cc: Yao Jin <yao.jin@linux.intel.com>
Link: http://lkml.kernel.org/r/1477876794-30749-4-git-send-email-yao.jin@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/callchain.c
tools/perf/util/callchain.h

index 138a415fad0d9b15e1cdc2ef6b73eefb351753e0..823befd8209a473b39e9b96965a353fd9b293a69 100644 (file)
@@ -438,6 +438,21 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
                call->ip = cursor_node->ip;
                call->ms.sym = cursor_node->sym;
                call->ms.map = cursor_node->map;
+
+               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;
+               }
+
                list_add_tail(&call->list, &node->val);
 
                callchain_cursor_advance(cursor);
@@ -497,8 +512,23 @@ static enum match_result match_chain(struct callchain_cursor_node *node,
                right = node->ip;
        }
 
-       if (left == right)
+       if (left == right) {
+               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;
+               }
+
                return MATCH_EQ;
+       }
 
        return left > right ? MATCH_GT : MATCH_LT;
 }
@@ -947,6 +977,163 @@ int callchain_node__fprintf_value(struct callchain_node *node,
        return 0;
 }
 
+static void callchain_counts_value(struct callchain_node *node,
+                                  u64 *branch_count, u64 *predicted_count,
+                                  u64 *abort_count, u64 *cycles_count)
+{
+       struct callchain_list *clist;
+
+       list_for_each_entry(clist, &node->val, list) {
+               if (branch_count)
+                       *branch_count += clist->branch_count;
+
+               if (predicted_count)
+                       *predicted_count += clist->predicted_count;
+
+               if (abort_count)
+                       *abort_count += clist->abort_count;
+
+               if (cycles_count)
+                       *cycles_count += clist->cycles_count;
+       }
+}
+
+static int callchain_node_branch_counts_cumul(struct callchain_node *node,
+                                             u64 *branch_count,
+                                             u64 *predicted_count,
+                                             u64 *abort_count,
+                                             u64 *cycles_count)
+{
+       struct callchain_node *child;
+       struct rb_node *n;
+
+       n = rb_first(&node->rb_root_in);
+       while (n) {
+               child = rb_entry(n, struct callchain_node, rb_node_in);
+               n = rb_next(n);
+
+               callchain_node_branch_counts_cumul(child, branch_count,
+                                                  predicted_count,
+                                                  abort_count,
+                                                  cycles_count);
+
+               callchain_counts_value(child, branch_count,
+                                      predicted_count, abort_count,
+                                      cycles_count);
+       }
+
+       return 0;
+}
+
+int callchain_branch_counts(struct callchain_root *root,
+                           u64 *branch_count, u64 *predicted_count,
+                           u64 *abort_count, u64 *cycles_count)
+{
+       if (branch_count)
+               *branch_count = 0;
+
+       if (predicted_count)
+               *predicted_count = 0;
+
+       if (abort_count)
+               *abort_count = 0;
+
+       if (cycles_count)
+               *cycles_count = 0;
+
+       return callchain_node_branch_counts_cumul(&root->node,
+                                                 branch_count,
+                                                 predicted_count,
+                                                 abort_count,
+                                                 cycles_count);
+}
+
+static int callchain_counts_printf(FILE *fp, char *bf, int bfsize,
+                                  u64 branch_count, u64 predicted_count,
+                                  u64 abort_count, u64 cycles_count,
+                                  u64 iter_count, u64 samples_count)
+{
+       double predicted_percent = 0.0;
+       const char *null_str = "";
+       char iter_str[32];
+       char *str;
+       u64 cycles = 0;
+
+       if (branch_count == 0) {
+               if (fp)
+                       return fprintf(fp, " (calltrace)");
+
+               return scnprintf(bf, bfsize, " (calltrace)");
+       }
+
+       if (iter_count && samples_count) {
+               scnprintf(iter_str, sizeof(iter_str),
+                        ", iterations:%" PRId64 "",
+                        iter_count / samples_count);
+               str = iter_str;
+       } else
+               str = (char *)null_str;
+
+       predicted_percent = predicted_count * 100.0 / branch_count;
+       cycles = cycles_count / branch_count;
+
+       if ((predicted_percent >= 100.0) && (abort_count == 0)) {
+               if (fp)
+                       return fprintf(fp, " (cycles:%" PRId64 "%s)",
+                                      cycles, str);
+
+               return scnprintf(bf, bfsize, " (cycles:%" PRId64 "%s)",
+                                cycles, str);
+       }
+
+       if ((predicted_percent < 100.0) && (abort_count == 0)) {
+               if (fp)
+                       return fprintf(fp,
+                               " (predicted:%.1f%%, cycles:%" PRId64 "%s)",
+                               predicted_percent, cycles, str);
+
+               return scnprintf(bf, bfsize,
+                       " (predicted:%.1f%%, cycles:%" PRId64 "%s)",
+                       predicted_percent, cycles, str);
+       }
+
+       if (fp)
+               return fprintf(fp,
+               " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)",
+                       predicted_percent, abort_count, cycles, str);
+
+       return scnprintf(bf, bfsize,
+               " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)",
+               predicted_percent, abort_count, cycles, str);
+}
+
+int callchain_list_counts__printf_value(struct callchain_node *node,
+                                       struct callchain_list *clist,
+                                       FILE *fp, char *bf, int bfsize)
+{
+       u64 branch_count, predicted_count;
+       u64 abort_count, cycles_count;
+       u64 iter_count = 0, samples_count = 0;
+
+       branch_count = clist->branch_count;
+       predicted_count = clist->predicted_count;
+       abort_count = clist->abort_count;
+       cycles_count = clist->cycles_count;
+
+       if (node) {
+               struct callchain_list *call;
+
+               list_for_each_entry(call, &node->val, list) {
+                       iter_count += call->iter_count;
+                       samples_count += call->samples_count;
+               }
+       }
+
+       return callchain_counts_printf(fp, bf, bfsize, branch_count,
+                                      predicted_count, abort_count,
+                                      cycles_count, iter_count, samples_count);
+}
+
 static void free_callchain_node(struct callchain_node *node)
 {
        struct callchain_list *list, *tmp;
index df6329d1c3503010d0e3e9cbbeeb7eec3ba60d18..d9c70dccf06ad50ca72cc98e22a7b6f8eb42f0c3 100644 (file)
@@ -111,6 +111,12 @@ struct callchain_list {
                bool            unfolded;
                bool            has_children;
        };
+       u64                     branch_count;
+       u64                     predicted_count;
+       u64                     abort_count;
+       u64                     cycles_count;
+       u64                     iter_count;
+       u64                     samples_count;
        char                   *srcline;
        struct list_head        list;
 };
@@ -263,8 +269,16 @@ char *callchain_node__scnprintf_value(struct callchain_node *node,
 int callchain_node__fprintf_value(struct callchain_node *node,
                                  FILE *fp, u64 total);
 
+int callchain_list_counts__printf_value(struct callchain_node *node,
+                                       struct callchain_list *clist,
+                                       FILE *fp, char *bf, int bfsize);
+
 void free_callchain(struct callchain_root *root);
 void decay_callchain(struct callchain_root *root);
 int callchain_node__make_parent_list(struct callchain_node *node);
 
+int callchain_branch_counts(struct callchain_root *root,
+                           u64 *branch_count, u64 *predicted_count,
+                           u64 *abort_count, u64 *cycles_count);
+
 #endif /* __PERF_CALLCHAIN_H */