}
pr_debug("Parsing metric events '%s'\n", events.buf);
parse_events_error__init(&parse_error);
- ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu);
+ ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu,
+ /*warn_if_reordered=*/false);
if (ret) {
parse_events_error__print(&parse_error, events.buf);
goto err_out;
return arch_evlist__cmp(lhs, rhs);
}
-static void parse_events__sort_events_and_fix_groups(struct list_head *list)
+static bool parse_events__sort_events_and_fix_groups(struct list_head *list)
{
- int idx = -1;
+ int idx = 0, unsorted_idx = -1;
struct evsel *pos, *cur_leader = NULL;
struct perf_evsel *cur_leaders_grp = NULL;
+ bool idx_changed = false;
+ int orig_num_leaders = 0, num_leaders = 0;
/*
* Compute index to insert ungrouped events at. Place them where the
list_for_each_entry(pos, list, core.node) {
const struct evsel *pos_leader = evsel__leader(pos);
- if (pos != pos_leader || pos->core.nr_members > 1)
- continue;
+ if (pos == pos_leader)
+ orig_num_leaders++;
- idx = pos->core.idx;
- break;
+ /*
+ * Ensure indexes are sequential, in particular for multiple
+ * event lists being merged. The indexes are used to detect when
+ * the user order is modified.
+ */
+ pos->core.idx = idx++;
+
+ if (unsorted_idx == -1 && pos == pos_leader && pos->core.nr_members < 2)
+ unsorted_idx = pos->core.idx;
}
/* Sort events. */
- list_sort(&idx, list, evlist__cmp);
+ list_sort(&unsorted_idx, list, evlist__cmp);
/*
* Recompute groups, splitting for PMUs and adding groups for events
bool force_grouped = arch_evsel__must_be_in_group(pos);
/* Reset index and nr_members. */
+ if (pos->core.idx != idx)
+ idx_changed = true;
pos->core.idx = idx++;
pos->core.nr_members = 0;
}
}
list_for_each_entry(pos, list, core.node) {
- pos->core.leader->nr_members++;
+ struct evsel *pos_leader = evsel__leader(pos);
+
+ if (pos == pos_leader)
+ num_leaders++;
+ pos_leader->core.nr_members++;
}
+ return idx_changed || num_leaders != orig_num_leaders;
}
int __parse_events(struct evlist *evlist, const char *str,
- struct parse_events_error *err, struct perf_pmu *fake_pmu)
+ struct parse_events_error *err, struct perf_pmu *fake_pmu,
+ bool warn_if_reordered)
{
struct parse_events_state parse_state = {
.list = LIST_HEAD_INIT(parse_state.list),
return -1;
}
- parse_events__sort_events_and_fix_groups(&parse_state.list);
+ if (parse_events__sort_events_and_fix_groups(&parse_state.list) &&
+ warn_if_reordered && !parse_state.wild_card_pmus)
+ pr_warning("WARNING: events were regrouped to match PMUs\n");
/*
* Add list to the evlist even with errors to allow callers to clean up.
int parse_events_option_new_evlist(const struct option *opt, const char *str, int unset);
__attribute__((nonnull(1, 2, 3)))
int __parse_events(struct evlist *evlist, const char *str, struct parse_events_error *error,
- struct perf_pmu *fake_pmu);
+ struct perf_pmu *fake_pmu, bool warn_if_reordered);
-__attribute__((nonnull))
+__attribute__((nonnull(1, 2, 3)))
static inline int parse_events(struct evlist *evlist, const char *str,
struct parse_events_error *err)
{
- return __parse_events(evlist, str, err, NULL);
+ return __parse_events(evlist, str, err, /*fake_pmu=*/NULL, /*warn_if_reordered=*/true);
}
int parse_event(struct evlist *evlist, const char *str);
int stoken;
struct perf_pmu *fake_pmu;
char *hybrid_pmu_name;
+ bool wild_card_pmus;
};
void parse_events__shrink_config_terms(void);