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