xref: /linux/tools/perf/tests/uncore-event-sorting.c (revision 05d2a3da153bc08c5fe7937584b5d86505747b9e)
1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 #include <string.h>
3 
4 #include "debug.h"
5 #include "evlist.h"
6 #include "parse-events.h"
7 #include "pmu.h"
8 #include "pmus.h"
9 #include "tests.h"
10 
11 struct match_state {
12 	char *event1;
13 	char *event2;
14 };
15 
16 static char *clean_event_name(struct pmu_event_info *info)
17 {
18 	const char *name = info->name;
19 	const char *pmu_name = info->pmu->name;
20 	size_t pmu_len = strlen(pmu_name);
21 	char *res;
22 	size_t len;
23 
24 	if (!strncmp(name, pmu_name, pmu_len) && name[pmu_len] == '/')
25 		name += pmu_len + 1;
26 
27 	res = strdup(name);
28 	if (!res)
29 		return NULL;
30 
31 	len = strlen(res);
32 	if (len > 0 && res[len - 1] == '/')
33 		res[len - 1] = '\0';
34 
35 	return res;
36 }
37 
38 static int event_cb(void *state, struct pmu_event_info *info)
39 {
40 	struct match_state *m = state;
41 	char *clean_name;
42 
43 	if (m->event1 && m->event2)
44 		return 1;
45 
46 	clean_name = clean_event_name(info);
47 	if (!clean_name)
48 		return 0;
49 
50 	if (!m->event1) {
51 		m->event1 = clean_name;
52 	} else {
53 		if (strcmp(m->event1, clean_name)) {
54 			m->event2 = clean_name;
55 			return 1;
56 		}
57 		free(clean_name);
58 	}
59 	return 0;
60 }
61 
62 #define CHECK_COND(cond, text)					\
63 do {								\
64 	if (!(cond)) {						\
65 		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
66 		ret = TEST_FAIL;				\
67 		goto out_err;					\
68 	}							\
69 } while (0)
70 
71 #define CHECK_EQUAL(val, expected, text)			\
72 do {								\
73 	if ((val) != (expected)) {				\
74 		pr_debug("FAILED %s:%d %s (%d != %d)\n",	\
75 			 __FILE__, __LINE__, text, (val), (expected)); \
76 		ret = TEST_FAIL;				\
77 		goto out_err;					\
78 	}							\
79 } while (0)
80 
81 static int test__uncore_event_sorting(struct test_suite *test __maybe_unused,
82 				      int subtest __maybe_unused)
83 {
84 	struct evlist *evlist = NULL;
85 	struct parse_events_error err;
86 	struct evsel *evsel;
87 	struct perf_pmu *pmu = NULL;
88 	char *pmu_prefix = NULL;
89 	struct match_state m = { NULL, NULL };
90 	char buf[1024];
91 	int ret;
92 
93 	parse_events_error__init(&err);
94 
95 	while ((pmu = perf_pmus__scan(pmu)) != NULL) {
96 		size_t len;
97 		struct perf_pmu *sibling;
98 
99 		if (pmu->is_core)
100 			continue;
101 
102 		len = pmu_name_len_no_suffix(pmu->name);
103 		if (len == strlen(pmu->name))
104 			continue;
105 
106 		sibling = pmu;
107 		while ((sibling = perf_pmus__scan(sibling)) != NULL) {
108 			if (sibling->is_core)
109 				continue;
110 			if (pmu_name_len_no_suffix(sibling->name) == len &&
111 			    !strncmp(pmu->name, sibling->name, len))
112 				break;
113 		}
114 
115 		if (!sibling)
116 			continue;
117 
118 		m.event1 = m.event2 = NULL;
119 		perf_pmu__for_each_event(pmu, false, &m, event_cb);
120 
121 		if (m.event1 && m.event2) {
122 			pmu_prefix = strndup(pmu->name, len);
123 			break;
124 		}
125 		zfree(&m.event1);
126 	}
127 
128 	if (!pmu_prefix) {
129 		pr_debug("No suitable uncore PMU found\n");
130 		ret = TEST_SKIP;
131 		goto out_err;
132 	}
133 
134 	evlist = evlist__new();
135 	if (!evlist) {
136 		ret = TEST_FAIL;
137 		goto out_err;
138 	}
139 
140 	snprintf(buf, sizeof(buf), "{%s/%s/,%s/%s/}", pmu_prefix, m.event1, pmu_prefix, m.event2);
141 	pr_debug("Parsing: %s\n", buf);
142 
143 	ret = parse_events(evlist, buf, &err);
144 	if (ret) {
145 		pr_debug("parse_events failed\n");
146 		ret = TEST_FAIL;
147 		goto out_err;
148 	}
149 
150 	CHECK_COND(evlist->core.nr_entries >= 4, "Number of events is >= 4");
151 	CHECK_EQUAL(evlist->core.nr_entries % 2, 0, "Number of events is a multiple of 2");
152 
153 	evlist__for_each_entry(evlist, evsel) {
154 		struct evsel *next;
155 
156 		if (!evsel__is_group_leader(evsel))
157 			continue;
158 
159 		next = evsel__next(evsel);
160 		CHECK_EQUAL(evsel->core.nr_members, 2, "Group size is 2");
161 		CHECK_COND(evsel->pmu == next->pmu, "PMU match");
162 		CHECK_COND(strstr(evsel__name(evsel), m.event1) != NULL, "First event name");
163 		CHECK_COND(strstr(evsel__name(next), m.event2) != NULL, "Second event name");
164 	}
165 	ret = TEST_OK;
166 
167 out_err:
168 	evlist__delete(evlist);
169 	parse_events_error__exit(&err);
170 	zfree(&pmu_prefix);
171 	zfree(&m.event1);
172 	zfree(&m.event2);
173 	return ret;
174 }
175 
176 DEFINE_SUITE("Uncore event sorting", uncore_event_sorting);
177