aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDavid Ahern <daahern@cisco.com>2011-04-06 23:54:20 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-04-20 06:27:52 -0400
commit9cbdb702092a2d82f909312f4ec3eeded77bb82e (patch)
treedb5f06a2b534c2731c5da085a5a995b230c0091c /tools
parent0817a6a3a4fc7c069111083351ca33a78da2a0c9 (diff)
perf script: improve validation of sample attributes for output fields
Check for required sample attributes using evsel rather than sample_type in the session header. If the attribute for a default field is not present for the event type (e.g., new command operating on file from older kernel) the field is removed from the output list. Expected event types must exist. For example, if a user specifies -f trace:time,trace -f sw:time,cpu,sym the perf.data file must contain both tracepoints and software events (ie., it is an error if either does not exist in the file). Attribute checking is done once at the beginning of perf-script rather than for each sample. v1 -> v2: - addressed comments from acme Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/1302148460-570-1-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/builtin-script.c111
-rw-r--r--tools/perf/util/session.c12
-rw-r--r--tools/perf/util/session.h3
3 files changed, 109 insertions, 17 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b3012c4fff19..974f6d3f4e53 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -51,6 +51,7 @@ struct output_option {
51/* default set to maintain compatibility with current format */ 51/* default set to maintain compatibility with current format */
52static struct { 52static struct {
53 bool user_set; 53 bool user_set;
54 bool wildcard_set;
54 u64 fields; 55 u64 fields;
55 u64 invalid_fields; 56 u64 invalid_fields;
56} output[PERF_TYPE_MAX] = { 57} output[PERF_TYPE_MAX] = {
@@ -104,41 +105,113 @@ static bool output_set_by_user(void)
104 return false; 105 return false;
105} 106}
106 107
108static const char *output_field2str(enum perf_output_field field)
109{
110 int i, imax = ARRAY_SIZE(all_output_options);
111 const char *str = "";
112
113 for (i = 0; i < imax; ++i) {
114 if (all_output_options[i].field == field) {
115 str = all_output_options[i].str;
116 break;
117 }
118 }
119 return str;
120}
121
107#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) 122#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x)
108 123
109static int perf_session__check_attr(struct perf_session *session, 124static int perf_event_attr__check_stype(struct perf_event_attr *attr,
110 struct perf_event_attr *attr) 125 u64 sample_type, const char *sample_msg,
126 enum perf_output_field field)
111{ 127{
128 int type = attr->type;
129 const char *evname;
130
131 if (attr->sample_type & sample_type)
132 return 0;
133
134 if (output[type].user_set) {
135 evname = __event_name(attr->type, attr->config);
136 pr_err("Samples for '%s' event do not have %s attribute set. "
137 "Cannot print '%s' field.\n",
138 evname, sample_msg, output_field2str(field));
139 return -1;
140 }
141
142 /* user did not ask for it explicitly so remove from the default list */
143 output[type].fields &= ~field;
144 evname = __event_name(attr->type, attr->config);
145 pr_debug("Samples for '%s' event do not have %s attribute set. "
146 "Skipping '%s' field.\n",
147 evname, sample_msg, output_field2str(field));
148
149 return 0;
150}
151
152static int perf_evsel__check_attr(struct perf_evsel *evsel,
153 struct perf_session *session)
154{
155 struct perf_event_attr *attr = &evsel->attr;
156
112 if (PRINT_FIELD(TRACE) && 157 if (PRINT_FIELD(TRACE) &&
113 !perf_session__has_traces(session, "record -R")) 158 !perf_session__has_traces(session, "record -R"))
114 return -EINVAL; 159 return -EINVAL;
115 160
116 if (PRINT_FIELD(SYM)) { 161 if (PRINT_FIELD(SYM)) {
117 if (!(session->sample_type & PERF_SAMPLE_IP)) { 162 if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
118 pr_err("Samples do not contain IP data.\n"); 163 PERF_OUTPUT_SYM))
119 return -EINVAL; 164 return -EINVAL;
120 } 165
121 if (!no_callchain && 166 if (!no_callchain &&
122 !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) 167 !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
123 symbol_conf.use_callchain = false; 168 symbol_conf.use_callchain = false;
124 } 169 }
125 170
126 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && 171 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
127 !(session->sample_type & PERF_SAMPLE_TID)) { 172 perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
128 pr_err("Samples do not contain TID/PID data.\n"); 173 PERF_OUTPUT_TID|PERF_OUTPUT_PID))
129 return -EINVAL; 174 return -EINVAL;
130 }
131 175
132 if (PRINT_FIELD(TIME) && 176 if (PRINT_FIELD(TIME) &&
133 !(session->sample_type & PERF_SAMPLE_TIME)) { 177 perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME",
134 pr_err("Samples do not contain timestamps.\n"); 178 PERF_OUTPUT_TIME))
135 return -EINVAL; 179 return -EINVAL;
136 }
137 180
138 if (PRINT_FIELD(CPU) && 181 if (PRINT_FIELD(CPU) &&
139 !(session->sample_type & PERF_SAMPLE_CPU)) { 182 perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU",
140 pr_err("Samples do not contain cpu.\n"); 183 PERF_OUTPUT_CPU))
141 return -EINVAL; 184 return -EINVAL;
185
186 return 0;
187}
188
189/*
190 * verify all user requested events exist and the samples
191 * have the expected data
192 */
193static int perf_session__check_output_opt(struct perf_session *session)
194{
195 int j;
196 struct perf_evsel *evsel;
197
198 for (j = 0; j < PERF_TYPE_MAX; ++j) {
199 evsel = perf_session__find_first_evtype(session, j);
200
201 /*
202 * even if fields is set to 0 (ie., show nothing) event must
203 * exist if user explicitly includes it on the command line
204 */
205 if (!evsel && output[j].user_set && !output[j].wildcard_set) {
206 pr_err("%s events do not exist. "
207 "Remove corresponding -f option to proceed.\n",
208 event_type(j));
209 return -1;
210 }
211
212 if (evsel && output[j].fields &&
213 perf_evsel__check_attr(evsel, session))
214 return -1;
142 } 215 }
143 216
144 return 0; 217 return 0;
@@ -210,9 +283,6 @@ static void process_event(union perf_event *event __unused,
210 if (output[attr->type].fields == 0) 283 if (output[attr->type].fields == 0)
211 return; 284 return;
212 285
213 if (perf_session__check_attr(session, attr) < 0)
214 return;
215
216 print_sample_start(sample, thread, attr); 286 print_sample_start(sample, thread, attr);
217 287
218 if (PRINT_FIELD(TRACE)) 288 if (PRINT_FIELD(TRACE))
@@ -525,6 +595,7 @@ static int parse_output_fields(const struct option *opt __used,
525 595
526 output[type].fields = 0; 596 output[type].fields = 0;
527 output[type].user_set = true; 597 output[type].user_set = true;
598 output[type].wildcard_set = false;
528 599
529 } else { 600 } else {
530 tok = str; 601 tok = str;
@@ -541,6 +612,7 @@ static int parse_output_fields(const struct option *opt __used,
541 for (j = 0; j < PERF_TYPE_MAX; ++j) { 612 for (j = 0; j < PERF_TYPE_MAX; ++j) {
542 output[j].fields = 0; 613 output[j].fields = 0;
543 output[j].user_set = true; 614 output[j].user_set = true;
615 output[j].wildcard_set = true;
544 } 616 }
545 } 617 }
546 618
@@ -1145,6 +1217,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
1145 pr_debug("perf script started with script %s\n\n", script_name); 1217 pr_debug("perf script started with script %s\n\n", script_name);
1146 } 1218 }
1147 1219
1220
1221 err = perf_session__check_output_opt(session);
1222 if (err < 0)
1223 goto out;
1224
1148 err = __cmd_script(session); 1225 err = __cmd_script(session);
1149 1226
1150 perf_session__delete(session); 1227 perf_session__delete(session);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index caa224522fea..fff66741f18d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1156,6 +1156,18 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1156 return ret; 1156 return ret;
1157} 1157}
1158 1158
1159struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1160 unsigned int type)
1161{
1162 struct perf_evsel *pos;
1163
1164 list_for_each_entry(pos, &session->evlist->entries, node) {
1165 if (pos->attr.type == type)
1166 return pos;
1167 }
1168 return NULL;
1169}
1170
1159void perf_session__print_symbols(union perf_event *event, 1171void perf_session__print_symbols(union perf_event *event,
1160 struct perf_sample *sample, 1172 struct perf_sample *sample,
1161 struct perf_session *session) 1173 struct perf_session *session)
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 1ac481fc1100..8daaa2d15396 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -162,6 +162,9 @@ static inline int perf_session__parse_sample(struct perf_session *session,
162 session->sample_id_all, sample); 162 session->sample_id_all, sample);
163} 163}
164 164
165struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
166 unsigned int type);
167
165void perf_session__print_symbols(union perf_event *event, 168void perf_session__print_symbols(union perf_event *event,
166 struct perf_sample *sample, 169 struct perf_sample *sample,
167 struct perf_session *session); 170 struct perf_session *session);