|
@@ -17,6 +17,7 @@
|
|
|
#include "evsel.h"
|
|
|
#include <asm/bug.h>
|
|
|
#include "ui/browsers/hists.h"
|
|
|
+#include "evlist.h"
|
|
|
|
|
|
struct c2c_hists {
|
|
|
struct hists hists;
|
|
@@ -183,6 +184,11 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+ ret = sample__resolve_callchain(sample, &callchain_cursor, NULL,
|
|
|
+ evsel, &al, sysctl_perf_event_max_stack);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
mi = sample__resolve_mem(sample, &al);
|
|
|
if (mi == NULL)
|
|
|
return -ENOMEM;
|
|
@@ -2117,6 +2123,58 @@ static void ui_quirks(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
|
|
|
+
|
|
|
+const char callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
|
|
|
+ CALLCHAIN_REPORT_HELP
|
|
|
+ "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
|
|
|
+
|
|
|
+static int
|
|
|
+parse_callchain_opt(const struct option *opt, const char *arg, int unset)
|
|
|
+{
|
|
|
+ struct callchain_param *callchain = opt->value;
|
|
|
+
|
|
|
+ callchain->enabled = !unset;
|
|
|
+ /*
|
|
|
+ * --no-call-graph
|
|
|
+ */
|
|
|
+ if (unset) {
|
|
|
+ symbol_conf.use_callchain = false;
|
|
|
+ callchain->mode = CHAIN_NONE;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return parse_callchain_report_opt(arg);
|
|
|
+}
|
|
|
+
|
|
|
+static int setup_callchain(struct perf_evlist *evlist)
|
|
|
+{
|
|
|
+ u64 sample_type = perf_evlist__combined_sample_type(evlist);
|
|
|
+ enum perf_call_graph_mode mode = CALLCHAIN_NONE;
|
|
|
+
|
|
|
+ if ((sample_type & PERF_SAMPLE_REGS_USER) &&
|
|
|
+ (sample_type & PERF_SAMPLE_STACK_USER))
|
|
|
+ mode = CALLCHAIN_DWARF;
|
|
|
+ else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
|
|
|
+ mode = CALLCHAIN_LBR;
|
|
|
+ else if (sample_type & PERF_SAMPLE_CALLCHAIN)
|
|
|
+ mode = CALLCHAIN_FP;
|
|
|
+
|
|
|
+ if (!callchain_param.enabled &&
|
|
|
+ callchain_param.mode != CHAIN_NONE &&
|
|
|
+ mode != CALLCHAIN_NONE) {
|
|
|
+ symbol_conf.use_callchain = true;
|
|
|
+ if (callchain_register_param(&callchain_param) < 0) {
|
|
|
+ ui__error("Can't register callchain params.\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ callchain_param.record_mode = mode;
|
|
|
+ callchain_param.min_percent = 0;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int perf_c2c__report(int argc, const char **argv)
|
|
|
{
|
|
|
struct perf_session *session;
|
|
@@ -2124,6 +2182,7 @@ static int perf_c2c__report(int argc, const char **argv)
|
|
|
struct perf_data_file file = {
|
|
|
.mode = PERF_DATA_MODE_READ,
|
|
|
};
|
|
|
+ char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
|
|
|
const struct option c2c_options[] = {
|
|
|
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
|
|
|
"file", "vmlinux pathname"),
|
|
@@ -2138,6 +2197,10 @@ static int perf_c2c__report(int argc, const char **argv)
|
|
|
#endif
|
|
|
OPT_BOOLEAN(0, "stats", &c2c.stats_only,
|
|
|
"Use the stdio interface"),
|
|
|
+ OPT_CALLBACK_DEFAULT('g', "call-graph", &callchain_param,
|
|
|
+ "print_type,threshold[,print_limit],order,sort_key[,branch],value",
|
|
|
+ callchain_help, &parse_callchain_opt,
|
|
|
+ callchain_default_opt),
|
|
|
OPT_END()
|
|
|
};
|
|
|
int err = 0;
|
|
@@ -2179,6 +2242,10 @@ static int perf_c2c__report(int argc, const char **argv)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+ err = setup_callchain(session->evlist);
|
|
|
+ if (err)
|
|
|
+ goto out_session;
|
|
|
+
|
|
|
if (symbol__init(&session->header.env) < 0)
|
|
|
goto out_session;
|
|
|
|