diff options
author | David Ahern <daahern@cisco.com> | 2011-03-10 00:23:28 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-03-14 16:07:20 -0400 |
commit | 1424dc96807909438282663079adc7f27c10b4a5 (patch) | |
tree | 1201a9cbe3bf34584f67ea3ddeef3c93bcd5ecc6 /tools | |
parent | c0230b2bfbd16e42d937c34aed99e5d6493eb5e4 (diff) |
perf script: Add support for H/W and S/W events
Custom fields set for each type by prepending field argument with type.
For file with multiple event types (e.g., trace and S/W) display of an
event type suppressed by setting output fields to "".
e.g.,
perf record -ga -e sched:sched_switch -e cpu-clock -c 10000000 -R -- sleep 1
perf script
openssl 11496 [000] 9711.807107: cpu-clock-msecs:
ffffffff810c22dc arch_local_irq_restore ([kernel.kallsyms])
ffffffff810c518c __alloc_pages_nodemask ([kernel.kallsyms])
ffffffff810297b2 pte_alloc_one ([kernel.kallsyms])
ffffffff810d8b98 __pte_alloc ([kernel.kallsyms])
ffffffff810daf07 handle_mm_fault ([kernel.kallsyms])
ffffffff8138763a do_page_fault ([kernel.kallsyms])
ffffffff81384a65 page_fault ([kernel.kallsyms])
7f6130507d70 asn1_check_tlen (/lib64/libcrypto.so.1.0.0c)
0 ()
openssl 11496 [000] 9711.808042: sched_switch: prev_comm=openssl ...
kworker/0:0 4 [000] 9711.808067: sched_switch: prev_comm=kworker/...
swapper 0 [001] 9711.808090: sched_switch: prev_comm=kworker/...
sshd 11451 [001] 9711.808185: sched_switch: prev_comm=sshd pre...
swapper 0 [001] 9711.816155: cpu-clock-msecs:
ffffffff81023609 native_safe_halt ([kernel.kallsyms])
ffffffff8100132a cpu_idle ([kernel.kallsyms])
ffffffff8137cf9b start_secondary ([kernel.kallsyms])
openssl 11496 [000] 9711.817104: cpu-clock-msecs:
7f61304ad723 AES_cbc_encrypt (/lib64/libcrypto.so.1.0.0c)
7fff3402f950 ()
12f0debc9a785634 ()
swapper 0 [001] 9711.826155: cpu-clock-msecs:
ffffffff81023609 native_safe_halt ([kernel.kallsyms])
ffffffff8100132a cpu_idle ([kernel.kallsyms])
ffffffff8137cf9b start_secondary ([kernel.kallsyms])
To suppress trace events within the file and use default output for S/W events:
perf script -f trace:
or to suppress S/W events and do default display for trace events:
perf script -f sw:
Custom field selections:
perf script -f sw:comm,tid,time -f trace:time,trace
openssl 11496 9711.797162:
swapper 0 9711.807071:
openssl 11496 9711.807107:
9711.808042: prev_comm=openssl prev_pid=11496 prev_prio=120 prev_state=R ...
9711.808067: prev_comm=kworker/0:0 prev_pid=4 prev_prio=120 prev_state=S ...
9711.808090: prev_comm=kworker/0:0 prev_pid=0 prev_prio=120 prev_state=R ...
9711.808185: prev_comm=sshd prev_pid=11451 prev_prio=120 prev_state=S ==>...
swapper 0 9711.816155:
openssl 11496 9711.817104:
swapper 0 9711.826155:
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-7-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.txt | 5 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 155 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 22 | ||||
-rw-r--r-- | tools/perf/util/parse-events.h | 1 |
4 files changed, 147 insertions, 36 deletions
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index c64118a4de49..66f040b30729 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -115,7 +115,10 @@ OPTIONS | |||
115 | -f:: | 115 | -f:: |
116 | --fields | 116 | --fields |
117 | Comma separated list of fields to print. Options are: | 117 | Comma separated list of fields to print. Options are: |
118 | comm, tid, pid, time, cpu, event, trace, sym | 118 | comm, tid, pid, time, cpu, event, trace, sym. Field |
119 | list must be prepended with the type, trace, sw or hw, | ||
120 | to indicate to which event type the field list applies. | ||
121 | e.g., -f sw:comm,tid,time,sym and -f trace:time,cpu,trace | ||
119 | 122 | ||
120 | -k:: | 123 | -k:: |
121 | --vmlinux=<file>:: | 124 | --vmlinux=<file>:: |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index b45b09c13f7a..9f5fc5492141 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -12,6 +12,8 @@ | |||
12 | #include "util/trace-event.h" | 12 | #include "util/trace-event.h" |
13 | #include "util/parse-options.h" | 13 | #include "util/parse-options.h" |
14 | #include "util/util.h" | 14 | #include "util/util.h" |
15 | #include "util/evlist.h" | ||
16 | #include "util/evsel.h" | ||
15 | 17 | ||
16 | static char const *script_name; | 18 | static char const *script_name; |
17 | static char const *generate_script_lang; | 19 | static char const *generate_script_lang; |
@@ -47,16 +49,65 @@ struct output_option { | |||
47 | }; | 49 | }; |
48 | 50 | ||
49 | /* default set to maintain compatibility with current format */ | 51 | /* default set to maintain compatibility with current format */ |
50 | static u64 output_fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ | 52 | static u64 output_fields[PERF_TYPE_MAX] = { |
51 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ | 53 | [PERF_TYPE_HARDWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ |
52 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE; | 54 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ |
55 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, | ||
56 | |||
57 | [PERF_TYPE_SOFTWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ | ||
58 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ | ||
59 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, | ||
60 | |||
61 | [PERF_TYPE_TRACEPOINT] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ | ||
62 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ | ||
63 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, | ||
64 | }; | ||
53 | 65 | ||
54 | static bool output_set_by_user; | 66 | static bool output_set_by_user; |
55 | 67 | ||
56 | #define PRINT_FIELD(x) (output_fields & PERF_OUTPUT_##x) | 68 | #define PRINT_FIELD(x) (output_fields[attr->type] & PERF_OUTPUT_##x) |
69 | |||
70 | static int perf_session__check_attr(struct perf_session *session, | ||
71 | struct perf_event_attr *attr) | ||
72 | { | ||
73 | if (PRINT_FIELD(TRACE) && | ||
74 | !perf_session__has_traces(session, "record -R")) | ||
75 | return -EINVAL; | ||
76 | |||
77 | if (PRINT_FIELD(SYM)) { | ||
78 | if (!(session->sample_type & PERF_SAMPLE_IP)) { | ||
79 | pr_err("Samples do not contain IP data.\n"); | ||
80 | return -EINVAL; | ||
81 | } | ||
82 | if (!no_callchain && | ||
83 | !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) | ||
84 | symbol_conf.use_callchain = false; | ||
85 | } | ||
86 | |||
87 | if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && | ||
88 | !(session->sample_type & PERF_SAMPLE_TID)) { | ||
89 | pr_err("Samples do not contain TID/PID data.\n"); | ||
90 | return -EINVAL; | ||
91 | } | ||
92 | |||
93 | if (PRINT_FIELD(TIME) && | ||
94 | !(session->sample_type & PERF_SAMPLE_TIME)) { | ||
95 | pr_err("Samples do not contain timestamps.\n"); | ||
96 | return -EINVAL; | ||
97 | } | ||
98 | |||
99 | if (PRINT_FIELD(CPU) && | ||
100 | !(session->sample_type & PERF_SAMPLE_CPU)) { | ||
101 | pr_err("Samples do not contain cpu.\n"); | ||
102 | return -EINVAL; | ||
103 | } | ||
104 | |||
105 | return 0; | ||
106 | } | ||
57 | 107 | ||
58 | static void print_sample_start(struct perf_sample *sample, | 108 | static void print_sample_start(struct perf_sample *sample, |
59 | struct thread *thread) | 109 | struct thread *thread, |
110 | struct perf_event_attr *attr) | ||
60 | { | 111 | { |
61 | int type; | 112 | int type; |
62 | struct event *event; | 113 | struct event *event; |
@@ -97,10 +148,13 @@ static void print_sample_start(struct perf_sample *sample, | |||
97 | } | 148 | } |
98 | 149 | ||
99 | if (PRINT_FIELD(EVNAME)) { | 150 | if (PRINT_FIELD(EVNAME)) { |
100 | type = trace_parse_common_type(sample->raw_data); | 151 | if (attr->type == PERF_TYPE_TRACEPOINT) { |
101 | event = trace_find_event(type); | 152 | type = trace_parse_common_type(sample->raw_data); |
102 | if (event) | 153 | event = trace_find_event(type); |
103 | evname = event->name; | 154 | if (event) |
155 | evname = event->name; | ||
156 | } else | ||
157 | evname = __event_name(attr->type, attr->config); | ||
104 | 158 | ||
105 | printf("%s: ", evname ? evname : "(unknown)"); | 159 | printf("%s: ", evname ? evname : "(unknown)"); |
106 | } | 160 | } |
@@ -108,10 +162,27 @@ static void print_sample_start(struct perf_sample *sample, | |||
108 | 162 | ||
109 | static void process_event(union perf_event *event __unused, | 163 | static void process_event(union perf_event *event __unused, |
110 | struct perf_sample *sample, | 164 | struct perf_sample *sample, |
111 | struct perf_session *session __unused, | 165 | struct perf_session *session, |
112 | struct thread *thread) | 166 | struct thread *thread) |
113 | { | 167 | { |
114 | print_sample_start(sample, thread); | 168 | struct perf_event_attr *attr; |
169 | struct perf_evsel *evsel; | ||
170 | |||
171 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); | ||
172 | if (evsel == NULL) { | ||
173 | pr_err("Invalid data. Contains samples with id not in " | ||
174 | "its header!\n"); | ||
175 | return; | ||
176 | } | ||
177 | attr = &evsel->attr; | ||
178 | |||
179 | if (output_fields[attr->type] == 0) | ||
180 | return; | ||
181 | |||
182 | if (perf_session__check_attr(session, attr) < 0) | ||
183 | return; | ||
184 | |||
185 | print_sample_start(sample, thread, attr); | ||
115 | 186 | ||
116 | if (PRINT_FIELD(TRACE)) | 187 | if (PRINT_FIELD(TRACE)) |
117 | print_trace_event(sample->cpu, sample->raw_data, | 188 | print_trace_event(sample->cpu, sample->raw_data, |
@@ -183,19 +254,17 @@ static int process_sample_event(union perf_event *event, | |||
183 | return -1; | 254 | return -1; |
184 | } | 255 | } |
185 | 256 | ||
186 | if (session->sample_type & PERF_SAMPLE_RAW) { | 257 | if (debug_mode) { |
187 | if (debug_mode) { | 258 | if (sample->time < last_timestamp) { |
188 | if (sample->time < last_timestamp) { | 259 | pr_err("Samples misordered, previous: %" PRIu64 |
189 | pr_err("Samples misordered, previous: %" PRIu64 | 260 | " this: %" PRIu64 "\n", last_timestamp, |
190 | " this: %" PRIu64 "\n", last_timestamp, | 261 | sample->time); |
191 | sample->time); | 262 | nr_unordered++; |
192 | nr_unordered++; | ||
193 | } | ||
194 | last_timestamp = sample->time; | ||
195 | return 0; | ||
196 | } | 263 | } |
197 | scripting_ops->process_event(event, sample, session, thread); | 264 | last_timestamp = sample->time; |
265 | return 0; | ||
198 | } | 266 | } |
267 | scripting_ops->process_event(event, sample, session, thread); | ||
199 | 268 | ||
200 | session->hists.stats.total_period += sample->period; | 269 | session->hists.stats.total_period += sample->period; |
201 | return 0; | 270 | return 0; |
@@ -391,21 +460,40 @@ static int parse_output_fields(const struct option *opt __used, | |||
391 | int i, imax = sizeof(all_output_options) / sizeof(struct output_option); | 460 | int i, imax = sizeof(all_output_options) / sizeof(struct output_option); |
392 | int rc = 0; | 461 | int rc = 0; |
393 | char *str = strdup(arg); | 462 | char *str = strdup(arg); |
463 | int type = -1; | ||
394 | 464 | ||
395 | if (!str) | 465 | if (!str) |
396 | return -ENOMEM; | 466 | return -ENOMEM; |
397 | 467 | ||
398 | tok = strtok(str, ","); | 468 | tok = strtok(str, ":"); |
399 | if (!tok) { | 469 | if (!tok) { |
400 | fprintf(stderr, "Invalid field string."); | 470 | fprintf(stderr, |
471 | "Invalid field string - not prepended with type."); | ||
472 | return -EINVAL; | ||
473 | } | ||
474 | |||
475 | /* first word should state which event type user | ||
476 | * is specifying the fields | ||
477 | */ | ||
478 | if (!strcmp(tok, "hw")) | ||
479 | type = PERF_TYPE_HARDWARE; | ||
480 | else if (!strcmp(tok, "sw")) | ||
481 | type = PERF_TYPE_SOFTWARE; | ||
482 | else if (!strcmp(tok, "trace")) | ||
483 | type = PERF_TYPE_TRACEPOINT; | ||
484 | else { | ||
485 | fprintf(stderr, "Invalid event type in field string."); | ||
401 | return -EINVAL; | 486 | return -EINVAL; |
402 | } | 487 | } |
403 | 488 | ||
404 | output_fields = 0; | 489 | output_fields[type] = 0; |
405 | while (1) { | 490 | while (1) { |
491 | tok = strtok(NULL, ","); | ||
492 | if (!tok) | ||
493 | break; | ||
406 | for (i = 0; i < imax; ++i) { | 494 | for (i = 0; i < imax; ++i) { |
407 | if (strcmp(tok, all_output_options[i].str) == 0) { | 495 | if (strcmp(tok, all_output_options[i].str) == 0) { |
408 | output_fields |= all_output_options[i].field; | 496 | output_fields[type] |= all_output_options[i].field; |
409 | break; | 497 | break; |
410 | } | 498 | } |
411 | } | 499 | } |
@@ -414,10 +502,11 @@ static int parse_output_fields(const struct option *opt __used, | |||
414 | rc = -EINVAL; | 502 | rc = -EINVAL; |
415 | break; | 503 | break; |
416 | } | 504 | } |
505 | } | ||
417 | 506 | ||
418 | tok = strtok(NULL, ","); | 507 | if (output_fields[type] == 0) { |
419 | if (!tok) | 508 | pr_debug("No fields requested for %s type. " |
420 | break; | 509 | "Events will not be displayed\n", event_type(type)); |
421 | } | 510 | } |
422 | 511 | ||
423 | output_set_by_user = true; | 512 | output_set_by_user = true; |
@@ -747,7 +836,7 @@ static const struct option options[] = { | |||
747 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 836 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
748 | "Look for files with symbols relative to this directory"), | 837 | "Look for files with symbols relative to this directory"), |
749 | OPT_CALLBACK('f', "fields", NULL, "str", | 838 | OPT_CALLBACK('f', "fields", NULL, "str", |
750 | "comma separated output fields. Options: comm,tid,pid,time,cpu,event,trace,sym", | 839 | "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace. Fields: comm,tid,pid,time,cpu,event,trace,sym", |
751 | parse_output_fields), | 840 | parse_output_fields), |
752 | 841 | ||
753 | OPT_END() | 842 | OPT_END() |
@@ -929,15 +1018,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
929 | if (session == NULL) | 1018 | if (session == NULL) |
930 | return -ENOMEM; | 1019 | return -ENOMEM; |
931 | 1020 | ||
932 | if (!no_callchain && (session->sample_type & PERF_SAMPLE_CALLCHAIN)) | 1021 | if (!no_callchain) |
933 | symbol_conf.use_callchain = true; | 1022 | symbol_conf.use_callchain = true; |
934 | else | 1023 | else |
935 | symbol_conf.use_callchain = false; | 1024 | symbol_conf.use_callchain = false; |
936 | 1025 | ||
937 | if (strcmp(input_name, "-") && | ||
938 | !perf_session__has_traces(session, "record -R")) | ||
939 | return -EINVAL; | ||
940 | |||
941 | if (generate_script_lang) { | 1026 | if (generate_script_lang) { |
942 | struct stat perf_stat; | 1027 | struct stat perf_stat; |
943 | int input; | 1028 | int input; |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 54a7e2634d58..952b4ae3d954 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -263,6 +263,28 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result) | |||
263 | return name; | 263 | return name; |
264 | } | 264 | } |
265 | 265 | ||
266 | const char *event_type(int type) | ||
267 | { | ||
268 | switch (type) { | ||
269 | case PERF_TYPE_HARDWARE: | ||
270 | return "hardware"; | ||
271 | |||
272 | case PERF_TYPE_SOFTWARE: | ||
273 | return "software"; | ||
274 | |||
275 | case PERF_TYPE_TRACEPOINT: | ||
276 | return "tracepoint"; | ||
277 | |||
278 | case PERF_TYPE_HW_CACHE: | ||
279 | return "hardware-cache"; | ||
280 | |||
281 | default: | ||
282 | break; | ||
283 | } | ||
284 | |||
285 | return "unknown"; | ||
286 | } | ||
287 | |||
266 | const char *event_name(struct perf_evsel *evsel) | 288 | const char *event_name(struct perf_evsel *evsel) |
267 | { | 289 | { |
268 | u64 config = evsel->attr.config; | 290 | u64 config = evsel->attr.config; |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 212f88e07a9c..746d3fcbfc2a 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -20,6 +20,7 @@ struct tracepoint_path { | |||
20 | extern struct tracepoint_path *tracepoint_id_to_path(u64 config); | 20 | extern struct tracepoint_path *tracepoint_id_to_path(u64 config); |
21 | extern bool have_tracepoints(struct list_head *evlist); | 21 | extern bool have_tracepoints(struct list_head *evlist); |
22 | 22 | ||
23 | const char *event_type(int type); | ||
23 | const char *event_name(struct perf_evsel *event); | 24 | const char *event_name(struct perf_evsel *event); |
24 | extern const char *__event_name(int type, u64 config); | 25 | extern const char *__event_name(int type, u64 config); |
25 | 26 | ||