aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-script.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r--tools/perf/builtin-script.c166
1 files changed, 142 insertions, 24 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 4da5e32b9e03..b5bc85bd0bbe 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -44,6 +44,7 @@
44#include <sys/stat.h> 44#include <sys/stat.h>
45#include <fcntl.h> 45#include <fcntl.h>
46#include <unistd.h> 46#include <unistd.h>
47#include <subcmd/pager.h>
47 48
48#include "sane_ctype.h" 49#include "sane_ctype.h"
49 50
@@ -912,7 +913,7 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
912 913
913static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, 914static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
914 struct perf_insn *x, u8 *inbuf, int len, 915 struct perf_insn *x, u8 *inbuf, int len,
915 int insn, FILE *fp) 916 int insn, FILE *fp, int *total_cycles)
916{ 917{
917 int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip, 918 int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip,
918 dump_insn(x, ip, inbuf, len, NULL), 919 dump_insn(x, ip, inbuf, len, NULL),
@@ -921,7 +922,8 @@ static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
921 en->flags.in_tx ? " INTX" : "", 922 en->flags.in_tx ? " INTX" : "",
922 en->flags.abort ? " ABORT" : ""); 923 en->flags.abort ? " ABORT" : "");
923 if (en->flags.cycles) { 924 if (en->flags.cycles) {
924 printed += fprintf(fp, " %d cycles", en->flags.cycles); 925 *total_cycles += en->flags.cycles;
926 printed += fprintf(fp, " %d cycles [%d]", en->flags.cycles, *total_cycles);
925 if (insn) 927 if (insn)
926 printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles); 928 printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles);
927 } 929 }
@@ -978,6 +980,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
978 u8 buffer[MAXBB]; 980 u8 buffer[MAXBB];
979 unsigned off; 981 unsigned off;
980 struct symbol *lastsym = NULL; 982 struct symbol *lastsym = NULL;
983 int total_cycles = 0;
981 984
982 if (!(br && br->nr)) 985 if (!(br && br->nr))
983 return 0; 986 return 0;
@@ -998,7 +1001,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
998 printed += ip__fprintf_sym(br->entries[nr - 1].from, thread, 1001 printed += ip__fprintf_sym(br->entries[nr - 1].from, thread,
999 x.cpumode, x.cpu, &lastsym, attr, fp); 1002 x.cpumode, x.cpu, &lastsym, attr, fp);
1000 printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1], 1003 printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1],
1001 &x, buffer, len, 0, fp); 1004 &x, buffer, len, 0, fp, &total_cycles);
1002 } 1005 }
1003 1006
1004 /* Print all blocks */ 1007 /* Print all blocks */
@@ -1026,7 +1029,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
1026 1029
1027 printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp); 1030 printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp);
1028 if (ip == end) { 1031 if (ip == end) {
1029 printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp); 1032 printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp,
1033 &total_cycles);
1030 break; 1034 break;
1031 } else { 1035 } else {
1032 printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip, 1036 printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip,
@@ -1104,6 +1108,35 @@ out:
1104 return printed; 1108 return printed;
1105} 1109}
1106 1110
1111static const char *resolve_branch_sym(struct perf_sample *sample,
1112 struct perf_evsel *evsel,
1113 struct thread *thread,
1114 struct addr_location *al,
1115 u64 *ip)
1116{
1117 struct addr_location addr_al;
1118 struct perf_event_attr *attr = &evsel->attr;
1119 const char *name = NULL;
1120
1121 if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) {
1122 if (sample_addr_correlates_sym(attr)) {
1123 thread__resolve(thread, &addr_al, sample);
1124 if (addr_al.sym)
1125 name = addr_al.sym->name;
1126 else
1127 *ip = sample->addr;
1128 } else {
1129 *ip = sample->addr;
1130 }
1131 } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) {
1132 if (al->sym)
1133 name = al->sym->name;
1134 else
1135 *ip = sample->ip;
1136 }
1137 return name;
1138}
1139
1107static int perf_sample__fprintf_callindent(struct perf_sample *sample, 1140static int perf_sample__fprintf_callindent(struct perf_sample *sample,
1108 struct perf_evsel *evsel, 1141 struct perf_evsel *evsel,
1109 struct thread *thread, 1142 struct thread *thread,
@@ -1111,7 +1144,6 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,
1111{ 1144{
1112 struct perf_event_attr *attr = &evsel->attr; 1145 struct perf_event_attr *attr = &evsel->attr;
1113 size_t depth = thread_stack__depth(thread); 1146 size_t depth = thread_stack__depth(thread);
1114 struct addr_location addr_al;
1115 const char *name = NULL; 1147 const char *name = NULL;
1116 static int spacing; 1148 static int spacing;
1117 int len = 0; 1149 int len = 0;
@@ -1125,22 +1157,7 @@ static int perf_sample__fprintf_callindent(struct perf_sample *sample,
1125 if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN) 1157 if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN)
1126 depth += 1; 1158 depth += 1;
1127 1159
1128 if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { 1160 name = resolve_branch_sym(sample, evsel, thread, al, &ip);
1129 if (sample_addr_correlates_sym(attr)) {
1130 thread__resolve(thread, &addr_al, sample);
1131 if (addr_al.sym)
1132 name = addr_al.sym->name;
1133 else
1134 ip = sample->addr;
1135 } else {
1136 ip = sample->addr;
1137 }
1138 } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) {
1139 if (al->sym)
1140 name = al->sym->name;
1141 else
1142 ip = sample->ip;
1143 }
1144 1161
1145 if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) { 1162 if (PRINT_FIELD(DSO) && !(PRINT_FIELD(IP) || PRINT_FIELD(ADDR))) {
1146 dlen += fprintf(fp, "("); 1163 dlen += fprintf(fp, "(");
@@ -1646,6 +1663,47 @@ static void perf_sample__fprint_metric(struct perf_script *script,
1646 } 1663 }
1647} 1664}
1648 1665
1666static bool show_event(struct perf_sample *sample,
1667 struct perf_evsel *evsel,
1668 struct thread *thread,
1669 struct addr_location *al)
1670{
1671 int depth = thread_stack__depth(thread);
1672
1673 if (!symbol_conf.graph_function)
1674 return true;
1675
1676 if (thread->filter) {
1677 if (depth <= thread->filter_entry_depth) {
1678 thread->filter = false;
1679 return false;
1680 }
1681 return true;
1682 } else {
1683 const char *s = symbol_conf.graph_function;
1684 u64 ip;
1685 const char *name = resolve_branch_sym(sample, evsel, thread, al,
1686 &ip);
1687 unsigned nlen;
1688
1689 if (!name)
1690 return false;
1691 nlen = strlen(name);
1692 while (*s) {
1693 unsigned len = strcspn(s, ",");
1694 if (nlen == len && !strncmp(name, s, len)) {
1695 thread->filter = true;
1696 thread->filter_entry_depth = depth;
1697 return true;
1698 }
1699 s += len;
1700 if (*s == ',')
1701 s++;
1702 }
1703 return false;
1704 }
1705}
1706
1649static void process_event(struct perf_script *script, 1707static void process_event(struct perf_script *script,
1650 struct perf_sample *sample, struct perf_evsel *evsel, 1708 struct perf_sample *sample, struct perf_evsel *evsel,
1651 struct addr_location *al, 1709 struct addr_location *al,
@@ -1660,6 +1718,9 @@ static void process_event(struct perf_script *script,
1660 if (output[type].fields == 0) 1718 if (output[type].fields == 0)
1661 return; 1719 return;
1662 1720
1721 if (!show_event(sample, evsel, thread, al))
1722 return;
1723
1663 ++es->samples; 1724 ++es->samples;
1664 1725
1665 perf_sample__fprintf_start(sample, thread, evsel, 1726 perf_sample__fprintf_start(sample, thread, evsel,
@@ -1737,6 +1798,9 @@ static void process_event(struct perf_script *script,
1737 1798
1738 if (PRINT_FIELD(METRIC)) 1799 if (PRINT_FIELD(METRIC))
1739 perf_sample__fprint_metric(script, thread, evsel, sample, fp); 1800 perf_sample__fprint_metric(script, thread, evsel, sample, fp);
1801
1802 if (verbose)
1803 fflush(fp);
1740} 1804}
1741 1805
1742static struct scripting_ops *scripting_ops; 1806static struct scripting_ops *scripting_ops;
@@ -3100,6 +3164,44 @@ static int perf_script__process_auxtrace_info(struct perf_session *session,
3100#define perf_script__process_auxtrace_info 0 3164#define perf_script__process_auxtrace_info 0
3101#endif 3165#endif
3102 3166
3167static int parse_insn_trace(const struct option *opt __maybe_unused,
3168 const char *str __maybe_unused,
3169 int unset __maybe_unused)
3170{
3171 parse_output_fields(NULL, "+insn,-event,-period", 0);
3172 itrace_parse_synth_opts(opt, "i0ns", 0);
3173 nanosecs = true;
3174 return 0;
3175}
3176
3177static int parse_xed(const struct option *opt __maybe_unused,
3178 const char *str __maybe_unused,
3179 int unset __maybe_unused)
3180{
3181 force_pager("xed -F insn: -A -64 | less");
3182 return 0;
3183}
3184
3185static int parse_call_trace(const struct option *opt __maybe_unused,
3186 const char *str __maybe_unused,
3187 int unset __maybe_unused)
3188{
3189 parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent", 0);
3190 itrace_parse_synth_opts(opt, "cewp", 0);
3191 nanosecs = true;
3192 return 0;
3193}
3194
3195static int parse_callret_trace(const struct option *opt __maybe_unused,
3196 const char *str __maybe_unused,
3197 int unset __maybe_unused)
3198{
3199 parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent,+flags", 0);
3200 itrace_parse_synth_opts(opt, "crewp", 0);
3201 nanosecs = true;
3202 return 0;
3203}
3204
3103int cmd_script(int argc, const char **argv) 3205int cmd_script(int argc, const char **argv)
3104{ 3206{
3105 bool show_full_info = false; 3207 bool show_full_info = false;
@@ -3109,7 +3211,10 @@ int cmd_script(int argc, const char **argv)
3109 char *rec_script_path = NULL; 3211 char *rec_script_path = NULL;
3110 char *rep_script_path = NULL; 3212 char *rep_script_path = NULL;
3111 struct perf_session *session; 3213 struct perf_session *session;
3112 struct itrace_synth_opts itrace_synth_opts = { .set = false, }; 3214 struct itrace_synth_opts itrace_synth_opts = {
3215 .set = false,
3216 .default_no_sample = true,
3217 };
3113 char *script_path = NULL; 3218 char *script_path = NULL;
3114 const char **__argv; 3219 const char **__argv;
3115 int i, j, err = 0; 3220 int i, j, err = 0;
@@ -3184,6 +3289,16 @@ int cmd_script(int argc, const char **argv)
3184 "system-wide collection from all CPUs"), 3289 "system-wide collection from all CPUs"),
3185 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 3290 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
3186 "only consider these symbols"), 3291 "only consider these symbols"),
3292 OPT_CALLBACK_OPTARG(0, "insn-trace", &itrace_synth_opts, NULL, NULL,
3293 "Decode instructions from itrace", parse_insn_trace),
3294 OPT_CALLBACK_OPTARG(0, "xed", NULL, NULL, NULL,
3295 "Run xed disassembler on output", parse_xed),
3296 OPT_CALLBACK_OPTARG(0, "call-trace", &itrace_synth_opts, NULL, NULL,
3297 "Decode calls from from itrace", parse_call_trace),
3298 OPT_CALLBACK_OPTARG(0, "call-ret-trace", &itrace_synth_opts, NULL, NULL,
3299 "Decode calls and returns from itrace", parse_callret_trace),
3300 OPT_STRING(0, "graph-function", &symbol_conf.graph_function, "symbol[,symbol...]",
3301 "Only print symbols and callees with --call-trace/--call-ret-trace"),
3187 OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]", 3302 OPT_STRING(0, "stop-bt", &symbol_conf.bt_stop_list_str, "symbol[,symbol...]",
3188 "Stop display of callgraph at these symbols"), 3303 "Stop display of callgraph at these symbols"),
3189 OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 3304 OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
@@ -3417,8 +3532,10 @@ int cmd_script(int argc, const char **argv)
3417 exit(-1); 3532 exit(-1);
3418 } 3533 }
3419 3534
3420 if (!script_name) 3535 if (!script_name) {
3421 setup_pager(); 3536 setup_pager();
3537 use_browser = 0;
3538 }
3422 3539
3423 session = perf_session__new(&data, false, &script.tool); 3540 session = perf_session__new(&data, false, &script.tool);
3424 if (session == NULL) 3541 if (session == NULL)
@@ -3439,7 +3556,8 @@ int cmd_script(int argc, const char **argv)
3439 script.session = session; 3556 script.session = session;
3440 script__setup_sample_type(&script); 3557 script__setup_sample_type(&script);
3441 3558
3442 if (output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) 3559 if ((output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) ||
3560 symbol_conf.graph_function)
3443 itrace_synth_opts.thread_stack = true; 3561 itrace_synth_opts.thread_stack = true;
3444 3562
3445 session->itrace_synth_opts = &itrace_synth_opts; 3563 session->itrace_synth_opts = &itrace_synth_opts;