Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S938904AbcJSOO5 (ORCPT ); Wed, 19 Oct 2016 10:14:57 -0400 Received: from mga03.intel.com ([134.134.136.65]:30265 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S938790AbcJSOOu (ORCPT ); Wed, 19 Oct 2016 10:14:50 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.31,514,1473145200"; d="scan'208";a="21673838" 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 6/6] perf report: Display columns Predicted/Abort/Cycles in --branch-history Date: Thu, 20 Oct 2016 06:01:17 +0800 Message-Id: <1476914477-25420-7-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: 8224 Lines: 250 Use current sort mechanism but the real .se_cmp() just returns 0 so that new columns "Predicted", "Abort" and Cycles are created in display but actually these keys are not the sort keys. For example: Overhead Source:Line Symbol Shared Object Predicted Abort Cycles ........ ............ ........ ............. ......... ..... ...... 38.25% div.c:45 [.] main div 97.6% 0.0% 3 Signed-off-by: Jin Yao --- tools/perf/Documentation/perf-report.txt | 8 +++ tools/perf/builtin-report.c | 6 +- tools/perf/util/hist.c | 3 + tools/perf/util/hist.h | 3 + tools/perf/util/sort.c | 117 ++++++++++++++++++++++++++++++- tools/perf/util/sort.h | 3 + 6 files changed, 138 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 2d17462..bb927cb 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -335,6 +335,14 @@ OPTIONS --branch-history:: Add the addresses of sampled taken branches to the callstack. This allows to examine the path the program took to each sample. + + Also show with some branch flags that can be: + - Predicted: display the average percentage of predicated branches. + (predicated number / total number) + - Abort: display the average percentage of abort branches. + (abort number /total number) + - Cycles: cycles in basic block. + The data collection must have used -b (or -j) and -g. --objdump=:: diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index c406393..df83ea4 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -664,6 +664,10 @@ const char report_callchain_help[] = "Display call graph (stack chain/backtrace) CALLCHAIN_REPORT_HELP "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; +#define CALLCHAIN_BRANCH_SORT_ORDER \ + "srcline,symbol,dso,callchain_branch_predicted," \ + "callchain_branch_abort,callchain_branch_cycles" + int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) { struct perf_session *session; @@ -924,7 +928,7 @@ repeat: symbol_conf.use_callchain = true; callchain_register_param(&callchain_param); if (sort_order == NULL) - sort_order = "srcline,symbol,dso"; + sort_order = CALLCHAIN_BRANCH_SORT_ORDER; } if (report.mem_mode) { diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index e1be413..2470fff 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -176,6 +176,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3); hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); + hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_PREDICTED, 9); + hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_ABORT, 5); + hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_CYCLES, 6); if (h->srcline) { len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header)); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index d4b6514..74e1dd4 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -57,6 +57,9 @@ enum hist_column { HISTC_SRCLINE_FROM, HISTC_SRCLINE_TO, HISTC_TRACE, + HISTC_CALLCHAIN_BRANCH_PREDICTED, + HISTC_CALLCHAIN_BRANCH_ABORT, + HISTC_CALLCHAIN_BRANCH_CYCLES, HISTC_NR_COLS, /* Last entry */ }; diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index df622f4..e47a984 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -435,6 +435,106 @@ struct sort_entry sort_srcline_to = { .se_width_idx = HISTC_SRCLINE_TO, }; +/* --sort callchain_branch_predicted */ + +static int64_t +sort__callchain_branch_predicted_cmp(struct hist_entry *left __maybe_unused, + struct hist_entry *right __maybe_unused) +{ + return 0; +} + +static int hist_entry__callchain_branch_predicted_snprintf( + struct hist_entry *he, char *bf, size_t size, unsigned int width) +{ + u64 branch_count, predicted_count; + double percent = 0.0; + char str[32]; + + callchain_branch_counts(he->callchain, &branch_count, + &predicted_count, NULL, NULL); + + if (branch_count) + percent = predicted_count * 100.0 / branch_count; + + snprintf(str, sizeof(str), "%.1f%%", percent); + return repsep_snprintf(bf, size, "%-*.*s", width, width, str); +} + +struct sort_entry sort_callchain_branch_predicted = { + .se_header = "Predicted", + .se_cmp = sort__callchain_branch_predicted_cmp, + .se_snprintf = hist_entry__callchain_branch_predicted_snprintf, + .se_width_idx = HISTC_CALLCHAIN_BRANCH_PREDICTED, +}; + +/* --sort callchain_branch_abort */ + +static int64_t +sort__callchain_branch_abort_cmp(struct hist_entry *left __maybe_unused, + struct hist_entry *right __maybe_unused) +{ + return 0; +} + +static int hist_entry__callchain_branch_abort_snprintf(struct hist_entry *he, + char *bf, size_t size, + unsigned int width) +{ + u64 branch_count, abort_count; + double percent = 0.0; + char str[32]; + + callchain_branch_counts(he->callchain, &branch_count, + NULL, &abort_count, NULL); + + if (branch_count) + percent = abort_count * 100.0 / branch_count; + + snprintf(str, sizeof(str), "%.1f%%", percent); + return repsep_snprintf(bf, size, "%-*.*s", width, width, str); +} + +struct sort_entry sort_callchain_branch_abort = { + .se_header = "Abort", + .se_cmp = sort__callchain_branch_abort_cmp, + .se_snprintf = hist_entry__callchain_branch_abort_snprintf, + .se_width_idx = HISTC_CALLCHAIN_BRANCH_ABORT, +}; + +/* --sort callchain_branch_cycles */ + +static int64_t +sort__callchain_branch_cycles_cmp(struct hist_entry *left __maybe_unused, + struct hist_entry *right __maybe_unused) +{ + return 0; +} + +static int hist_entry__callchain_branch_cycles_snprintf(struct hist_entry *he, + char *bf, size_t size, + unsigned int width) +{ + u64 branch_count, cycles_count, cycles = 0; + char str[32]; + + callchain_branch_counts(he->callchain, &branch_count, + NULL, NULL, &cycles_count); + + if (branch_count) + cycles = cycles_count / branch_count; + + snprintf(str, sizeof(str), "%" PRId64 "", cycles); + return repsep_snprintf(bf, size, "%-*.*s", width, width, str); +} + +struct sort_entry sort_callchain_branch_cycles = { + .se_header = "Cycles", + .se_cmp = sort__callchain_branch_cycles_cmp, + .se_snprintf = hist_entry__callchain_branch_cycles_snprintf, + .se_width_idx = HISTC_CALLCHAIN_BRANCH_CYCLES, +}; + /* --sort srcfile */ static char no_srcfile[1]; @@ -1435,6 +1535,15 @@ static struct sort_dimension bstack_sort_dimensions[] = { DIM(SORT_CYCLES, "cycles", sort_cycles), DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from), DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to), + DIM(SORT_CALLCHAIN_BRANCH_PREDICTED, + "callchain_branch_predicted", + sort_callchain_branch_predicted), + DIM(SORT_CALLCHAIN_BRANCH_ABORT, + "callchain_branch_abort", + sort_callchain_branch_abort), + DIM(SORT_CALLCHAIN_BRANCH_CYCLES, + "callchain_branch_cycles", + sort_callchain_branch_cycles), }; #undef DIM @@ -2369,7 +2478,13 @@ int sort_dimension__add(struct perf_hpp_list *list, const char *tok, if (strncasecmp(tok, sd->name, strlen(tok))) continue; - if (sort__mode != SORT_MODE__BRANCH) + if ((sort__mode != SORT_MODE__BRANCH) && + strncasecmp(tok, "callchain_branch_predicted", + strlen(tok)) && + strncasecmp(tok, "callchain_branch_abort", + strlen(tok)) && + strncasecmp(tok, "callchain_branch_cycles", + strlen(tok))) return -EINVAL; if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 7aff317..30c6e97 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -224,6 +224,9 @@ enum sort_type { SORT_CYCLES, SORT_SRCLINE_FROM, SORT_SRCLINE_TO, + SORT_CALLCHAIN_BRANCH_PREDICTED, + SORT_CALLCHAIN_BRANCH_ABORT, + SORT_CALLCHAIN_BRANCH_CYCLES, /* memory mode specific sort keys */ __SORT_MEMORY_MODE, -- 2.7.4