Commit 0e332f03 authored by Andi Kleen's avatar Andi Kleen Committed by Arnaldo Carvalho de Melo

perf tools: Add support for cycles, weight branch_info field

cycles is a new branch_info field available on some CPUs that indicates
the time deltas between branches in the LBR.

Add a sort key and output code for the cycles to allow to display the
basic block cycles individually in perf report.

We also pass in the cycles for weight when LBRs are processed, which
allows to get global and local weight, to get an estimate of the total
cost.

And also print the cycles information for perf report -D.  I also added
printing for the previously missing LBR flags (mispredict etc.)
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1437233094-12844-2-git-send-email-andi@firstfloor.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 93df8a1e
...@@ -109,6 +109,7 @@ OPTIONS ...@@ -109,6 +109,7 @@ OPTIONS
- mispredict: "N" for predicted branch, "Y" for mispredicted branch - mispredict: "N" for predicted branch, "Y" for mispredicted branch
- in_tx: branch in TSX transaction - in_tx: branch in TSX transaction
- abort: TSX transaction abort. - abort: TSX transaction abort.
- cycles: Cycles in basic block
And default sort keys are changed to comm, dso_from, symbol_from, dso_to And default sort keys are changed to comm, dso_from, symbol_from, dso_to
and symbol_to, see '--branch-stack'. and symbol_to, see '--branch-stack'.
......
...@@ -134,7 +134,8 @@ struct branch_flags { ...@@ -134,7 +134,8 @@ struct branch_flags {
u64 predicted:1; u64 predicted:1;
u64 in_tx:1; u64 in_tx:1;
u64 abort:1; u64 abort:1;
u64 reserved:60; u64 cycles:16;
u64 reserved:44;
}; };
struct branch_entry { struct branch_entry {
......
...@@ -618,7 +618,8 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a ...@@ -618,7 +618,8 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
* and not events sampled. Thus we use a pseudo period of 1. * and not events sampled. Thus we use a pseudo period of 1.
*/ */
he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL, he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL,
1, 1, 0, true); 1, bi->flags.cycles ? bi->flags.cycles : 1,
0, true);
if (he == NULL) if (he == NULL)
return -ENOMEM; return -ENOMEM;
......
...@@ -47,6 +47,7 @@ enum hist_column { ...@@ -47,6 +47,7 @@ enum hist_column {
HISTC_MEM_SNOOP, HISTC_MEM_SNOOP,
HISTC_MEM_DCACHELINE, HISTC_MEM_DCACHELINE,
HISTC_TRANSACTION, HISTC_TRANSACTION,
HISTC_CYCLES,
HISTC_NR_COLS, /* Last entry */ HISTC_NR_COLS, /* Last entry */
}; };
......
...@@ -784,10 +784,18 @@ static void branch_stack__printf(struct perf_sample *sample) ...@@ -784,10 +784,18 @@ static void branch_stack__printf(struct perf_sample *sample)
printf("... branch stack: nr:%" PRIu64 "\n", sample->branch_stack->nr); printf("... branch stack: nr:%" PRIu64 "\n", sample->branch_stack->nr);
for (i = 0; i < sample->branch_stack->nr; i++) for (i = 0; i < sample->branch_stack->nr; i++) {
printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 "\n", struct branch_entry *e = &sample->branch_stack->entries[i];
i, sample->branch_stack->entries[i].from,
sample->branch_stack->entries[i].to); printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 " %hu cycles %s%s%s%s %x\n",
i, e->from, e->to,
e->flags.cycles,
e->flags.mispred ? "M" : " ",
e->flags.predicted ? "P" : " ",
e->flags.abort ? "A" : " ",
e->flags.in_tx ? "T" : " ",
(unsigned)e->flags.reserved);
}
} }
static void regs_dump__printf(u64 mask, u64 *regs) static void regs_dump__printf(u64 mask, u64 *regs)
......
...@@ -526,6 +526,29 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf, ...@@ -526,6 +526,29 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
return repsep_snprintf(bf, size, "%-*.*s", width, width, out); return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
} }
static int64_t
sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
{
return left->branch_info->flags.cycles -
right->branch_info->flags.cycles;
}
static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
if (he->branch_info->flags.cycles == 0)
return repsep_snprintf(bf, size, "%-*s", width, "-");
return repsep_snprintf(bf, size, "%-*hd", width,
he->branch_info->flags.cycles);
}
struct sort_entry sort_cycles = {
.se_header = "Basic Block Cycles",
.se_cmp = sort__cycles_cmp,
.se_snprintf = hist_entry__cycles_snprintf,
.se_width_idx = HISTC_CYCLES,
};
/* --sort daddr_sym */ /* --sort daddr_sym */
static int64_t static int64_t
sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right) sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
...@@ -1190,6 +1213,7 @@ static struct sort_dimension bstack_sort_dimensions[] = { ...@@ -1190,6 +1213,7 @@ static struct sort_dimension bstack_sort_dimensions[] = {
DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
DIM(SORT_IN_TX, "in_tx", sort_in_tx), DIM(SORT_IN_TX, "in_tx", sort_in_tx),
DIM(SORT_ABORT, "abort", sort_abort), DIM(SORT_ABORT, "abort", sort_abort),
DIM(SORT_CYCLES, "cycles", sort_cycles),
}; };
#undef DIM #undef DIM
......
...@@ -185,6 +185,7 @@ enum sort_type { ...@@ -185,6 +185,7 @@ enum sort_type {
SORT_MISPREDICT, SORT_MISPREDICT,
SORT_ABORT, SORT_ABORT,
SORT_IN_TX, SORT_IN_TX,
SORT_CYCLES,
/* memory mode specific sort keys */ /* memory mode specific sort keys */
__SORT_MEMORY_MODE, __SORT_MEMORY_MODE,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment