|
@@ -53,6 +53,50 @@ struct perf_report {
|
|
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
|
|
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
|
|
|
|
+ struct addr_location *al,
|
|
|
|
+ struct perf_sample *sample,
|
|
|
|
+ struct perf_evsel *evsel,
|
|
|
|
+ struct machine *machine)
|
|
|
|
+{
|
|
|
|
+ struct perf_report *rep = container_of(tool, struct perf_report, tool);
|
|
|
|
+ struct symbol *parent = NULL;
|
|
|
|
+ int err = 0;
|
|
|
|
+ unsigned i;
|
|
|
|
+ struct hist_entry *he;
|
|
|
|
+ struct branch_info *bi;
|
|
|
|
+
|
|
|
|
+ if ((sort__has_parent || symbol_conf.use_callchain)
|
|
|
|
+ && sample->callchain) {
|
|
|
|
+ err = machine__resolve_callchain(machine, evsel, al->thread,
|
|
|
|
+ sample->callchain, &parent);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ bi = machine__resolve_bstack(machine, al->thread,
|
|
|
|
+ sample->branch_stack);
|
|
|
|
+ if (!bi)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < sample->branch_stack->nr; i++) {
|
|
|
|
+ if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
|
|
|
|
+ continue;
|
|
|
|
+ /*
|
|
|
|
+ * The report shows the percentage of total branches captured
|
|
|
|
+ * and not events sampled. Thus we use a pseudo period of 1.
|
|
|
|
+ */
|
|
|
|
+ he = __hists__add_branch_entry(&evsel->hists, al, parent,
|
|
|
|
+ &bi[i], 1);
|
|
|
|
+ if (he) {
|
|
|
|
+ evsel->hists.stats.total_period += 1;
|
|
|
|
+ hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
|
|
|
|
+ } else
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+ return err;
|
|
|
|
+}
|
|
|
|
+
|
|
static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
|
|
static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
|
|
struct addr_location *al,
|
|
struct addr_location *al,
|
|
struct perf_sample *sample,
|
|
struct perf_sample *sample,
|
|
@@ -126,14 +170,21 @@ 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 (al.map != NULL)
|
|
|
|
- al.map->dso->hit = 1;
|
|
|
|
|
|
+ if (sort__branch_mode) {
|
|
|
|
+ if (perf_report__add_branch_hist_entry(tool, &al, sample,
|
|
|
|
+ evsel, machine)) {
|
|
|
|
+ pr_debug("problem adding lbr entry, skipping event\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (al.map != NULL)
|
|
|
|
+ al.map->dso->hit = 1;
|
|
|
|
|
|
- if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
|
|
|
|
- pr_debug("problem incrementing symbol period, skipping event\n");
|
|
|
|
- return -1;
|
|
|
|
|
|
+ if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
|
|
|
|
+ pr_debug("problem incrementing symbol period, skipping event\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -188,6 +239,15 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (sort__branch_mode) {
|
|
|
|
+ if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
|
|
|
|
+ fprintf(stderr, "selected -b but no branch data."
|
|
|
|
+ " Did you call perf record without"
|
|
|
|
+ " -b?\n");
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -477,7 +537,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
|
|
OPT_BOOLEAN(0, "stdio", &report.use_stdio,
|
|
OPT_BOOLEAN(0, "stdio", &report.use_stdio,
|
|
"Use the stdio interface"),
|
|
"Use the stdio interface"),
|
|
OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
|
|
OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
|
|
- "sort by key(s): pid, comm, dso, symbol, parent"),
|
|
|
|
|
|
+ "sort by key(s): pid, comm, dso, symbol, parent, dso_to,"
|
|
|
|
+ " dso_from, symbol_to, symbol_from, mispredict"),
|
|
OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
|
|
OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
|
|
"Show sample percentage for different cpu modes"),
|
|
"Show sample percentage for different cpu modes"),
|
|
OPT_STRING('p', "parent", &parent_pattern, "regex",
|
|
OPT_STRING('p', "parent", &parent_pattern, "regex",
|
|
@@ -517,6 +578,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,
|
|
|
|
+ "use branch records for histogram filling"),
|
|
OPT_END()
|
|
OPT_END()
|
|
};
|
|
};
|
|
|
|
|
|
@@ -537,10 +600,36 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
|
|
report.input_name = "perf.data";
|
|
report.input_name = "perf.data";
|
|
}
|
|
}
|
|
|
|
|
|
- if (strcmp(report.input_name, "-") != 0)
|
|
|
|
|
|
+ if (sort__branch_mode) {
|
|
|
|
+ if (use_browser)
|
|
|
|
+ fprintf(stderr, "Warning: TUI interface not supported"
|
|
|
|
+ " in branch mode\n");
|
|
|
|
+ if (symbol_conf.dso_list_str != NULL)
|
|
|
|
+ fprintf(stderr, "Warning: dso filtering not supported"
|
|
|
|
+ " in branch mode\n");
|
|
|
|
+ if (symbol_conf.sym_list_str != NULL)
|
|
|
|
+ fprintf(stderr, "Warning: symbol filtering not"
|
|
|
|
+ " supported in branch mode\n");
|
|
|
|
+
|
|
|
|
+ report.use_stdio = true;
|
|
|
|
+ use_browser = 0;
|
|
setup_browser(true);
|
|
setup_browser(true);
|
|
- else
|
|
|
|
|
|
+ symbol_conf.dso_list_str = NULL;
|
|
|
|
+ symbol_conf.sym_list_str = NULL;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * if no sort_order is provided, then specify branch-mode
|
|
|
|
+ * specific order
|
|
|
|
+ */
|
|
|
|
+ if (sort_order == default_sort_order)
|
|
|
|
+ sort_order = "comm,dso_from,symbol_from,"
|
|
|
|
+ "dso_to,symbol_to";
|
|
|
|
+
|
|
|
|
+ } else if (strcmp(report.input_name, "-") != 0) {
|
|
|
|
+ setup_browser(true);
|
|
|
|
+ } else {
|
|
use_browser = 0;
|
|
use_browser = 0;
|
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
/*
|
|
* Only in the newt browser we are doing integrated annotation,
|
|
* Only in the newt browser we are doing integrated annotation,
|