diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 155 |
1 files changed, 131 insertions, 24 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index c691214d820f..57f9a7e7f7d3 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "util/stat.h" | 23 | #include "util/stat.h" |
24 | #include <linux/bitmap.h> | 24 | #include <linux/bitmap.h> |
25 | #include "asm/bug.h" | 25 | #include "asm/bug.h" |
26 | #include "util/mem-events.h" | ||
26 | 27 | ||
27 | static char const *script_name; | 28 | static char const *script_name; |
28 | static char const *generate_script_lang; | 29 | static char const *generate_script_lang; |
@@ -58,6 +59,9 @@ enum perf_output_field { | |||
58 | PERF_OUTPUT_IREGS = 1U << 14, | 59 | PERF_OUTPUT_IREGS = 1U << 14, |
59 | PERF_OUTPUT_BRSTACK = 1U << 15, | 60 | PERF_OUTPUT_BRSTACK = 1U << 15, |
60 | PERF_OUTPUT_BRSTACKSYM = 1U << 16, | 61 | PERF_OUTPUT_BRSTACKSYM = 1U << 16, |
62 | PERF_OUTPUT_DATA_SRC = 1U << 17, | ||
63 | PERF_OUTPUT_WEIGHT = 1U << 18, | ||
64 | PERF_OUTPUT_BPF_OUTPUT = 1U << 19, | ||
61 | }; | 65 | }; |
62 | 66 | ||
63 | struct output_option { | 67 | struct output_option { |
@@ -81,6 +85,9 @@ struct output_option { | |||
81 | {.str = "iregs", .field = PERF_OUTPUT_IREGS}, | 85 | {.str = "iregs", .field = PERF_OUTPUT_IREGS}, |
82 | {.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, | 86 | {.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, |
83 | {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, | 87 | {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, |
88 | {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC}, | ||
89 | {.str = "weight", .field = PERF_OUTPUT_WEIGHT}, | ||
90 | {.str = "bpf-output", .field = PERF_OUTPUT_BPF_OUTPUT}, | ||
84 | }; | 91 | }; |
85 | 92 | ||
86 | /* default set to maintain compatibility with current format */ | 93 | /* default set to maintain compatibility with current format */ |
@@ -101,7 +108,7 @@ static struct { | |||
101 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | | 108 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | |
102 | PERF_OUTPUT_PERIOD, | 109 | PERF_OUTPUT_PERIOD, |
103 | 110 | ||
104 | .invalid_fields = PERF_OUTPUT_TRACE, | 111 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, |
105 | }, | 112 | }, |
106 | 113 | ||
107 | [PERF_TYPE_SOFTWARE] = { | 114 | [PERF_TYPE_SOFTWARE] = { |
@@ -111,7 +118,7 @@ static struct { | |||
111 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | | 118 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | |
112 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | 119 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | |
113 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | | 120 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | |
114 | PERF_OUTPUT_PERIOD, | 121 | PERF_OUTPUT_PERIOD | PERF_OUTPUT_BPF_OUTPUT, |
115 | 122 | ||
116 | .invalid_fields = PERF_OUTPUT_TRACE, | 123 | .invalid_fields = PERF_OUTPUT_TRACE, |
117 | }, | 124 | }, |
@@ -121,7 +128,7 @@ static struct { | |||
121 | 128 | ||
122 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | | 129 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | |
123 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | | 130 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | |
124 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, | 131 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE |
125 | }, | 132 | }, |
126 | 133 | ||
127 | [PERF_TYPE_RAW] = { | 134 | [PERF_TYPE_RAW] = { |
@@ -131,9 +138,10 @@ static struct { | |||
131 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | | 138 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | |
132 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | 139 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | |
133 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | | 140 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | |
134 | PERF_OUTPUT_PERIOD, | 141 | PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR | |
142 | PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT, | ||
135 | 143 | ||
136 | .invalid_fields = PERF_OUTPUT_TRACE, | 144 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, |
137 | }, | 145 | }, |
138 | 146 | ||
139 | [PERF_TYPE_BREAKPOINT] = { | 147 | [PERF_TYPE_BREAKPOINT] = { |
@@ -145,7 +153,7 @@ static struct { | |||
145 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | | 153 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | |
146 | PERF_OUTPUT_PERIOD, | 154 | PERF_OUTPUT_PERIOD, |
147 | 155 | ||
148 | .invalid_fields = PERF_OUTPUT_TRACE, | 156 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, |
149 | }, | 157 | }, |
150 | }; | 158 | }; |
151 | 159 | ||
@@ -242,6 +250,16 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
242 | PERF_OUTPUT_ADDR, allow_user_set)) | 250 | PERF_OUTPUT_ADDR, allow_user_set)) |
243 | return -EINVAL; | 251 | return -EINVAL; |
244 | 252 | ||
253 | if (PRINT_FIELD(DATA_SRC) && | ||
254 | perf_evsel__check_stype(evsel, PERF_SAMPLE_DATA_SRC, "DATA_SRC", | ||
255 | PERF_OUTPUT_DATA_SRC)) | ||
256 | return -EINVAL; | ||
257 | |||
258 | if (PRINT_FIELD(WEIGHT) && | ||
259 | perf_evsel__check_stype(evsel, PERF_SAMPLE_WEIGHT, "WEIGHT", | ||
260 | PERF_OUTPUT_WEIGHT)) | ||
261 | return -EINVAL; | ||
262 | |||
245 | if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { | 263 | if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { |
246 | pr_err("Display of symbols requested but neither sample IP nor " | 264 | pr_err("Display of symbols requested but neither sample IP nor " |
247 | "sample address\nis selected. Hence, no addresses to convert " | 265 | "sample address\nis selected. Hence, no addresses to convert " |
@@ -608,6 +626,84 @@ static void print_sample_flags(u32 flags) | |||
608 | printf(" %-4s ", str); | 626 | printf(" %-4s ", str); |
609 | } | 627 | } |
610 | 628 | ||
629 | struct printer_data { | ||
630 | int line_no; | ||
631 | bool hit_nul; | ||
632 | bool is_printable; | ||
633 | }; | ||
634 | |||
635 | static void | ||
636 | print_sample_bpf_output_printer(enum binary_printer_ops op, | ||
637 | unsigned int val, | ||
638 | void *extra) | ||
639 | { | ||
640 | unsigned char ch = (unsigned char)val; | ||
641 | struct printer_data *printer_data = extra; | ||
642 | |||
643 | switch (op) { | ||
644 | case BINARY_PRINT_DATA_BEGIN: | ||
645 | printf("\n"); | ||
646 | break; | ||
647 | case BINARY_PRINT_LINE_BEGIN: | ||
648 | printf("%17s", !printer_data->line_no ? "BPF output:" : | ||
649 | " "); | ||
650 | break; | ||
651 | case BINARY_PRINT_ADDR: | ||
652 | printf(" %04x:", val); | ||
653 | break; | ||
654 | case BINARY_PRINT_NUM_DATA: | ||
655 | printf(" %02x", val); | ||
656 | break; | ||
657 | case BINARY_PRINT_NUM_PAD: | ||
658 | printf(" "); | ||
659 | break; | ||
660 | case BINARY_PRINT_SEP: | ||
661 | printf(" "); | ||
662 | break; | ||
663 | case BINARY_PRINT_CHAR_DATA: | ||
664 | if (printer_data->hit_nul && ch) | ||
665 | printer_data->is_printable = false; | ||
666 | |||
667 | if (!isprint(ch)) { | ||
668 | printf("%c", '.'); | ||
669 | |||
670 | if (!printer_data->is_printable) | ||
671 | break; | ||
672 | |||
673 | if (ch == '\0') | ||
674 | printer_data->hit_nul = true; | ||
675 | else | ||
676 | printer_data->is_printable = false; | ||
677 | } else { | ||
678 | printf("%c", ch); | ||
679 | } | ||
680 | break; | ||
681 | case BINARY_PRINT_CHAR_PAD: | ||
682 | printf(" "); | ||
683 | break; | ||
684 | case BINARY_PRINT_LINE_END: | ||
685 | printf("\n"); | ||
686 | printer_data->line_no++; | ||
687 | break; | ||
688 | case BINARY_PRINT_DATA_END: | ||
689 | default: | ||
690 | break; | ||
691 | } | ||
692 | } | ||
693 | |||
694 | static void print_sample_bpf_output(struct perf_sample *sample) | ||
695 | { | ||
696 | unsigned int nr_bytes = sample->raw_size; | ||
697 | struct printer_data printer_data = {0, false, true}; | ||
698 | |||
699 | print_binary(sample->raw_data, nr_bytes, 8, | ||
700 | print_sample_bpf_output_printer, &printer_data); | ||
701 | |||
702 | if (printer_data.is_printable && printer_data.hit_nul) | ||
703 | printf("%17s \"%s\"\n", "BPF string:", | ||
704 | (char *)(sample->raw_data)); | ||
705 | } | ||
706 | |||
611 | struct perf_script { | 707 | struct perf_script { |
612 | struct perf_tool tool; | 708 | struct perf_tool tool; |
613 | struct perf_session *session; | 709 | struct perf_session *session; |
@@ -634,6 +730,23 @@ static int perf_evlist__max_name_len(struct perf_evlist *evlist) | |||
634 | return max; | 730 | return max; |
635 | } | 731 | } |
636 | 732 | ||
733 | static size_t data_src__printf(u64 data_src) | ||
734 | { | ||
735 | struct mem_info mi = { .data_src.val = data_src }; | ||
736 | char decode[100]; | ||
737 | char out[100]; | ||
738 | static int maxlen; | ||
739 | int len; | ||
740 | |||
741 | perf_script__meminfo_scnprintf(decode, 100, &mi); | ||
742 | |||
743 | len = scnprintf(out, 100, "%16" PRIx64 " %s", data_src, decode); | ||
744 | if (maxlen < len) | ||
745 | maxlen = len; | ||
746 | |||
747 | return printf("%-*s", maxlen, out); | ||
748 | } | ||
749 | |||
637 | static void process_event(struct perf_script *script, union perf_event *event, | 750 | static void process_event(struct perf_script *script, union perf_event *event, |
638 | struct perf_sample *sample, struct perf_evsel *evsel, | 751 | struct perf_sample *sample, struct perf_evsel *evsel, |
639 | struct addr_location *al) | 752 | struct addr_location *al) |
@@ -673,6 +786,12 @@ static void process_event(struct perf_script *script, union perf_event *event, | |||
673 | if (PRINT_FIELD(ADDR)) | 786 | if (PRINT_FIELD(ADDR)) |
674 | print_sample_addr(event, sample, thread, attr); | 787 | print_sample_addr(event, sample, thread, attr); |
675 | 788 | ||
789 | if (PRINT_FIELD(DATA_SRC)) | ||
790 | data_src__printf(sample->data_src); | ||
791 | |||
792 | if (PRINT_FIELD(WEIGHT)) | ||
793 | printf("%16" PRIu64, sample->weight); | ||
794 | |||
676 | if (PRINT_FIELD(IP)) { | 795 | if (PRINT_FIELD(IP)) { |
677 | if (!symbol_conf.use_callchain) | 796 | if (!symbol_conf.use_callchain) |
678 | printf(" "); | 797 | printf(" "); |
@@ -692,6 +811,9 @@ static void process_event(struct perf_script *script, union perf_event *event, | |||
692 | else if (PRINT_FIELD(BRSTACKSYM)) | 811 | else if (PRINT_FIELD(BRSTACKSYM)) |
693 | print_sample_brstacksym(event, sample, thread, attr); | 812 | print_sample_brstacksym(event, sample, thread, attr); |
694 | 813 | ||
814 | if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) | ||
815 | print_sample_bpf_output(sample); | ||
816 | |||
695 | printf("\n"); | 817 | printf("\n"); |
696 | } | 818 | } |
697 | 819 | ||
@@ -1090,23 +1212,6 @@ static struct script_spec *script_spec__find(const char *spec) | |||
1090 | return NULL; | 1212 | return NULL; |
1091 | } | 1213 | } |
1092 | 1214 | ||
1093 | static struct script_spec *script_spec__findnew(const char *spec, | ||
1094 | struct scripting_ops *ops) | ||
1095 | { | ||
1096 | struct script_spec *s = script_spec__find(spec); | ||
1097 | |||
1098 | if (s) | ||
1099 | return s; | ||
1100 | |||
1101 | s = script_spec__new(spec, ops); | ||
1102 | if (!s) | ||
1103 | return NULL; | ||
1104 | |||
1105 | script_spec__add(s); | ||
1106 | |||
1107 | return s; | ||
1108 | } | ||
1109 | |||
1110 | int script_spec_register(const char *spec, struct scripting_ops *ops) | 1215 | int script_spec_register(const char *spec, struct scripting_ops *ops) |
1111 | { | 1216 | { |
1112 | struct script_spec *s; | 1217 | struct script_spec *s; |
@@ -1115,9 +1220,11 @@ int script_spec_register(const char *spec, struct scripting_ops *ops) | |||
1115 | if (s) | 1220 | if (s) |
1116 | return -1; | 1221 | return -1; |
1117 | 1222 | ||
1118 | s = script_spec__findnew(spec, ops); | 1223 | s = script_spec__new(spec, ops); |
1119 | if (!s) | 1224 | if (!s) |
1120 | return -1; | 1225 | return -1; |
1226 | else | ||
1227 | script_spec__add(s); | ||
1121 | 1228 | ||
1122 | return 0; | 1229 | return 0; |
1123 | } | 1230 | } |