|
@@ -1105,6 +1105,35 @@ out:
|
|
|
return printed;
|
|
|
}
|
|
|
|
|
|
+static const char *resolve_branch_sym(struct perf_sample *sample,
|
|
|
+ struct perf_evsel *evsel,
|
|
|
+ struct thread *thread,
|
|
|
+ struct addr_location *al,
|
|
|
+ u64 *ip)
|
|
|
+{
|
|
|
+ struct addr_location addr_al;
|
|
|
+ struct perf_event_attr *attr = &evsel->attr;
|
|
|
+ const char *name = NULL;
|
|
|
+
|
|
|
+ if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) {
|
|
|
+ if (sample_addr_correlates_sym(attr)) {
|
|
|
+ thread__resolve(thread, &addr_al, sample);
|
|
|
+ if (addr_al.sym)
|
|
|
+ name = addr_al.sym->name;
|
|
|
+ else
|
|
|
+ *ip = sample->addr;
|
|
|
+ } else {
|
|
|
+ *ip = sample->addr;
|
|
|
+ }
|
|
|
+ } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) {
|
|
|
+ if (al->sym)
|
|
|
+ name = al->sym->name;
|
|
|
+ else
|
|
|
+ *ip = sample->ip;
|
|
|
+ }
|
|
|
+ return name;
|
|
|
+}
|
|
|
+
|
|
|
static int perf_sample__fprintf_callindent(struct perf_sample *sample,
|
|
|
struct perf_evsel *evsel,
|
|
|
struct thread *thread,
|
|
@@ -1112,7 +1141,6 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,
|
|
|
{
|
|
|
struct perf_event_attr *attr = &evsel->attr;
|
|
|
size_t depth = thread_stack__depth(thread);
|
|
|
- struct addr_location addr_al;
|
|
|
const char *name = NULL;
|
|
|
static int spacing;
|
|
|
int len = 0;
|
|
@@ -1126,22 +1154,7 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,
|
|
|
if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN)
|
|
|
depth += 1;
|
|
|
|
|
|
- if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) {
|
|
|
- if (sample_addr_correlates_sym(attr)) {
|
|
|
- thread__resolve(thread, &addr_al, sample);
|
|
|
- if (addr_al.sym)
|
|
|
- name = addr_al.sym->name;
|
|
|
- else
|
|
|
- ip = sample->addr;
|
|
|
- } else {
|
|
|
- ip = sample->addr;
|
|
|
- }
|
|
|
- } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) {
|
|
|
- if (al->sym)
|
|
|
- name = al->sym->name;
|
|
|
- else
|
|
|
- ip = sample->ip;
|
|
|
- }
|
|
|
+ name = resolve_branch_sym(sample, evsel, thread, al, &ip);
|
|
|
|
|
|
if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) {
|
|
|
dlen += fprintf(fp, "(");
|
|
@@ -1647,6 +1660,47 @@ static void perf_sample__fprint_metric(struct perf_script *script,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static bool show_event(struct perf_sample *sample,
|
|
|
+ struct perf_evsel *evsel,
|
|
|
+ struct thread *thread,
|
|
|
+ struct addr_location *al)
|
|
|
+{
|
|
|
+ int depth = thread_stack__depth(thread);
|
|
|
+
|
|
|
+ if (!symbol_conf.graph_function)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ if (thread->filter) {
|
|
|
+ if (depth <= thread->filter_entry_depth) {
|
|
|
+ thread->filter = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ const char *s = symbol_conf.graph_function;
|
|
|
+ u64 ip;
|
|
|
+ const char *name = resolve_branch_sym(sample, evsel, thread, al,
|
|
|
+ &ip);
|
|
|
+ unsigned nlen;
|
|
|
+
|
|
|
+ if (!name)
|
|
|
+ return false;
|
|
|
+ nlen = strlen(name);
|
|
|
+ while (*s) {
|
|
|
+ unsigned len = strcspn(s, ",");
|
|
|
+ if (nlen == len && !strncmp(name, s, len)) {
|
|
|
+ thread->filter = true;
|
|
|
+ thread->filter_entry_depth = depth;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ s += len;
|
|
|
+ if (*s == ',')
|
|
|
+ s++;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void process_event(struct perf_script *script,
|
|
|
struct perf_sample *sample, struct perf_evsel *evsel,
|
|
|
struct addr_location *al,
|
|
@@ -1661,6 +1715,9 @@ static void process_event(struct perf_script *script,
|
|
|
if (output[type].fields == 0)
|
|
|
return;
|
|
|
|
|
|
+ if (!show_event(sample, evsel, thread, al))
|
|
|
+ return;
|
|
|
+
|
|
|
++es->samples;
|
|
|
|
|
|
perf_sample__fprintf_start(sample, thread, evsel,
|
|
@@ -3237,6 +3294,8 @@ int cmd_script(int argc, const char **argv)
|
|
|
"Decode calls from from itrace", parse_call_trace),
|
|
|
OPT_CALLBACK_OPTARG(0, "call-ret-trace", &itrace_synth_opts, NULL, NULL,
|
|
|
"Decode calls and returns from itrace", parse_callret_trace),
|
|
|
+ OPT_STRING(0, "graph-function", &symbol_conf.graph_function, "symbol[,symbol...]",
|
|
|
+ "Only print symbols and callees with --call-trace/--call-ret-trace"),
|
|
|
OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]",
|
|
|
"Stop display of callgraph at these symbols"),
|
|
|
OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
|
|
@@ -3494,7 +3553,8 @@ int cmd_script(int argc, const char **argv)
|
|
|
script.session = session;
|
|
|
script__setup_sample_type(&script);
|
|
|
|
|
|
- if (output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT)
|
|
|
+ if ((output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) ||
|
|
|
+ symbol_conf.graph_function)
|
|
|
itrace_synth_opts.thread_stack = true;
|
|
|
|
|
|
session->itrace_synth_opts = &itrace_synth_opts;
|