aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDavid Ahern <daahern@cisco.com>2011-03-10 00:23:26 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-03-14 16:06:16 -0400
commit745f43e3433a7939bd9c351c8106e0c1db2044c6 (patch)
tree68955a0bd5e4d179194bf3296c946e5bf745dae8 /tools
parentc70c94b47405d2c94df19c16273daf1f5fb9193d (diff)
perf script: Support custom field selection for output
Allow a user to select which fields to print to stdout for event data. Options include comm (command name), tid (thread id), pid (process id), time (perf timestamp), cpu, event (for event name), and trace (for trace data). Default is set to maintain compatibility with current output; this feature does alter output format slightly -- no '-' between command and pid/tid. Thanks to Frederic Weisbecker for detailed suggestions on this approach. Examples (output compressed) 1. trace, default format perf record -ga -e sched:sched_switch perf script swapper 0 [000] 537.037184: sched_switch: prev_comm=swapper prev_pid=0... sshd 1675 [000] 537.037309: sched_switch: prev_comm=sshd prev_pid=1675... netstat 1692 [001] 537.038664: sched_switch: prev_comm=netstat prev_pid=1692... 2. trace, custom format perf record -ga -e sched:sched_switch perf script -f comm,pid,time,trace <--- omitting cpu and event name swapper 0 537.037184: prev_comm=swapper prev_pid=0 prev_prio=120 ... sshd 1675 537.037309: prev_comm=sshd prev_pid=1675 prev_prio=120 ... netstat 1692 537.038664: prev_comm=netstat prev_pid=1692 prev_prio=120 ... Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> LKML-Reference: <1299734608-5223-5-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern <daahern@cisco.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-script.txt5
-rw-r--r--tools/perf/builtin-script.c141
2 files changed, 130 insertions, 16 deletions
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 29ad94293cd2..b73cf589c109 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -112,6 +112,11 @@ OPTIONS
112--debug-mode:: 112--debug-mode::
113 Do various checks like samples ordering and lost events. 113 Do various checks like samples ordering and lost events.
114 114
115-f::
116--fields
117 Comma separated list of fields to print. Options are:
118 comm, tid, pid, time, cpu, event, trace
119
115SEE ALSO 120SEE ALSO
116-------- 121--------
117linkperf:perf-record[1], linkperf:perf-script-perl[1], 122linkperf:perf-record[1], linkperf:perf-script-perl[1],
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;
20static u64 nr_unordered; 20static u64 nr_unordered;
21extern const struct option record_options[]; 21extern const struct option record_options[];
22 22
23enum 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
33struct 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 */
47static u64 output_fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
48 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
49 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE;
50
51static bool output_set_by_user;
52
53#define PRINT_FIELD(x) (output_fields & PERF_OUTPUT_##x)
54
23static void print_sample_start(struct perf_sample *sample, 55static 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
51static void process_event(union perf_event *event __unused, 104static 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
371static 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 */
315static int is_directory(const char *base_path, const struct dirent *dent) 414static 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);