Commit 8dcd27b1 authored by Ian Rogers's avatar Ian Rogers Committed by Namhyung Kim
Browse files

perf parse-events: Fix missing slots for Intel topdown metric events



Topdown metric events require grouping with a slots event. In perf
metrics this is currently achieved by metrics adding an unnecessary
"0 * tma_info_thread_slots". New TMA metrics trigger optimizations of
the metric expression that removes the event and breaks the metric due
to the missing but required event. Add a pass immediately before
sorting and fixing parsed events, that insert a slots event if one is
missing. Update test expectations to match this.

Signed-off-by: default avatarIan Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250719030517.1990983-15-irogers@google.com


Signed-off-by: default avatarNamhyung Kim <namhyung@kernel.org>
parent 5b546de9
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -81,3 +81,27 @@ int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs)
	/* Default ordering by insertion index. */
	return lhs->core.idx - rhs->core.idx;
}

int arch_evlist__add_required_events(struct list_head *list)
{
	struct evsel *pos, *metric_event = NULL;
	int idx = 0;

	if (!topdown_sys_has_perf_metrics())
		return 0;

	list_for_each_entry(pos, list, core.node) {
		if (arch_is_topdown_slots(pos)) {
			/* Slots event already present, nothing to do. */
			return 0;
		}
		if (metric_event == NULL && arch_is_topdown_metrics(pos))
			metric_event = pos;
		idx++;
	}
	if (metric_event == NULL) {
		/* No topdown metric events, nothing to do. */
		return 0;
	}
	return topdown_insert_slots_event(list, idx + 1, metric_event);
}
+28 −0
Original line number Diff line number Diff line
@@ -77,3 +77,31 @@ bool arch_topdown_sample_read(struct evsel *leader)

	return false;
}

/*
 * Make a copy of the topdown metric event metric_event with the given index but
 * change its configuration to be a topdown slots event. Copying from
 * metric_event ensures modifiers are the same.
 */
int topdown_insert_slots_event(struct list_head *list, int idx, struct evsel *metric_event)
{
	struct evsel *evsel = evsel__new_idx(&metric_event->core.attr, idx);

	if (!evsel)
		return -ENOMEM;

	evsel->core.attr.config = TOPDOWN_SLOTS;
	evsel->core.cpus = perf_cpu_map__get(metric_event->core.cpus);
	evsel->core.pmu_cpus = perf_cpu_map__get(metric_event->core.pmu_cpus);
	evsel->core.is_pmu_core = true;
	evsel->pmu = metric_event->pmu;
	evsel->name = strdup("slots");
	evsel->precise_max = metric_event->precise_max;
	evsel->sample_read = metric_event->sample_read;
	evsel->weak_group = metric_event->weak_group;
	evsel->bpf_counter = metric_event->bpf_counter;
	evsel->retire_lat = metric_event->retire_lat;
	evsel__set_leader(evsel, evsel__leader(metric_event));
	list_add_tail(&evsel->core.node, list);
	return 0;
}
+2 −0
Original line number Diff line number Diff line
@@ -5,9 +5,11 @@
#include <stdbool.h>

struct evsel;
struct list_head;

bool topdown_sys_has_perf_metrics(void);
bool arch_is_topdown_slots(const struct evsel *evsel);
bool arch_is_topdown_metrics(const struct evsel *evsel);
int topdown_insert_slots_event(struct list_head *list, int idx, struct evsel *metric_event);

#endif
+12 −12
Original line number Diff line number Diff line
@@ -719,20 +719,20 @@ static int test__checkevent_pmu_partial_time_callgraph(struct evlist *evlist)

static int test__checkevent_pmu_events(struct evlist *evlist)
{
	struct evsel *evsel = evlist__first(evlist);
	struct evsel *evsel;

	TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
	TEST_ASSERT_VAL("wrong number of entries", 1 <= evlist->core.nr_entries);

	evlist__for_each_entry(evlist, evsel) {
		TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type ||
					      strcmp(evsel->pmu->name, "cpu"));
	TEST_ASSERT_VAL("wrong exclude_user",
			!evsel->core.attr.exclude_user);
	TEST_ASSERT_VAL("wrong exclude_kernel",
			evsel->core.attr.exclude_kernel);
		TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
		TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
		TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
		TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip);
		TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned);
		TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive);

	}
	return TEST_OK;
}

+1 −0
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ void evlist__add(struct evlist *evlist, struct evsel *entry);
void evlist__remove(struct evlist *evlist, struct evsel *evsel);

int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs);
int arch_evlist__add_required_events(struct list_head *list);

int evlist__add_dummy(struct evlist *evlist);
struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
Loading