Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / tools / perf / tests / hwmon_pmu.c
blobf8bcee9660d53324cf00deba1a485ec4b449aa7d
1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 #include "debug.h"
3 #include "evlist.h"
4 #include "hwmon_pmu.h"
5 #include "parse-events.h"
6 #include "tests.h"
7 #include <fcntl.h>
8 #include <sys/stat.h>
9 #include <linux/compiler.h>
10 #include <linux/kernel.h>
11 #include <linux/string.h>
13 static const struct test_event {
14 const char *name;
15 const char *alias;
16 long config;
17 } test_events[] = {
19 "temp_test_hwmon_event1",
20 "temp1",
21 0xA0001,
24 "temp_test_hwmon_event2",
25 "temp2",
26 0xA0002,
30 /* Cleanup test PMU directory. */
31 static int test_pmu_put(const char *dir, struct perf_pmu *hwm)
33 char buf[PATH_MAX + 20];
34 int ret;
36 if (scnprintf(buf, sizeof(buf), "rm -fr %s", dir) < 0) {
37 pr_err("Failure to set up buffer for \"%s\"\n", dir);
38 return -EINVAL;
40 ret = system(buf);
41 if (ret)
42 pr_err("Failure to \"%s\"\n", buf);
44 list_del(&hwm->list);
45 perf_pmu__delete(hwm);
46 return ret;
50 * Prepare test PMU directory data, normally exported by kernel at
51 * /sys/class/hwmon/hwmon<number>/. Give as input a buffer to hold the file
52 * path, the result is PMU loaded using that directory.
54 static struct perf_pmu *test_pmu_get(char *dir, size_t sz)
56 const char *test_hwmon_name_nl = "A test hwmon PMU\n";
57 const char *test_hwmon_name = "A test hwmon PMU";
58 /* Simulated hwmon items. */
59 const struct test_item {
60 const char *name;
61 const char *value;
62 } test_items[] = {
63 { "temp1_label", "test hwmon event1\n", },
64 { "temp1_input", "40000\n", },
65 { "temp2_label", "test hwmon event2\n", },
66 { "temp2_input", "50000\n", },
68 int dirfd, file;
69 struct perf_pmu *hwm = NULL;
70 ssize_t len;
72 /* Create equivalent of sysfs mount point. */
73 scnprintf(dir, sz, "/tmp/perf-hwmon-pmu-test-XXXXXX");
74 if (!mkdtemp(dir)) {
75 pr_err("mkdtemp failed\n");
76 dir[0] = '\0';
77 return NULL;
79 dirfd = open(dir, O_DIRECTORY);
80 if (dirfd < 0) {
81 pr_err("Failed to open test directory \"%s\"\n", dir);
82 goto err_out;
85 /* Create the test hwmon directory and give it a name. */
86 if (mkdirat(dirfd, "hwmon1234", 0755) < 0) {
87 pr_err("Failed to mkdir hwmon directory\n");
88 goto err_out;
90 file = openat(dirfd, "hwmon1234/name", O_WRONLY | O_CREAT, 0600);
91 if (!file) {
92 pr_err("Failed to open for writing file \"name\"\n");
93 goto err_out;
95 len = strlen(test_hwmon_name_nl);
96 if (write(file, test_hwmon_name_nl, len) < len) {
97 close(file);
98 pr_err("Failed to write to 'name' file\n");
99 goto err_out;
101 close(file);
103 /* Create test hwmon files. */
104 for (size_t i = 0; i < ARRAY_SIZE(test_items); i++) {
105 const struct test_item *item = &test_items[i];
107 file = openat(dirfd, item->name, O_WRONLY | O_CREAT, 0600);
108 if (!file) {
109 pr_err("Failed to open for writing file \"%s\"\n", item->name);
110 goto err_out;
113 if (write(file, item->value, strlen(item->value)) < 0) {
114 pr_err("Failed to write to file \"%s\"\n", item->name);
115 close(file);
116 goto err_out;
118 close(file);
121 /* Make the PMU reading the files created above. */
122 hwm = perf_pmus__add_test_hwmon_pmu(dirfd, "hwmon1234", test_hwmon_name);
123 if (!hwm)
124 pr_err("Test hwmon creation failed\n");
126 err_out:
127 if (!hwm) {
128 test_pmu_put(dir, hwm);
129 if (dirfd >= 0)
130 close(dirfd);
132 return hwm;
135 static int do_test(size_t i, bool with_pmu, bool with_alias)
137 const char *test_event = with_alias ? test_events[i].alias : test_events[i].name;
138 struct evlist *evlist = evlist__new();
139 struct evsel *evsel;
140 struct parse_events_error err;
141 int ret;
142 char str[128];
143 bool found = false;
145 if (!evlist) {
146 pr_err("evlist allocation failed\n");
147 return TEST_FAIL;
150 if (with_pmu)
151 snprintf(str, sizeof(str), "hwmon_a_test_hwmon_pmu/%s/", test_event);
152 else
153 strlcpy(str, test_event, sizeof(str));
155 pr_debug("Testing '%s'\n", str);
156 parse_events_error__init(&err);
157 ret = parse_events(evlist, str, &err);
158 if (ret) {
159 pr_debug("FAILED %s:%d failed to parse event '%s', err %d\n",
160 __FILE__, __LINE__, str, ret);
161 parse_events_error__print(&err, str);
162 ret = TEST_FAIL;
163 goto out;
166 ret = TEST_OK;
167 if (with_pmu ? (evlist->core.nr_entries != 1) : (evlist->core.nr_entries < 1)) {
168 pr_debug("FAILED %s:%d Unexpected number of events for '%s' of %d\n",
169 __FILE__, __LINE__, str, evlist->core.nr_entries);
170 ret = TEST_FAIL;
171 goto out;
174 evlist__for_each_entry(evlist, evsel) {
175 if (!evsel->pmu || !evsel->pmu->name ||
176 strcmp(evsel->pmu->name, "hwmon_a_test_hwmon_pmu"))
177 continue;
179 if (evsel->core.attr.config != (u64)test_events[i].config) {
180 pr_debug("FAILED %s:%d Unexpected config for '%s', %lld != %ld\n",
181 __FILE__, __LINE__, str,
182 evsel->core.attr.config,
183 test_events[i].config);
184 ret = TEST_FAIL;
185 goto out;
187 found = true;
190 if (!found) {
191 pr_debug("FAILED %s:%d Didn't find hwmon event '%s' in parsed evsels\n",
192 __FILE__, __LINE__, str);
193 ret = TEST_FAIL;
196 out:
197 parse_events_error__exit(&err);
198 evlist__delete(evlist);
199 return ret;
202 static int test__hwmon_pmu(bool with_pmu)
204 char dir[PATH_MAX];
205 struct perf_pmu *pmu = test_pmu_get(dir, sizeof(dir));
206 int ret = TEST_OK;
208 if (!pmu)
209 return TEST_FAIL;
211 for (size_t i = 0; i < ARRAY_SIZE(test_events); i++) {
212 ret = do_test(i, with_pmu, /*with_alias=*/false);
214 if (ret != TEST_OK)
215 break;
217 ret = do_test(i, with_pmu, /*with_alias=*/true);
219 if (ret != TEST_OK)
220 break;
222 test_pmu_put(dir, pmu);
223 return ret;
226 static int test__hwmon_pmu_without_pmu(struct test_suite *test __maybe_unused,
227 int subtest __maybe_unused)
229 return test__hwmon_pmu(/*with_pmu=*/false);
232 static int test__hwmon_pmu_with_pmu(struct test_suite *test __maybe_unused,
233 int subtest __maybe_unused)
235 return test__hwmon_pmu(/*with_pmu=*/true);
238 static int test__parse_hwmon_filename(struct test_suite *test __maybe_unused,
239 int subtest __maybe_unused)
241 const struct hwmon_parse_test {
242 const char *filename;
243 enum hwmon_type type;
244 int number;
245 enum hwmon_item item;
246 bool alarm;
247 bool parse_ok;
248 } tests[] = {
250 .filename = "cpu0_accuracy",
251 .type = HWMON_TYPE_CPU,
252 .number = 0,
253 .item = HWMON_ITEM_ACCURACY,
254 .alarm = false,
255 .parse_ok = true,
258 .filename = "temp1_input",
259 .type = HWMON_TYPE_TEMP,
260 .number = 1,
261 .item = HWMON_ITEM_INPUT,
262 .alarm = false,
263 .parse_ok = true,
266 .filename = "fan2_vid",
267 .type = HWMON_TYPE_FAN,
268 .number = 2,
269 .item = HWMON_ITEM_VID,
270 .alarm = false,
271 .parse_ok = true,
274 .filename = "power3_crit_alarm",
275 .type = HWMON_TYPE_POWER,
276 .number = 3,
277 .item = HWMON_ITEM_CRIT,
278 .alarm = true,
279 .parse_ok = true,
282 .filename = "intrusion4_average_interval_min_alarm",
283 .type = HWMON_TYPE_INTRUSION,
284 .number = 4,
285 .item = HWMON_ITEM_AVERAGE_INTERVAL_MIN,
286 .alarm = true,
287 .parse_ok = true,
290 .filename = "badtype5_baditem",
291 .type = HWMON_TYPE_NONE,
292 .number = 5,
293 .item = HWMON_ITEM_NONE,
294 .alarm = false,
295 .parse_ok = false,
298 .filename = "humidity6_baditem",
299 .type = HWMON_TYPE_NONE,
300 .number = 6,
301 .item = HWMON_ITEM_NONE,
302 .alarm = false,
303 .parse_ok = false,
307 for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
308 enum hwmon_type type;
309 int number;
310 enum hwmon_item item;
311 bool alarm;
313 TEST_ASSERT_EQUAL("parse_hwmon_filename",
314 parse_hwmon_filename(
315 tests[i].filename,
316 &type,
317 &number,
318 &item,
319 &alarm),
320 tests[i].parse_ok
322 if (tests[i].parse_ok) {
323 TEST_ASSERT_EQUAL("parse_hwmon_filename type", type, tests[i].type);
324 TEST_ASSERT_EQUAL("parse_hwmon_filename number", number, tests[i].number);
325 TEST_ASSERT_EQUAL("parse_hwmon_filename item", item, tests[i].item);
326 TEST_ASSERT_EQUAL("parse_hwmon_filename alarm", alarm, tests[i].alarm);
329 return TEST_OK;
332 static struct test_case tests__hwmon_pmu[] = {
333 TEST_CASE("Basic parsing test", parse_hwmon_filename),
334 TEST_CASE("Parsing without PMU name", hwmon_pmu_without_pmu),
335 TEST_CASE("Parsing with PMU name", hwmon_pmu_with_pmu),
336 { .name = NULL, }
339 struct test_suite suite__hwmon_pmu = {
340 .desc = "Hwmon PMU",
341 .test_cases = tests__hwmon_pmu,