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 <yao....@linux.intel.com>
---
 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=<path>::
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

Reply via email to