aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDavid Ahern <daahern@cisco.com>2011-03-10 00:23:28 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-03-14 16:07:20 -0400
commit1424dc96807909438282663079adc7f27c10b4a5 (patch)
tree1201a9cbe3bf34584f67ea3ddeef3c93bcd5ecc6 /tools
parentc0230b2bfbd16e42d937c34aed99e5d6493eb5e4 (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.txt5
-rw-r--r--tools/perf/builtin-script.c155
-rw-r--r--tools/perf/util/parse-events.c22
-rw-r--r--tools/perf/util/parse-events.h1
4 files changed, 147 insertions, 36 deletions
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index c64118a4de4..66f040b3072 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 b45b09c13f7..9f5fc549214 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
16static char const *script_name; 18static char const *script_name;
17static char const *generate_script_lang; 19static 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 */
50static u64 output_fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ 52static 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
54static bool output_set_by_user; 66static 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
70static 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
58static void print_sample_start(struct perf_sample *sample, 108static 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
109static void process_event(union perf_event *event __unused, 163static 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 54a7e2634d5..952b4ae3d95 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
266const 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
266const char *event_name(struct perf_evsel *evsel) 288const 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 212f88e07a9..746d3fcbfc2 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -20,6 +20,7 @@ struct tracepoint_path {
20extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 20extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
21extern bool have_tracepoints(struct list_head *evlist); 21extern bool have_tracepoints(struct list_head *evlist);
22 22
23const char *event_type(int type);
23const char *event_name(struct perf_evsel *event); 24const char *event_name(struct perf_evsel *event);
24extern const char *__event_name(int type, u64 config); 25extern const char *__event_name(int type, u64 config);
25 26