Commit 993ac88d authored by Stephane Eranian's avatar Stephane Eranian Committed by Ingo Molnar

perf report: Auto-detect branch stack sampling mode

This patch enhances perf report to auto-detect when the
perf.data file contains samples with branch stacks. That way it
is not necessary to use the -b option.

To force branch view mode to off, simply use --no-branch-stack.
Signed-off-by: default avatarStephane Eranian <eranian@google.com>
Cc: peterz@infradead.org
Cc: acme@redhat.com
Cc: asharma@fb.com
Cc: ravitillo@lbl.gov
Cc: vweaver1@eecs.utk.edu
Cc: khandual@linux.vnet.ibm.com
Cc: dsahern@gmail.com
Link: http://lkml.kernel.org/r/1331246868-19905-4-git-send-email-eranian@google.comSigned-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 330aa675
...@@ -157,8 +157,11 @@ OPTIONS ...@@ -157,8 +157,11 @@ OPTIONS
--branch-stack:: --branch-stack::
Use the addresses of sampled taken branches instead of the instruction Use the addresses of sampled taken branches instead of the instruction
address to build the histograms. To generate meaningful output, the address to build the histograms. To generate meaningful output, the
perf.data file must have been obtained using perf record -b xxx where perf.data file must have been obtained using perf record -b or
xxx is a branch filter option. perf record --branch-filter xxx where xxx is a branch filter option.
perf report is able to auto-detect whether a perf.data file contains
branch stacks and it will automatically switch to the branch view mode,
unless --no-branch-stack is used.
SEE ALSO SEE ALSO
-------- --------
......
...@@ -170,7 +170,7 @@ static int process_sample_event(struct perf_tool *tool, ...@@ -170,7 +170,7 @@ static int process_sample_event(struct perf_tool *tool,
if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
return 0; return 0;
if (sort__branch_mode) { if (sort__branch_mode == 1) {
if (perf_report__add_branch_hist_entry(tool, &al, sample, if (perf_report__add_branch_hist_entry(tool, &al, sample,
evsel, machine)) { evsel, machine)) {
pr_debug("problem adding lbr entry, skipping event\n"); pr_debug("problem adding lbr entry, skipping event\n");
...@@ -239,7 +239,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep) ...@@ -239,7 +239,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
} }
} }
if (sort__branch_mode) { if (sort__branch_mode == 1) {
if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) { if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
fprintf(stderr, "selected -b but no branch data." fprintf(stderr, "selected -b but no branch data."
" Did you call perf record without" " Did you call perf record without"
...@@ -306,7 +306,7 @@ static int __cmd_report(struct perf_report *rep) ...@@ -306,7 +306,7 @@ static int __cmd_report(struct perf_report *rep)
{ {
int ret = -EINVAL; int ret = -EINVAL;
u64 nr_samples; u64 nr_samples;
struct perf_session *session; struct perf_session *session = rep->session;
struct perf_evsel *pos; struct perf_evsel *pos;
struct map *kernel_map; struct map *kernel_map;
struct kmap *kernel_kmap; struct kmap *kernel_kmap;
...@@ -314,13 +314,6 @@ static int __cmd_report(struct perf_report *rep) ...@@ -314,13 +314,6 @@ static int __cmd_report(struct perf_report *rep)
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
session = perf_session__new(rep->input_name, O_RDONLY,
rep->force, false, &rep->tool);
if (session == NULL)
return -ENOMEM;
rep->session = session;
if (rep->cpu_list) { if (rep->cpu_list) {
ret = perf_session__cpu_bitmap(session, rep->cpu_list, ret = perf_session__cpu_bitmap(session, rep->cpu_list,
rep->cpu_bitmap); rep->cpu_bitmap);
...@@ -487,9 +480,19 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) ...@@ -487,9 +480,19 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
return 0; return 0;
} }
static int
parse_branch_mode(const struct option *opt __used, const char *str __used, int unset)
{
sort__branch_mode = !unset;
return 0;
}
int cmd_report(int argc, const char **argv, const char *prefix __used) int cmd_report(int argc, const char **argv, const char *prefix __used)
{ {
struct perf_session *session;
struct stat st; struct stat st;
bool has_br_stack = false;
int ret = -1;
char callchain_default_opt[] = "fractal,0.5,callee"; char callchain_default_opt[] = "fractal,0.5,callee";
const char * const report_usage[] = { const char * const report_usage[] = {
"perf report [<options>]", "perf report [<options>]",
...@@ -578,8 +581,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) ...@@ -578,8 +581,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
"Specify disassembler style (e.g. -M intel for intel syntax)"), "Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
"Show a column with the sum of periods"), "Show a column with the sum of periods"),
OPT_BOOLEAN('b', "branch-stack", &sort__branch_mode, OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
"use branch records for histogram filling"), "use branch records for histogram filling", parse_branch_mode),
OPT_END() OPT_END()
}; };
...@@ -599,8 +602,20 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) ...@@ -599,8 +602,20 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
else else
report.input_name = "perf.data"; report.input_name = "perf.data";
} }
session = perf_session__new(report.input_name, O_RDONLY,
report.force, false, &report.tool);
if (session == NULL)
return -ENOMEM;
report.session = session;
has_br_stack = perf_header__has_feat(&session->header,
HEADER_BRANCH_STACK);
if (sort__branch_mode) { if (sort__branch_mode == -1 && has_br_stack)
sort__branch_mode = 1;
if (sort__branch_mode == 1) {
if (use_browser) if (use_browser)
fprintf(stderr, "Warning: TUI interface not supported" fprintf(stderr, "Warning: TUI interface not supported"
" in branch mode\n"); " in branch mode\n");
...@@ -657,13 +672,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) ...@@ -657,13 +672,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
} }
if (symbol__init() < 0) if (symbol__init() < 0)
return -1; goto error;
setup_sorting(report_usage, options); setup_sorting(report_usage, options);
if (parent_pattern != default_parent_pattern) { if (parent_pattern != default_parent_pattern) {
if (sort_dimension__add("parent") < 0) if (sort_dimension__add("parent") < 0)
return -1; goto error;
/* /*
* Only show the parent fields if we explicitly * Only show the parent fields if we explicitly
...@@ -685,5 +700,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) ...@@ -685,5 +700,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
return __cmd_report(&report); ret = __cmd_report(&report);
error:
perf_session__delete(session);
return ret;
} }
...@@ -8,7 +8,7 @@ const char default_sort_order[] = "comm,dso,symbol"; ...@@ -8,7 +8,7 @@ const char default_sort_order[] = "comm,dso,symbol";
const char *sort_order = default_sort_order; const char *sort_order = default_sort_order;
int sort__need_collapse = 0; int sort__need_collapse = 0;
int sort__has_parent = 0; int sort__has_parent = 0;
bool sort__branch_mode; int sort__branch_mode = -1; /* -1 = means not set */
enum sort_type sort__first_dimension; enum sort_type sort__first_dimension;
......
...@@ -31,7 +31,7 @@ extern const char *parent_pattern; ...@@ -31,7 +31,7 @@ extern const char *parent_pattern;
extern const char default_sort_order[]; extern const char default_sort_order[];
extern int sort__need_collapse; extern int sort__need_collapse;
extern int sort__has_parent; extern int sort__has_parent;
extern bool sort__branch_mode; extern int sort__branch_mode;
extern char *field_sep; extern char *field_sep;
extern struct sort_entry sort_comm; extern struct sort_entry sort_comm;
extern struct sort_entry sort_dso; extern struct sort_entry sort_dso;
......
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