perf report: Add srcline_from/to branch sort keys
Add "srcline_from" and "srcline_to" branch sort keys that allow to show the source lines of a branch. That makes it much easier to track down where particular branches happen in the program, for example to examine branch mispredictions, or to associate it with cycle counts: % perf record -b -e cycles:p ./tcall % perf report --sort srcline_from,srcline_to,mispredict ... 15.10% tcall.c:18 tcall.c:10 N 14.83% tcall.c:11 tcall.c:5 N 14.12% tcall.c:7 tcall.c:12 N 14.04% tcall.c:12 tcall.c:5 N 12.42% tcall.c:17 tcall.c:18 N 12.39% tcall.c:7 tcall.c:13 N 12.27% tcall.c:13 tcall.c:17 N ... % perf report --sort srcline_from,srcline_to,cycles ... 17.12% tcall.c:18 tcall.c:11 1 17.01% tcall.c:12 tcall.c:6 1 16.98% tcall.c:11 tcall.c:6 1 15.91% tcall.c:17 tcall.c:18 1 6.38% tcall.c:7 tcall.c:17 7 4.80% tcall.c:7 tcall.c:12 8 4.21% tcall.c:7 tcall.c:17 8 2.67% tcall.c:7 tcall.c:12 7 2.62% tcall.c:7 tcall.c:12 10 2.10% tcall.c:7 tcall.c:17 9 1.58% tcall.c:7 tcall.c:12 6 1.44% tcall.c:7 tcall.c:12 5 1.38% tcall.c:7 tcall.c:12 9 1.06% tcall.c:7 tcall.c:17 13 1.05% tcall.c:7 tcall.c:12 4 1.01% tcall.c:7 tcall.c:17 6 Open issues: - Some kernel symbols get misresolved. Signed-off-by: Andi Kleen <ak@linux.intel.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Link: http://lkml.kernel.org/r/1463775308-32748-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
d4c6fb36ac
commit
508be0dfe6
|
@ -103,12 +103,13 @@ OPTIONS
|
||||||
|
|
||||||
If --branch-stack option is used, following sort keys are also
|
If --branch-stack option is used, following sort keys are also
|
||||||
available:
|
available:
|
||||||
dso_from, dso_to, symbol_from, symbol_to, mispredict.
|
|
||||||
|
|
||||||
- dso_from: name of library or module branched from
|
- dso_from: name of library or module branched from
|
||||||
- dso_to: name of library or module branched to
|
- dso_to: name of library or module branched to
|
||||||
- symbol_from: name of function branched from
|
- symbol_from: name of function branched from
|
||||||
- symbol_to: name of function branched to
|
- symbol_to: name of function branched to
|
||||||
|
- srcline_from: source file and line branched from
|
||||||
|
- srcline_to: source file and line branched to
|
||||||
- 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.
|
||||||
|
|
|
@ -117,6 +117,13 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
|
||||||
hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
|
hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
|
||||||
hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
|
hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (h->branch_info->srcline_from)
|
||||||
|
hists__new_col_len(hists, HISTC_SRCLINE_FROM,
|
||||||
|
strlen(h->branch_info->srcline_from));
|
||||||
|
if (h->branch_info->srcline_to)
|
||||||
|
hists__new_col_len(hists, HISTC_SRCLINE_TO,
|
||||||
|
strlen(h->branch_info->srcline_to));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h->mem_info) {
|
if (h->mem_info) {
|
||||||
|
@ -1042,6 +1049,8 @@ void hist_entry__delete(struct hist_entry *he)
|
||||||
if (he->branch_info) {
|
if (he->branch_info) {
|
||||||
map__zput(he->branch_info->from.map);
|
map__zput(he->branch_info->from.map);
|
||||||
map__zput(he->branch_info->to.map);
|
map__zput(he->branch_info->to.map);
|
||||||
|
free_srcline(he->branch_info->srcline_from);
|
||||||
|
free_srcline(he->branch_info->srcline_to);
|
||||||
zfree(&he->branch_info);
|
zfree(&he->branch_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,8 @@ enum hist_column {
|
||||||
HISTC_MEM_IADDR_SYMBOL,
|
HISTC_MEM_IADDR_SYMBOL,
|
||||||
HISTC_TRANSACTION,
|
HISTC_TRANSACTION,
|
||||||
HISTC_CYCLES,
|
HISTC_CYCLES,
|
||||||
|
HISTC_SRCLINE_FROM,
|
||||||
|
HISTC_SRCLINE_TO,
|
||||||
HISTC_TRACE,
|
HISTC_TRACE,
|
||||||
HISTC_NR_COLS, /* Last entry */
|
HISTC_NR_COLS, /* Last entry */
|
||||||
};
|
};
|
||||||
|
|
|
@ -353,6 +353,88 @@ struct sort_entry sort_srcline = {
|
||||||
.se_width_idx = HISTC_SRCLINE,
|
.se_width_idx = HISTC_SRCLINE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* --sort srcline_from */
|
||||||
|
|
||||||
|
static int64_t
|
||||||
|
sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
|
||||||
|
{
|
||||||
|
if (!left->branch_info->srcline_from) {
|
||||||
|
struct map *map = left->branch_info->from.map;
|
||||||
|
if (!map)
|
||||||
|
left->branch_info->srcline_from = SRCLINE_UNKNOWN;
|
||||||
|
else
|
||||||
|
left->branch_info->srcline_from = get_srcline(map->dso,
|
||||||
|
map__rip_2objdump(map,
|
||||||
|
left->branch_info->from.al_addr),
|
||||||
|
left->branch_info->from.sym, true);
|
||||||
|
}
|
||||||
|
if (!right->branch_info->srcline_from) {
|
||||||
|
struct map *map = right->branch_info->from.map;
|
||||||
|
if (!map)
|
||||||
|
right->branch_info->srcline_from = SRCLINE_UNKNOWN;
|
||||||
|
else
|
||||||
|
right->branch_info->srcline_from = get_srcline(map->dso,
|
||||||
|
map__rip_2objdump(map,
|
||||||
|
right->branch_info->from.al_addr),
|
||||||
|
right->branch_info->from.sym, true);
|
||||||
|
}
|
||||||
|
return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf,
|
||||||
|
size_t size, unsigned int width)
|
||||||
|
{
|
||||||
|
return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_from);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sort_entry sort_srcline_from = {
|
||||||
|
.se_header = "From Source:Line",
|
||||||
|
.se_cmp = sort__srcline_from_cmp,
|
||||||
|
.se_snprintf = hist_entry__srcline_from_snprintf,
|
||||||
|
.se_width_idx = HISTC_SRCLINE_FROM,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* --sort srcline_to */
|
||||||
|
|
||||||
|
static int64_t
|
||||||
|
sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
|
||||||
|
{
|
||||||
|
if (!left->branch_info->srcline_to) {
|
||||||
|
struct map *map = left->branch_info->to.map;
|
||||||
|
if (!map)
|
||||||
|
left->branch_info->srcline_to = SRCLINE_UNKNOWN;
|
||||||
|
else
|
||||||
|
left->branch_info->srcline_to = get_srcline(map->dso,
|
||||||
|
map__rip_2objdump(map,
|
||||||
|
left->branch_info->to.al_addr),
|
||||||
|
left->branch_info->from.sym, true);
|
||||||
|
}
|
||||||
|
if (!right->branch_info->srcline_to) {
|
||||||
|
struct map *map = right->branch_info->to.map;
|
||||||
|
if (!map)
|
||||||
|
right->branch_info->srcline_to = SRCLINE_UNKNOWN;
|
||||||
|
else
|
||||||
|
right->branch_info->srcline_to = get_srcline(map->dso,
|
||||||
|
map__rip_2objdump(map,
|
||||||
|
right->branch_info->to.al_addr),
|
||||||
|
right->branch_info->to.sym, true);
|
||||||
|
}
|
||||||
|
return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf,
|
||||||
|
size_t size, unsigned int width)
|
||||||
|
{
|
||||||
|
return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_to);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sort_entry sort_srcline_to = {
|
||||||
|
.se_header = "To Source:Line",
|
||||||
|
.se_cmp = sort__srcline_to_cmp,
|
||||||
|
.se_snprintf = hist_entry__srcline_to_snprintf,
|
||||||
|
.se_width_idx = HISTC_SRCLINE_TO,
|
||||||
|
};
|
||||||
|
|
||||||
/* --sort srcfile */
|
/* --sort srcfile */
|
||||||
|
|
||||||
static char no_srcfile[1];
|
static char no_srcfile[1];
|
||||||
|
@ -1347,6 +1429,8 @@ static struct sort_dimension bstack_sort_dimensions[] = {
|
||||||
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),
|
DIM(SORT_CYCLES, "cycles", sort_cycles),
|
||||||
|
DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from),
|
||||||
|
DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to),
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef DIM
|
#undef DIM
|
||||||
|
|
|
@ -215,6 +215,8 @@ enum sort_type {
|
||||||
SORT_ABORT,
|
SORT_ABORT,
|
||||||
SORT_IN_TX,
|
SORT_IN_TX,
|
||||||
SORT_CYCLES,
|
SORT_CYCLES,
|
||||||
|
SORT_SRCLINE_FROM,
|
||||||
|
SORT_SRCLINE_TO,
|
||||||
|
|
||||||
/* memory mode specific sort keys */
|
/* memory mode specific sort keys */
|
||||||
__SORT_MEMORY_MODE,
|
__SORT_MEMORY_MODE,
|
||||||
|
|
|
@ -186,6 +186,8 @@ struct branch_info {
|
||||||
struct addr_map_symbol from;
|
struct addr_map_symbol from;
|
||||||
struct addr_map_symbol to;
|
struct addr_map_symbol to;
|
||||||
struct branch_flags flags;
|
struct branch_flags flags;
|
||||||
|
char *srcline_from;
|
||||||
|
char *srcline_to;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mem_info {
|
struct mem_info {
|
||||||
|
|
Loading…
Reference in New Issue