diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 141 |
1 files changed, 125 insertions, 16 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 0a79da21df23..c046e6e8600a 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -20,6 +20,38 @@ static u64 last_timestamp; | |||
20 | static u64 nr_unordered; | 20 | static u64 nr_unordered; |
21 | extern const struct option record_options[]; | 21 | extern const struct option record_options[]; |
22 | 22 | ||
23 | enum perf_output_field { | ||
24 | PERF_OUTPUT_COMM = 1U << 0, | ||
25 | PERF_OUTPUT_TID = 1U << 1, | ||
26 | PERF_OUTPUT_PID = 1U << 2, | ||
27 | PERF_OUTPUT_TIME = 1U << 3, | ||
28 | PERF_OUTPUT_CPU = 1U << 4, | ||
29 | PERF_OUTPUT_EVNAME = 1U << 5, | ||
30 | PERF_OUTPUT_TRACE = 1U << 6, | ||
31 | }; | ||
32 | |||
33 | struct output_option { | ||
34 | const char *str; | ||
35 | enum perf_output_field field; | ||
36 | } all_output_options[] = { | ||
37 | {.str = "comm", .field = PERF_OUTPUT_COMM}, | ||
38 | {.str = "tid", .field = PERF_OUTPUT_TID}, | ||
39 | {.str = "pid", .field = PERF_OUTPUT_PID}, | ||
40 | {.str = "time", .field = PERF_OUTPUT_TIME}, | ||
41 | {.str = "cpu", .field = PERF_OUTPUT_CPU}, | ||
42 | {.str = "event", .field = PERF_OUTPUT_EVNAME}, | ||
43 | {.str = "trace", .field = PERF_OUTPUT_TRACE}, | ||
44 | }; | ||
45 | |||
46 | /* default set to maintain compatibility with current format */ | ||
47 | static u64 output_fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ | ||
48 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ | ||
49 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE; | ||
50 | |||
51 | static bool output_set_by_user; | ||
52 | |||
53 | #define PRINT_FIELD(x) (output_fields & PERF_OUTPUT_##x) | ||
54 | |||
23 | static void print_sample_start(struct perf_sample *sample, | 55 | static void print_sample_start(struct perf_sample *sample, |
24 | struct thread *thread) | 56 | struct thread *thread) |
25 | { | 57 | { |
@@ -28,24 +60,45 @@ static void print_sample_start(struct perf_sample *sample, | |||
28 | const char *evname = NULL; | 60 | const char *evname = NULL; |
29 | unsigned long secs; | 61 | unsigned long secs; |
30 | unsigned long usecs; | 62 | unsigned long usecs; |
31 | unsigned long long nsecs = sample->time; | 63 | unsigned long long nsecs; |
64 | |||
65 | if (PRINT_FIELD(COMM)) { | ||
66 | if (latency_format) | ||
67 | printf("%8.8s ", thread->comm); | ||
68 | else | ||
69 | printf("%16s ", thread->comm); | ||
70 | } | ||
32 | 71 | ||
33 | if (latency_format) | 72 | if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) |
34 | printf("%8.8s-%-5d %3d", thread->comm, sample->tid, sample->cpu); | 73 | printf("%5d/%-5d ", sample->pid, sample->tid); |
35 | else | 74 | else if (PRINT_FIELD(PID)) |
36 | printf("%16s-%-5d [%03d]", thread->comm, sample->tid, sample->cpu); | 75 | printf("%5d ", sample->pid); |
76 | else if (PRINT_FIELD(TID)) | ||
77 | printf("%5d ", sample->tid); | ||
78 | |||
79 | if (PRINT_FIELD(CPU)) { | ||
80 | if (latency_format) | ||
81 | printf("%3d ", sample->cpu); | ||
82 | else | ||
83 | printf("[%03d] ", sample->cpu); | ||
84 | } | ||
37 | 85 | ||
38 | secs = nsecs / NSECS_PER_SEC; | 86 | if (PRINT_FIELD(TIME)) { |
39 | nsecs -= secs * NSECS_PER_SEC; | 87 | nsecs = sample->time; |
40 | usecs = nsecs / NSECS_PER_USEC; | 88 | secs = nsecs / NSECS_PER_SEC; |
41 | printf(" %5lu.%06lu: ", secs, usecs); | 89 | nsecs -= secs * NSECS_PER_SEC; |
90 | usecs = nsecs / NSECS_PER_USEC; | ||
91 | printf("%5lu.%06lu: ", secs, usecs); | ||
92 | } | ||
42 | 93 | ||
43 | type = trace_parse_common_type(sample->raw_data); | 94 | if (PRINT_FIELD(EVNAME)) { |
44 | event = trace_find_event(type); | 95 | type = trace_parse_common_type(sample->raw_data); |
45 | if (event) | 96 | event = trace_find_event(type); |
46 | evname = event->name; | 97 | if (event) |
98 | evname = event->name; | ||
47 | 99 | ||
48 | printf("%s: ", evname ? evname : "(unknown)"); | 100 | printf("%s: ", evname ? evname : "(unknown)"); |
101 | } | ||
49 | } | 102 | } |
50 | 103 | ||
51 | static void process_event(union perf_event *event __unused, | 104 | static void process_event(union perf_event *event __unused, |
@@ -54,7 +107,11 @@ static void process_event(union perf_event *event __unused, | |||
54 | struct thread *thread) | 107 | struct thread *thread) |
55 | { | 108 | { |
56 | print_sample_start(sample, thread); | 109 | print_sample_start(sample, thread); |
57 | print_trace_event(sample->cpu, sample->raw_data, sample->raw_size); | 110 | |
111 | if (PRINT_FIELD(TRACE)) | ||
112 | print_trace_event(sample->cpu, sample->raw_data, | ||
113 | sample->raw_size); | ||
114 | |||
58 | printf("\n"); | 115 | printf("\n"); |
59 | } | 116 | } |
60 | 117 | ||
@@ -311,6 +368,48 @@ static int parse_scriptname(const struct option *opt __used, | |||
311 | return 0; | 368 | return 0; |
312 | } | 369 | } |
313 | 370 | ||
371 | static int parse_output_fields(const struct option *opt __used, | ||
372 | const char *arg, int unset __used) | ||
373 | { | ||
374 | char *tok; | ||
375 | int i, imax = sizeof(all_output_options) / sizeof(struct output_option); | ||
376 | int rc = 0; | ||
377 | char *str = strdup(arg); | ||
378 | |||
379 | if (!str) | ||
380 | return -ENOMEM; | ||
381 | |||
382 | tok = strtok(str, ","); | ||
383 | if (!tok) { | ||
384 | fprintf(stderr, "Invalid field string."); | ||
385 | return -EINVAL; | ||
386 | } | ||
387 | |||
388 | output_fields = 0; | ||
389 | while (1) { | ||
390 | for (i = 0; i < imax; ++i) { | ||
391 | if (strcmp(tok, all_output_options[i].str) == 0) { | ||
392 | output_fields |= all_output_options[i].field; | ||
393 | break; | ||
394 | } | ||
395 | } | ||
396 | if (i == imax) { | ||
397 | fprintf(stderr, "Invalid field requested."); | ||
398 | rc = -EINVAL; | ||
399 | break; | ||
400 | } | ||
401 | |||
402 | tok = strtok(NULL, ","); | ||
403 | if (!tok) | ||
404 | break; | ||
405 | } | ||
406 | |||
407 | output_set_by_user = true; | ||
408 | |||
409 | free(str); | ||
410 | return rc; | ||
411 | } | ||
412 | |||
314 | /* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */ | 413 | /* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */ |
315 | static int is_directory(const char *base_path, const struct dirent *dent) | 414 | static int is_directory(const char *base_path, const struct dirent *dent) |
316 | { | 415 | { |
@@ -623,6 +722,9 @@ static const struct option options[] = { | |||
623 | "input file name"), | 722 | "input file name"), |
624 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, | 723 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, |
625 | "do various checks like samples ordering and lost events"), | 724 | "do various checks like samples ordering and lost events"), |
725 | OPT_CALLBACK('f', "fields", NULL, "str", | ||
726 | "comma separated output fields. Options: comm,tid,pid,time,cpu,event,trace", | ||
727 | parse_output_fields), | ||
626 | 728 | ||
627 | OPT_END() | 729 | OPT_END() |
628 | }; | 730 | }; |
@@ -809,8 +911,15 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
809 | 911 | ||
810 | if (generate_script_lang) { | 912 | if (generate_script_lang) { |
811 | struct stat perf_stat; | 913 | struct stat perf_stat; |
914 | int input; | ||
915 | |||
916 | if (output_set_by_user) { | ||
917 | fprintf(stderr, | ||
918 | "custom fields not supported for generated scripts"); | ||
919 | return -1; | ||
920 | } | ||
812 | 921 | ||
813 | int input = open(input_name, O_RDONLY); | 922 | input = open(input_name, O_RDONLY); |
814 | if (input < 0) { | 923 | if (input < 0) { |
815 | perror("failed to open file"); | 924 | perror("failed to open file"); |
816 | exit(-1); | 925 | exit(-1); |