diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-script.c | 111 | ||||
-rw-r--r-- | tools/perf/util/session.c | 12 | ||||
-rw-r--r-- | tools/perf/util/session.h | 3 |
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 */ |
52 | static struct { | 52 | static 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 | ||
108 | static 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 | ||
109 | static int perf_session__check_attr(struct perf_session *session, | 124 | static 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 | |||
152 | static 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 | */ | ||
193 | static 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 | ||
1159 | struct 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 | |||
1159 | void perf_session__print_symbols(union perf_event *event, | 1171 | void 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 | ||
165 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | ||
166 | unsigned int type); | ||
167 | |||
165 | void perf_session__print_symbols(union perf_event *event, | 168 | void 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); |