1 // SPDX-License-Identifier: GPL-2.0
2 #include "tests.h"
3 #include "debug.h"
4 #include "evlist.h"
5 #include "cgroup.h"
6 #include "rblist.h"
7 #include "metricgroup.h"
8 #include "parse-events.h"
9 #include "pmu-events/pmu-events.h"
10 #include "pfm.h"
11 #include <subcmd/parse-options.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
test_expand_events(struct evlist * evlist)16 static int test_expand_events(struct evlist *evlist)
17 {
18 	int i, ret = TEST_FAIL;
19 	int nr_events;
20 	bool was_group_event;
21 	int nr_members;  /* for the first evsel only */
22 	const char cgrp_str[] = "A,B,C";
23 	const char *cgrp_name[] = { "A", "B", "C" };
24 	int nr_cgrps = ARRAY_SIZE(cgrp_name);
25 	char **ev_name;
26 	struct evsel *evsel;
27 
28 	TEST_ASSERT_VAL("evlist is empty", !evlist__empty(evlist));
29 
30 	nr_events = evlist->core.nr_entries;
31 	ev_name = calloc(nr_events, sizeof(*ev_name));
32 	if (ev_name == NULL) {
33 		pr_debug("memory allocation failure\n");
34 		return TEST_FAIL;
35 	}
36 	i = 0;
37 	evlist__for_each_entry(evlist, evsel) {
38 		ev_name[i] = strdup(evsel->name);
39 		if (ev_name[i] == NULL) {
40 			pr_debug("memory allocation failure\n");
41 			goto out;
42 		}
43 		i++;
44 	}
45 	/* remember grouping info */
46 	was_group_event = evsel__is_group_event(evlist__first(evlist));
47 	nr_members = evlist__first(evlist)->core.nr_members;
48 
49 	ret = evlist__expand_cgroup(evlist, cgrp_str, false);
50 	if (ret < 0) {
51 		pr_debug("failed to expand events for cgroups\n");
52 		goto out;
53 	}
54 
55 	ret = TEST_FAIL;
56 	if (evlist->core.nr_entries != nr_events * nr_cgrps) {
57 		pr_debug("event count doesn't match\n");
58 		goto out;
59 	}
60 
61 	i = 0;
62 	evlist__for_each_entry(evlist, evsel) {
63 		if (!evsel__name_is(evsel, ev_name[i % nr_events])) {
64 			pr_debug("event name doesn't match:\n");
65 			pr_debug("  evsel[%d]: %s\n  expected: %s\n",
66 				 i, evsel->name, ev_name[i % nr_events]);
67 			goto out;
68 		}
69 		if (strcmp(evsel->cgrp->name, cgrp_name[i / nr_events])) {
70 			pr_debug("cgroup name doesn't match:\n");
71 			pr_debug("  evsel[%d]: %s\n  expected: %s\n",
72 				 i, evsel->cgrp->name, cgrp_name[i / nr_events]);
73 			goto out;
74 		}
75 
76 		if ((i % nr_events) == 0) {
77 			if (evsel__is_group_event(evsel) != was_group_event) {
78 				pr_debug("event group doesn't match: got %s, expect %s\n",
79 					 evsel__is_group_event(evsel) ? "true" : "false",
80 					 was_group_event ? "true" : "false");
81 				goto out;
82 			}
83 			if (evsel->core.nr_members != nr_members) {
84 				pr_debug("event group member doesn't match: %d vs %d\n",
85 					 evsel->core.nr_members, nr_members);
86 				goto out;
87 			}
88 		}
89 		i++;
90 	}
91 	ret = TEST_OK;
92 
93 out:	for (i = 0; i < nr_events; i++)
94 		free(ev_name[i]);
95 	free(ev_name);
96 	return ret;
97 }
98 
expand_default_events(void)99 static int expand_default_events(void)
100 {
101 	int ret;
102 	struct evlist *evlist = evlist__new_default();
103 
104 	TEST_ASSERT_VAL("failed to get evlist", evlist);
105 
106 	ret = test_expand_events(evlist);
107 	evlist__delete(evlist);
108 	return ret;
109 }
110 
expand_group_events(void)111 static int expand_group_events(void)
112 {
113 	int ret;
114 	struct evlist *evlist;
115 	struct parse_events_error err;
116 	const char event_str[] = "{cycles,instructions}";
117 
118 	symbol_conf.event_group = true;
119 
120 	evlist = evlist__new();
121 	TEST_ASSERT_VAL("failed to get evlist", evlist);
122 
123 	parse_events_error__init(&err);
124 	ret = parse_events(evlist, event_str, &err);
125 	if (ret < 0) {
126 		pr_debug("failed to parse event '%s', err %d\n", event_str, ret);
127 		parse_events_error__print(&err, event_str);
128 		goto out;
129 	}
130 
131 	ret = test_expand_events(evlist);
132 out:
133 	parse_events_error__exit(&err);
134 	evlist__delete(evlist);
135 	return ret;
136 }
137 
expand_libpfm_events(void)138 static int expand_libpfm_events(void)
139 {
140 	int ret;
141 	struct evlist *evlist;
142 	const char event_str[] = "CYCLES";
143 	struct option opt = {
144 		.value = &evlist,
145 	};
146 
147 	symbol_conf.event_group = true;
148 
149 	evlist = evlist__new();
150 	TEST_ASSERT_VAL("failed to get evlist", evlist);
151 
152 	ret = parse_libpfm_events_option(&opt, event_str, 0);
153 	if (ret < 0) {
154 		pr_debug("failed to parse libpfm event '%s', err %d\n",
155 			 event_str, ret);
156 		goto out;
157 	}
158 	if (evlist__empty(evlist)) {
159 		pr_debug("libpfm was not enabled\n");
160 		goto out;
161 	}
162 
163 	ret = test_expand_events(evlist);
164 out:
165 	evlist__delete(evlist);
166 	return ret;
167 }
168 
expand_metric_events(void)169 static int expand_metric_events(void)
170 {
171 	int ret;
172 	struct evlist *evlist;
173 	const char metric_str[] = "CPI";
174 	const struct pmu_metrics_table *pme_test;
175 
176 	evlist = evlist__new();
177 	TEST_ASSERT_VAL("failed to get evlist", evlist);
178 
179 	pme_test = find_core_metrics_table("testarch", "testcpu");
180 	ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str);
181 	if (ret < 0) {
182 		pr_debug("failed to parse '%s' metric\n", metric_str);
183 		goto out;
184 	}
185 
186 	ret = test_expand_events(evlist);
187 
188 out:
189 	evlist__delete(evlist);
190 	return ret;
191 }
192 
test__expand_cgroup_events(struct test_suite * test __maybe_unused,int subtest __maybe_unused)193 static int test__expand_cgroup_events(struct test_suite *test __maybe_unused,
194 				      int subtest __maybe_unused)
195 {
196 	int ret;
197 
198 	ret = expand_default_events();
199 	TEST_ASSERT_EQUAL("failed to expand default events", ret, 0);
200 
201 	ret = expand_group_events();
202 	TEST_ASSERT_EQUAL("failed to expand event group", ret, 0);
203 
204 	ret = expand_libpfm_events();
205 	TEST_ASSERT_EQUAL("failed to expand event group", ret, 0);
206 
207 	ret = expand_metric_events();
208 	TEST_ASSERT_EQUAL("failed to expand metric events", ret, 0);
209 
210 	return ret;
211 }
212 
213 DEFINE_SUITE("Event expansion for cgroups", expand_cgroup_events);
214