/* default set to maintain compatibility with current format */
static struct {
bool user_set;
+ bool wildcard_set;
u64 fields;
u64 invalid_fields;
} output[PERF_TYPE_MAX] = {
return false;
}
+static const char *output_field2str(enum perf_output_field field)
+{
+ int i, imax = ARRAY_SIZE(all_output_options);
+ const char *str = "";
+
+ for (i = 0; i < imax; ++i) {
+ if (all_output_options[i].field == field) {
+ str = all_output_options[i].str;
+ break;
+ }
+ }
+ return str;
+}
+
#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x)
-static int perf_session__check_attr(struct perf_session *session,
- struct perf_event_attr *attr)
+static int perf_event_attr__check_stype(struct perf_event_attr *attr,
+ u64 sample_type, const char *sample_msg,
+ enum perf_output_field field)
{
+ int type = attr->type;
+ const char *evname;
+
+ if (attr->sample_type & sample_type)
+ return 0;
+
+ if (output[type].user_set) {
+ evname = __event_name(attr->type, attr->config);
+ pr_err("Samples for '%s' event do not have %s attribute set. "
+ "Cannot print '%s' field.\n",
+ evname, sample_msg, output_field2str(field));
+ return -1;
+ }
+
+ /* user did not ask for it explicitly so remove from the default list */
+ output[type].fields &= ~field;
+ evname = __event_name(attr->type, attr->config);
+ pr_debug("Samples for '%s' event do not have %s attribute set. "
+ "Skipping '%s' field.\n",
+ evname, sample_msg, output_field2str(field));
+
+ return 0;
+}
+
+static int perf_evsel__check_attr(struct perf_evsel *evsel,
+ struct perf_session *session)
+{
+ struct perf_event_attr *attr = &evsel->attr;
+
if (PRINT_FIELD(TRACE) &&
!perf_session__has_traces(session, "record -R"))
return -EINVAL;
if (PRINT_FIELD(SYM)) {
- if (!(session->sample_type & PERF_SAMPLE_IP)) {
- pr_err("Samples do not contain IP data.\n");
+ if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
+ PERF_OUTPUT_SYM))
return -EINVAL;
- }
+
if (!no_callchain &&
- !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
+ !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
symbol_conf.use_callchain = false;
}
if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
- !(session->sample_type & PERF_SAMPLE_TID)) {
- pr_err("Samples do not contain TID/PID data.\n");
+ perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
+ PERF_OUTPUT_TID|PERF_OUTPUT_PID))
return -EINVAL;
- }
if (PRINT_FIELD(TIME) &&
- !(session->sample_type & PERF_SAMPLE_TIME)) {
- pr_err("Samples do not contain timestamps.\n");
+ perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME",
+ PERF_OUTPUT_TIME))
return -EINVAL;
- }
if (PRINT_FIELD(CPU) &&
- !(session->sample_type & PERF_SAMPLE_CPU)) {
- pr_err("Samples do not contain cpu.\n");
+ perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU",
+ PERF_OUTPUT_CPU))
return -EINVAL;
+
+ return 0;
+}
+
+/*
+ * verify all user requested events exist and the samples
+ * have the expected data
+ */
+static int perf_session__check_output_opt(struct perf_session *session)
+{
+ int j;
+ struct perf_evsel *evsel;
+
+ for (j = 0; j < PERF_TYPE_MAX; ++j) {
+ evsel = perf_session__find_first_evtype(session, j);
+
+ /*
+ * even if fields is set to 0 (ie., show nothing) event must
+ * exist if user explicitly includes it on the command line
+ */
+ if (!evsel && output[j].user_set && !output[j].wildcard_set) {
+ pr_err("%s events do not exist. "
+ "Remove corresponding -f option to proceed.\n",
+ event_type(j));
+ return -1;
+ }
+
+ if (evsel && output[j].fields &&
+ perf_evsel__check_attr(evsel, session))
+ return -1;
}
return 0;
if (output[attr->type].fields == 0)
return;
- if (perf_session__check_attr(session, attr) < 0)
- return;
-
print_sample_start(sample, thread, attr);
if (PRINT_FIELD(TRACE))
output[type].fields = 0;
output[type].user_set = true;
+ output[type].wildcard_set = false;
} else {
tok = str;
for (j = 0; j < PERF_TYPE_MAX; ++j) {
output[j].fields = 0;
output[j].user_set = true;
+ output[j].wildcard_set = true;
}
}
pr_debug("perf script started with script %s\n\n", script_name);
}
+
+ err = perf_session__check_output_opt(session);
+ if (err < 0)
+ goto out;
+
err = __cmd_script(session);
perf_session__delete(session);