Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S941482AbcJSQXy (ORCPT ); Wed, 19 Oct 2016 12:23:54 -0400 Received: from mga03.intel.com ([134.134.136.65]:42827 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S938894AbcJSOOz (ORCPT ); Wed, 19 Oct 2016 10:14:55 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.31,514,1473145200"; d="scan'208";a="21673799" From: Jin Yao To: acme@kernel.org, jolsa@kernel.org Cc: Linux-kernel@vger.kernel.org, ak@linux.intel.com, kan.liang@intel.com, yao.jin@linux.intel.com Subject: [PATCH v2 2/6] perf report: Caculate and return the branch counting in callchain Date: Thu, 20 Oct 2016 06:01:13 +0800 Message-Id: <1476914477-25420-3-git-send-email-yao.jin@linux.intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1476914477-25420-1-git-send-email-yao.jin@linux.intel.com> References: <1476914477-25420-1-git-send-email-yao.jin@linux.intel.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6635 Lines: 238 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. Signed-off-by: Jin Yao --- tools/perf/util/callchain.c | 165 +++++++++++++++++++++++++++++++++++++++++++- tools/perf/util/callchain.h | 11 +++ 2 files changed, 175 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 342ef20..8937a2c 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -440,6 +440,19 @@ 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; + } + list_add_tail(&call->list, &node->val); callchain_cursor_advance(cursor); @@ -499,8 +512,21 @@ 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; + } + return MATCH_EQ; + } return left > right ? MATCH_GT : MATCH_LT; } @@ -946,6 +972,143 @@ 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, + const char *cumul_str) +{ + double predicted_percent = 0.0; + double abort_percent = 0.0; + u64 cycles = 0; + + if (branch_count == 0) { + if (fp) + return fprintf(fp, " (calltrace)"); + + return scnprintf(bf, bfsize, " (calltrace)"); + } + + predicted_percent = predicted_count * 100.0 / branch_count; + abort_percent = abort_count * 100.0 / branch_count; + cycles = cycles_count / branch_count; + + if ((predicted_percent >= 100.0) && (abort_percent <= 0.0)) { + if (fp) + return fprintf(fp, " (%scycles:%" PRId64 ")", + cumul_str, cycles); + + return scnprintf(bf, bfsize, " (%scycles:%" PRId64 ")", + cumul_str, cycles); + } + + if ((predicted_percent < 100.0) && (abort_percent <= 0.0)) { + if (fp) + return fprintf(fp, + " (%spredicted:%.1f%%, cycles:%" PRId64 ")", + cumul_str, predicted_percent, cycles); + + return scnprintf(bf, bfsize, + " (%spredicted:%.1f%%, cycles:%" PRId64 ")", + cumul_str, predicted_percent, cycles); + } + + if (fp) + return fprintf(fp, + " (%spredicted:%.1f%%, abort:%.1f%%, cycles:%" PRId64 ")", + cumul_str, predicted_percent, abort_percent, cycles); + + return scnprintf(bf, bfsize, + " (%spredicted:%.1f%%, abort:%.1f%%, cycles:%" PRId64 ")", + cumul_str, predicted_percent, abort_percent, cycles); +} + +int callchain_list_counts__printf_value(struct callchain_list *clist, + FILE *fp, char *bf, int bfsize) +{ + u64 branch_count, predicted_count; + u64 abort_count, cycles_count; + + branch_count = clist->branch_count; + predicted_count = clist->predicted_count; + abort_count = clist->abort_count; + cycles_count = clist->cycles_count; + + return callchain_counts_printf(fp, bf, bfsize, branch_count, + predicted_count, abort_count, + cycles_count, ""); +} + static void free_callchain_node(struct callchain_node *node) { struct callchain_list *list, *tmp; diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 40ecf25..4f6bf6c 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -115,6 +115,10 @@ struct callchain_list { bool unfolded; bool has_children; }; + u64 branch_count; + u64 predicted_count; + u64 abort_count; + u64 cycles_count; char *srcline; struct list_head list; }; @@ -264,8 +268,15 @@ 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_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 */ -- 2.7.4