perf report: Display columns Predicted/Abort/Cycles in --branch-history
authorThomas Falcon <thomas.falcon@intel.com>
Thu, 10 Oct 2024 18:40:46 +0000 (13:40 -0500)
committerNamhyung Kim <namhyung@kernel.org>
Fri, 11 Oct 2024 06:41:23 +0000 (23:41 -0700)
The original commit message:

"
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      3
"

Update missed commit from series "perf report: Show branch flags/cycles
in --branch-history callgraph view" to apply to current repository so that
new columns described above are visible.

Link to original series:
https://lore.kernel.org/lkml/1477876794-30749-1-git-send-email-yao.jin@linux.intel.com/

Reported-by: Dr. David Alan Gilbert <linux@treblig.org>
Suggested-by: Kan Liang <kan.liang@linux.intel.com>
Co-developed-by: Jin Yao <yao.jin@linux.intel.com>
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Tested-by: Thomas Falcon <thomas.falcon@intel.com>
Signed-off-by: Thomas Falcon <thomas.falcon@intel.com>
Link: https://lore.kernel.org/r/20241010184046.203822-1-thomas.falcon@intel.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/Documentation/perf-report.txt
tools/perf/builtin-report.c
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/sort.c
tools/perf/util/sort.h

index 7c66d81ab978c84bf46244d9e4fccea28d2162db..87f86451940623f39de8e4b3b01683958ad961df 100644 (file)
@@ -391,6 +391,14 @@ OPTIONS
        This allows to examine the path the program took to each sample.
        The data collection must have used -b (or -j) and -g.
 
+       Also show with some branch flags that can be:
+       - Predicted: display the average percentage of predicated branches.
+                    (predicated number / total number)
+       - Abort: display the number of tsx aborted branches.
+       - Cycles: cycles in basic block.
+
+       - iterations: display the average number of iterations in callchain list.
+
 --addr2line=<path>::
         Path to addr2line binary.
 
index 5dc17ffee27a2de4614b22420d6621651b19da29..36b344e39dd63f0a28eca003cee7608c3a2a19f0 100644 (file)
@@ -1271,6 +1271,10 @@ static int process_attr(const struct perf_tool *tool __maybe_unused,
        return 0;
 }
 
+#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)
 {
        struct perf_session *session;
@@ -1639,7 +1643,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) {
index f387e85a008739d8203dbe122c500d3f0aa3187f..fff134565801669e8a64dfa730408d795f6d1816 100644 (file)
@@ -218,6 +218,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
        hists__new_col_len(hists, HISTC_LOCAL_P_STAGE_CYC, 13);
        hists__new_col_len(hists, HISTC_GLOBAL_P_STAGE_CYC, 13);
        hists__new_col_len(hists, HISTC_ADDR, BITS_PER_LONG / 4 + 2);
+       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 (symbol_conf.nanosecs)
                hists__new_col_len(hists, HISTC_TIME, 16);
index 7d7ae94b4b31fafa7db2573f46f12455b2e7da0f..1131056924d9c26adc8584021960b98cf3d994f3 100644 (file)
@@ -87,6 +87,9 @@ enum hist_column {
        HISTC_TYPE_OFFSET,
        HISTC_SYMBOL_OFFSET,
        HISTC_TYPE_CACHELINE,
+       HISTC_CALLCHAIN_BRANCH_PREDICTED,
+       HISTC_CALLCHAIN_BRANCH_ABORT,
+       HISTC_CALLCHAIN_BRANCH_CYCLES,
        HISTC_NR_COLS, /* Last entry */
 };
 
index 013020f33ece0abf162e5be235d7398d23005e04..168c488f0178d46f21126cd6603c423cc69cf8b2 100644 (file)
@@ -677,6 +677,102 @@ struct sort_entry sort_sym_ipc_null = {
        .se_width_idx   = HISTC_SYMBOL_IPC,
 };
 
+/* --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;
+       char str[32];
+
+       callchain_branch_counts(he->callchain, &branch_count,
+                               NULL, &abort_count, NULL);
+
+       snprintf(str, sizeof(str), "%" PRId64, abort_count);
+       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];
@@ -2456,6 +2552,15 @@ static struct sort_dimension bstack_sort_dimensions[] = {
        DIM(SORT_SYM_IPC, "ipc_lbr", sort_sym_ipc),
        DIM(SORT_ADDR_FROM, "addr_from", sort_addr_from),
        DIM(SORT_ADDR_TO, "addr_to", sort_addr_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
@@ -3484,7 +3589,13 @@ int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
                if (!sd->name || 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)
index 9ff68c6786e71814dd339e2362c06a693e8d8e09..a8572574e1686be6233ef4d11284caebe196825c 100644 (file)
@@ -88,6 +88,9 @@ enum sort_type {
        SORT_SYM_IPC,
        SORT_ADDR_FROM,
        SORT_ADDR_TO,
+       SORT_CALLCHAIN_BRANCH_PREDICTED,
+       SORT_CALLCHAIN_BRANCH_ABORT,
+       SORT_CALLCHAIN_BRANCH_CYCLES,
 
        /* memory mode specific sort keys */
        __SORT_MEMORY_MODE,