diff options
author | Andi Kleen <ak@linux.intel.com> | 2018-09-20 14:05:39 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2018-10-24 14:29:55 -0400 |
commit | 99f753f048b3f02f31a56951781672021af6cd0d (patch) | |
tree | 9c22f288e4be70e8c31d9c248657dcdd98231452 /tools/perf/builtin-script.c | |
parent | d1b1552e15d41297abcaf3812378e3391d44fa6b (diff) |
perf script: Implement --graph-function
Add a ftrace style --graph-function argument to 'perf script' that
allows to print itrace function calls only below a given function. This
makes it easier to find the code of interest in a large trace.
% perf record -e intel_pt//k -a sleep 1
% perf script --graph-function group_sched_in --call-trace
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) group_sched_in
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) __x86_indirect_thunk_rax
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) event_sched_in.isra.107
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) perf_event_set_state.part.71
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) perf_event_update_time
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) perf_pmu_disable
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) perf_log_itrace_start
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) __x86_indirect_thunk_rax
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) perf_event_update_userpage
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) calc_timer_values
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) sched_clock_cpu
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) __x86_indirect_thunk_rax
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) arch_perf_update_userpage
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) __fentry__
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) using_native_sched_clock
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) sched_clock_stable
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) perf_pmu_enable
perf 900 [000] 194167.205652203: ([kernel.kallsyms]) __x86_indirect_thunk_rax
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) group_sched_in
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) __x86_indirect_thunk_rax
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) event_sched_in.isra.107
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) perf_event_set_state.part.71
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) perf_event_update_time
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) perf_pmu_disable
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) perf_log_itrace_start
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) __x86_indirect_thunk_rax
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) perf_event_update_userpage
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) calc_timer_values
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) sched_clock_cpu
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) __x86_indirect_thunk_rax
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) arch_perf_update_userpage
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) __fentry__
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) using_native_sched_clock
swapper 0 [001] 194167.205660693: ([kernel.kallsyms]) sched_clock_stable
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Leo Yan <leo.yan@linaro.org>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Kim Phillips <kim.phillips@arm.com>
Link: http://lkml.kernel.org/r/20180920180540.14039-5-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 96 |
1 files changed, 78 insertions, 18 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 566e1450898a..9d2249ea75e3 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -1105,6 +1105,35 @@ out: | |||
1105 | return printed; | 1105 | return printed; |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | static const char *resolve_branch_sym(struct perf_sample *sample, | ||
1109 | struct perf_evsel *evsel, | ||
1110 | struct thread *thread, | ||
1111 | struct addr_location *al, | ||
1112 | u64 *ip) | ||
1113 | { | ||
1114 | struct addr_location addr_al; | ||
1115 | struct perf_event_attr *attr = &evsel->attr; | ||
1116 | const char *name = NULL; | ||
1117 | |||
1118 | if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { | ||
1119 | if (sample_addr_correlates_sym(attr)) { | ||
1120 | thread__resolve(thread, &addr_al, sample); | ||
1121 | if (addr_al.sym) | ||
1122 | name = addr_al.sym->name; | ||
1123 | else | ||
1124 | *ip = sample->addr; | ||
1125 | } else { | ||
1126 | *ip = sample->addr; | ||
1127 | } | ||
1128 | } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { | ||
1129 | if (al->sym) | ||
1130 | name = al->sym->name; | ||
1131 | else | ||
1132 | *ip = sample->ip; | ||
1133 | } | ||
1134 | return name; | ||
1135 | } | ||
1136 | |||
1108 | static int perf_sample__fprintf_callindent(struct perf_sample *sample, | 1137 | static int perf_sample__fprintf_callindent(struct perf_sample *sample, |
1109 | struct perf_evsel *evsel, | 1138 | struct perf_evsel *evsel, |
1110 | struct thread *thread, | 1139 | struct thread *thread, |
@@ -1112,7 +1141,6 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample, | |||
1112 | { | 1141 | { |
1113 | struct perf_event_attr *attr = &evsel->attr; | 1142 | struct perf_event_attr *attr = &evsel->attr; |
1114 | size_t depth = thread_stack__depth(thread); | 1143 | size_t depth = thread_stack__depth(thread); |
1115 | struct addr_location addr_al; | ||
1116 | const char *name = NULL; | 1144 | const char *name = NULL; |
1117 | static int spacing; | 1145 | static int spacing; |
1118 | int len = 0; | 1146 | int len = 0; |
@@ -1126,22 +1154,7 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample, | |||
1126 | if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN) | 1154 | if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN) |
1127 | depth += 1; | 1155 | depth += 1; |
1128 | 1156 | ||
1129 | if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { | 1157 | name = resolve_branch_sym(sample, evsel, thread, al, &ip); |
1130 | if (sample_addr_correlates_sym(attr)) { | ||
1131 | thread__resolve(thread, &addr_al, sample); | ||
1132 | if (addr_al.sym) | ||
1133 | name = addr_al.sym->name; | ||
1134 | else | ||
1135 | ip = sample->addr; | ||
1136 | } else { | ||
1137 | ip = sample->addr; | ||
1138 | } | ||
1139 | } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { | ||
1140 | if (al->sym) | ||
1141 | name = al->sym->name; | ||
1142 | else | ||
1143 | ip = sample->ip; | ||
1144 | } | ||
1145 | 1158 | ||
1146 | if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) { | 1159 | if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) { |
1147 | dlen += fprintf(fp, "("); | 1160 | dlen += fprintf(fp, "("); |
@@ -1647,6 +1660,47 @@ static void perf_sample__fprint_metric(struct perf_script *script, | |||
1647 | } | 1660 | } |
1648 | } | 1661 | } |
1649 | 1662 | ||
1663 | static bool show_event(struct perf_sample *sample, | ||
1664 | struct perf_evsel *evsel, | ||
1665 | struct thread *thread, | ||
1666 | struct addr_location *al) | ||
1667 | { | ||
1668 | int depth = thread_stack__depth(thread); | ||
1669 | |||
1670 | if (!symbol_conf.graph_function) | ||
1671 | return true; | ||
1672 | |||
1673 | if (thread->filter) { | ||
1674 | if (depth <= thread->filter_entry_depth) { | ||
1675 | thread->filter = false; | ||
1676 | return false; | ||
1677 | } | ||
1678 | return true; | ||
1679 | } else { | ||
1680 | const char *s = symbol_conf.graph_function; | ||
1681 | u64 ip; | ||
1682 | const char *name = resolve_branch_sym(sample, evsel, thread, al, | ||
1683 | &ip); | ||
1684 | unsigned nlen; | ||
1685 | |||
1686 | if (!name) | ||
1687 | return false; | ||
1688 | nlen = strlen(name); | ||
1689 | while (*s) { | ||
1690 | unsigned len = strcspn(s, ","); | ||
1691 | if (nlen == len && !strncmp(name, s, len)) { | ||
1692 | thread->filter = true; | ||
1693 | thread->filter_entry_depth = depth; | ||
1694 | return true; | ||
1695 | } | ||
1696 | s += len; | ||
1697 | if (*s == ',') | ||
1698 | s++; | ||
1699 | } | ||
1700 | return false; | ||
1701 | } | ||
1702 | } | ||
1703 | |||
1650 | static void process_event(struct perf_script *script, | 1704 | static void process_event(struct perf_script *script, |
1651 | struct perf_sample *sample, struct perf_evsel *evsel, | 1705 | struct perf_sample *sample, struct perf_evsel *evsel, |
1652 | struct addr_location *al, | 1706 | struct addr_location *al, |
@@ -1661,6 +1715,9 @@ static void process_event(struct perf_script *script, | |||
1661 | if (output[type].fields == 0) | 1715 | if (output[type].fields == 0) |
1662 | return; | 1716 | return; |
1663 | 1717 | ||
1718 | if (!show_event(sample, evsel, thread, al)) | ||
1719 | return; | ||
1720 | |||
1664 | ++es->samples; | 1721 | ++es->samples; |
1665 | 1722 | ||
1666 | perf_sample__fprintf_start(sample, thread, evsel, | 1723 | perf_sample__fprintf_start(sample, thread, evsel, |
@@ -3237,6 +3294,8 @@ int cmd_script(int argc, const char **argv) | |||
3237 | "Decode calls from from itrace", parse_call_trace), | 3294 | "Decode calls from from itrace", parse_call_trace), |
3238 | OPT_CALLBACK_OPTARG(0, "call-ret-trace", &itrace_synth_opts, NULL, NULL, | 3295 | OPT_CALLBACK_OPTARG(0, "call-ret-trace", &itrace_synth_opts, NULL, NULL, |
3239 | "Decode calls and returns from itrace", parse_callret_trace), | 3296 | "Decode calls and returns from itrace", parse_callret_trace), |
3297 | OPT_STRING(0, "graph-function", &symbol_conf.graph_function, "symbol[,symbol...]", | ||
3298 | "Only print symbols and callees with --call-trace/--call-ret-trace"), | ||
3240 | OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]", | 3299 | OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]", |
3241 | "Stop display of callgraph at these symbols"), | 3300 | "Stop display of callgraph at these symbols"), |
3242 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), | 3301 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), |
@@ -3494,7 +3553,8 @@ int cmd_script(int argc, const char **argv) | |||
3494 | script.session = session; | 3553 | script.session = session; |
3495 | script__setup_sample_type(&script); | 3554 | script__setup_sample_type(&script); |
3496 | 3555 | ||
3497 | if (output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) | 3556 | if ((output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) || |
3557 | symbol_conf.graph_function) | ||
3498 | itrace_synth_opts.thread_stack = true; | 3558 | itrace_synth_opts.thread_stack = true; |
3499 | 3559 | ||
3500 | session->itrace_synth_opts = &itrace_synth_opts; | 3560 | session->itrace_synth_opts = &itrace_synth_opts; |