diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 74 |
1 files changed, 58 insertions, 16 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 4bce7d8679cb..2999e7e425f6 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -119,6 +119,11 @@ struct output_option { | |||
119 | {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, | 119 | {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, |
120 | }; | 120 | }; |
121 | 121 | ||
122 | enum { | ||
123 | OUTPUT_TYPE_SYNTH = PERF_TYPE_MAX, | ||
124 | OUTPUT_TYPE_MAX | ||
125 | }; | ||
126 | |||
122 | /* default set to maintain compatibility with current format */ | 127 | /* default set to maintain compatibility with current format */ |
123 | static struct { | 128 | static struct { |
124 | bool user_set; | 129 | bool user_set; |
@@ -126,7 +131,7 @@ static struct { | |||
126 | unsigned int print_ip_opts; | 131 | unsigned int print_ip_opts; |
127 | u64 fields; | 132 | u64 fields; |
128 | u64 invalid_fields; | 133 | u64 invalid_fields; |
129 | } output[PERF_TYPE_MAX] = { | 134 | } output[OUTPUT_TYPE_MAX] = { |
130 | 135 | ||
131 | [PERF_TYPE_HARDWARE] = { | 136 | [PERF_TYPE_HARDWARE] = { |
132 | .user_set = false, | 137 | .user_set = false, |
@@ -184,12 +189,43 @@ static struct { | |||
184 | 189 | ||
185 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, | 190 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, |
186 | }, | 191 | }, |
192 | |||
193 | [OUTPUT_TYPE_SYNTH] = { | ||
194 | .user_set = false, | ||
195 | |||
196 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | | ||
197 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | | ||
198 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | ||
199 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO, | ||
200 | |||
201 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, | ||
202 | }, | ||
187 | }; | 203 | }; |
188 | 204 | ||
205 | static inline int output_type(unsigned int type) | ||
206 | { | ||
207 | switch (type) { | ||
208 | case PERF_TYPE_SYNTH: | ||
209 | return OUTPUT_TYPE_SYNTH; | ||
210 | default: | ||
211 | return type; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | static inline unsigned int attr_type(unsigned int type) | ||
216 | { | ||
217 | switch (type) { | ||
218 | case OUTPUT_TYPE_SYNTH: | ||
219 | return PERF_TYPE_SYNTH; | ||
220 | default: | ||
221 | return type; | ||
222 | } | ||
223 | } | ||
224 | |||
189 | static bool output_set_by_user(void) | 225 | static bool output_set_by_user(void) |
190 | { | 226 | { |
191 | int j; | 227 | int j; |
192 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 228 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
193 | if (output[j].user_set) | 229 | if (output[j].user_set) |
194 | return true; | 230 | return true; |
195 | } | 231 | } |
@@ -210,7 +246,7 @@ static const char *output_field2str(enum perf_output_field field) | |||
210 | return str; | 246 | return str; |
211 | } | 247 | } |
212 | 248 | ||
213 | #define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) | 249 | #define PRINT_FIELD(x) (output[output_type(attr->type)].fields & PERF_OUTPUT_##x) |
214 | 250 | ||
215 | static int perf_evsel__do_check_stype(struct perf_evsel *evsel, | 251 | static int perf_evsel__do_check_stype(struct perf_evsel *evsel, |
216 | u64 sample_type, const char *sample_msg, | 252 | u64 sample_type, const char *sample_msg, |
@@ -218,7 +254,7 @@ static int perf_evsel__do_check_stype(struct perf_evsel *evsel, | |||
218 | bool allow_user_set) | 254 | bool allow_user_set) |
219 | { | 255 | { |
220 | struct perf_event_attr *attr = &evsel->attr; | 256 | struct perf_event_attr *attr = &evsel->attr; |
221 | int type = attr->type; | 257 | int type = output_type(attr->type); |
222 | const char *evname; | 258 | const char *evname; |
223 | 259 | ||
224 | if (attr->sample_type & sample_type) | 260 | if (attr->sample_type & sample_type) |
@@ -348,7 +384,7 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
348 | 384 | ||
349 | static void set_print_ip_opts(struct perf_event_attr *attr) | 385 | static void set_print_ip_opts(struct perf_event_attr *attr) |
350 | { | 386 | { |
351 | unsigned int type = attr->type; | 387 | unsigned int type = output_type(attr->type); |
352 | 388 | ||
353 | output[type].print_ip_opts = 0; | 389 | output[type].print_ip_opts = 0; |
354 | if (PRINT_FIELD(IP)) | 390 | if (PRINT_FIELD(IP)) |
@@ -376,14 +412,15 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
376 | unsigned int j; | 412 | unsigned int j; |
377 | struct perf_evsel *evsel; | 413 | struct perf_evsel *evsel; |
378 | 414 | ||
379 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 415 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
380 | evsel = perf_session__find_first_evtype(session, j); | 416 | evsel = perf_session__find_first_evtype(session, attr_type(j)); |
381 | 417 | ||
382 | /* | 418 | /* |
383 | * even if fields is set to 0 (ie., show nothing) event must | 419 | * even if fields is set to 0 (ie., show nothing) event must |
384 | * exist if user explicitly includes it on the command line | 420 | * exist if user explicitly includes it on the command line |
385 | */ | 421 | */ |
386 | if (!evsel && output[j].user_set && !output[j].wildcard_set) { | 422 | if (!evsel && output[j].user_set && !output[j].wildcard_set && |
423 | j != OUTPUT_TYPE_SYNTH) { | ||
387 | pr_err("%s events do not exist. " | 424 | pr_err("%s events do not exist. " |
388 | "Remove corresponding -F option to proceed.\n", | 425 | "Remove corresponding -F option to proceed.\n", |
389 | event_type(j)); | 426 | event_type(j)); |
@@ -989,6 +1026,7 @@ static void print_sample_bts(struct perf_sample *sample, | |||
989 | struct machine *machine) | 1026 | struct machine *machine) |
990 | { | 1027 | { |
991 | struct perf_event_attr *attr = &evsel->attr; | 1028 | struct perf_event_attr *attr = &evsel->attr; |
1029 | unsigned int type = output_type(attr->type); | ||
992 | bool print_srcline_last = false; | 1030 | bool print_srcline_last = false; |
993 | 1031 | ||
994 | if (PRINT_FIELD(CALLINDENT)) | 1032 | if (PRINT_FIELD(CALLINDENT)) |
@@ -996,7 +1034,7 @@ static void print_sample_bts(struct perf_sample *sample, | |||
996 | 1034 | ||
997 | /* print branch_from information */ | 1035 | /* print branch_from information */ |
998 | if (PRINT_FIELD(IP)) { | 1036 | if (PRINT_FIELD(IP)) { |
999 | unsigned int print_opts = output[attr->type].print_ip_opts; | 1037 | unsigned int print_opts = output[type].print_ip_opts; |
1000 | struct callchain_cursor *cursor = NULL; | 1038 | struct callchain_cursor *cursor = NULL; |
1001 | 1039 | ||
1002 | if (symbol_conf.use_callchain && sample->callchain && | 1040 | if (symbol_conf.use_callchain && sample->callchain && |
@@ -1019,7 +1057,7 @@ static void print_sample_bts(struct perf_sample *sample, | |||
1019 | /* print branch_to information */ | 1057 | /* print branch_to information */ |
1020 | if (PRINT_FIELD(ADDR) || | 1058 | if (PRINT_FIELD(ADDR) || |
1021 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && | 1059 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && |
1022 | !output[attr->type].user_set)) { | 1060 | !output[type].user_set)) { |
1023 | printf(" => "); | 1061 | printf(" => "); |
1024 | print_sample_addr(sample, thread, attr); | 1062 | print_sample_addr(sample, thread, attr); |
1025 | } | 1063 | } |
@@ -1215,8 +1253,9 @@ static void process_event(struct perf_script *script, | |||
1215 | { | 1253 | { |
1216 | struct thread *thread = al->thread; | 1254 | struct thread *thread = al->thread; |
1217 | struct perf_event_attr *attr = &evsel->attr; | 1255 | struct perf_event_attr *attr = &evsel->attr; |
1256 | unsigned int type = output_type(attr->type); | ||
1218 | 1257 | ||
1219 | if (output[attr->type].fields == 0) | 1258 | if (output[type].fields == 0) |
1220 | return; | 1259 | return; |
1221 | 1260 | ||
1222 | print_sample_start(sample, thread, evsel); | 1261 | print_sample_start(sample, thread, evsel); |
@@ -1263,7 +1302,7 @@ static void process_event(struct perf_script *script, | |||
1263 | cursor = &callchain_cursor; | 1302 | cursor = &callchain_cursor; |
1264 | 1303 | ||
1265 | putchar(cursor ? '\n' : ' '); | 1304 | putchar(cursor ? '\n' : ' '); |
1266 | sample__fprintf_sym(sample, al, 0, output[attr->type].print_ip_opts, cursor, stdout); | 1305 | sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, stdout); |
1267 | } | 1306 | } |
1268 | 1307 | ||
1269 | if (PRINT_FIELD(IREGS)) | 1308 | if (PRINT_FIELD(IREGS)) |
@@ -1410,7 +1449,8 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, | |||
1410 | evlist = *pevlist; | 1449 | evlist = *pevlist; |
1411 | evsel = perf_evlist__last(*pevlist); | 1450 | evsel = perf_evlist__last(*pevlist); |
1412 | 1451 | ||
1413 | if (evsel->attr.type >= PERF_TYPE_MAX) | 1452 | if (evsel->attr.type >= PERF_TYPE_MAX && |
1453 | evsel->attr.type != PERF_TYPE_SYNTH) | ||
1414 | return 0; | 1454 | return 0; |
1415 | 1455 | ||
1416 | evlist__for_each_entry(evlist, pos) { | 1456 | evlist__for_each_entry(evlist, pos) { |
@@ -1835,6 +1875,8 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
1835 | type = PERF_TYPE_RAW; | 1875 | type = PERF_TYPE_RAW; |
1836 | else if (!strcmp(str, "break")) | 1876 | else if (!strcmp(str, "break")) |
1837 | type = PERF_TYPE_BREAKPOINT; | 1877 | type = PERF_TYPE_BREAKPOINT; |
1878 | else if (!strcmp(str, "synth")) | ||
1879 | type = OUTPUT_TYPE_SYNTH; | ||
1838 | else { | 1880 | else { |
1839 | fprintf(stderr, "Invalid event type in field string.\n"); | 1881 | fprintf(stderr, "Invalid event type in field string.\n"); |
1840 | rc = -EINVAL; | 1882 | rc = -EINVAL; |
@@ -1865,7 +1907,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
1865 | if (output_set_by_user()) | 1907 | if (output_set_by_user()) |
1866 | pr_warning("Overriding previous field request for all events.\n"); | 1908 | pr_warning("Overriding previous field request for all events.\n"); |
1867 | 1909 | ||
1868 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 1910 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
1869 | output[j].fields = 0; | 1911 | output[j].fields = 0; |
1870 | output[j].user_set = true; | 1912 | output[j].user_set = true; |
1871 | output[j].wildcard_set = true; | 1913 | output[j].wildcard_set = true; |
@@ -1908,7 +1950,7 @@ parse: | |||
1908 | /* add user option to all events types for | 1950 | /* add user option to all events types for |
1909 | * which it is valid | 1951 | * which it is valid |
1910 | */ | 1952 | */ |
1911 | for (j = 0; j < PERF_TYPE_MAX; ++j) { | 1953 | for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { |
1912 | if (output[j].invalid_fields & all_output_options[i].field) { | 1954 | if (output[j].invalid_fields & all_output_options[i].field) { |
1913 | pr_warning("\'%s\' not valid for %s events. Ignoring.\n", | 1955 | pr_warning("\'%s\' not valid for %s events. Ignoring.\n", |
1914 | all_output_options[i].str, event_type(j)); | 1956 | all_output_options[i].str, event_type(j)); |
@@ -2560,7 +2602,7 @@ int cmd_script(int argc, const char **argv) | |||
2560 | OPT_CALLBACK('F', "fields", NULL, "str", | 2602 | OPT_CALLBACK('F', "fields", NULL, "str", |
2561 | "comma separated output fields prepend with 'type:'. " | 2603 | "comma separated output fields prepend with 'type:'. " |
2562 | "+field to add and -field to remove." | 2604 | "+field to add and -field to remove." |
2563 | "Valid types: hw,sw,trace,raw. " | 2605 | "Valid types: hw,sw,trace,raw,synth. " |
2564 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," | 2606 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
2565 | "addr,symoff,period,iregs,brstack,brstacksym,flags," | 2607 | "addr,symoff,period,iregs,brstack,brstacksym,flags," |
2566 | "bpf-output,callindent,insn,insnlen,brstackinsn", | 2608 | "bpf-output,callindent,insn,insnlen,brstackinsn", |