| // SPDX-License-Identifier: GPL-2.0 | |
| #include "parse-events.h" | |
| #include "pmu.h" | |
| #include "util.h" | |
| #include "tests.h" | |
| #include <errno.h> | |
| #include <linux/kernel.h> | |
| /* Simulated format definitions. */ | |
| static struct test_format { | |
| const char *name; | |
| const char *value; | |
| } test_formats[] = { | |
| { "krava01", "config:0-1,62-63\n", }, | |
| { "krava02", "config:10-17\n", }, | |
| { "krava03", "config:5\n", }, | |
| { "krava11", "config1:0,2,4,6,8,20-28\n", }, | |
| { "krava12", "config1:63\n", }, | |
| { "krava13", "config1:45-47\n", }, | |
| { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", }, | |
| { "krava22", "config2:8,18,48,58\n", }, | |
| { "krava23", "config2:28-29,38\n", }, | |
| }; | |
| /* Simulated users input. */ | |
| static struct parse_events_term test_terms[] = { | |
| { | |
| .config = (char *) "krava01", | |
| .val.num = 15, | |
| .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | |
| .type_term = PARSE_EVENTS__TERM_TYPE_USER, | |
| }, | |
| { | |
| .config = (char *) "krava02", | |
| .val.num = 170, | |
| .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | |
| .type_term = PARSE_EVENTS__TERM_TYPE_USER, | |
| }, | |
| { | |
| .config = (char *) "krava03", | |
| .val.num = 1, | |
| .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | |
| .type_term = PARSE_EVENTS__TERM_TYPE_USER, | |
| }, | |
| { | |
| .config = (char *) "krava11", | |
| .val.num = 27, | |
| .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | |
| .type_term = PARSE_EVENTS__TERM_TYPE_USER, | |
| }, | |
| { | |
| .config = (char *) "krava12", | |
| .val.num = 1, | |
| .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | |
| .type_term = PARSE_EVENTS__TERM_TYPE_USER, | |
| }, | |
| { | |
| .config = (char *) "krava13", | |
| .val.num = 2, | |
| .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | |
| .type_term = PARSE_EVENTS__TERM_TYPE_USER, | |
| }, | |
| { | |
| .config = (char *) "krava21", | |
| .val.num = 119, | |
| .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | |
| .type_term = PARSE_EVENTS__TERM_TYPE_USER, | |
| }, | |
| { | |
| .config = (char *) "krava22", | |
| .val.num = 11, | |
| .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | |
| .type_term = PARSE_EVENTS__TERM_TYPE_USER, | |
| }, | |
| { | |
| .config = (char *) "krava23", | |
| .val.num = 2, | |
| .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | |
| .type_term = PARSE_EVENTS__TERM_TYPE_USER, | |
| }, | |
| }; | |
| /* | |
| * Prepare format directory data, exported by kernel | |
| * at /sys/bus/event_source/devices/<dev>/format. | |
| */ | |
| static char *test_format_dir_get(void) | |
| { | |
| static char dir[PATH_MAX]; | |
| unsigned int i; | |
| snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX"); | |
| if (!mkdtemp(dir)) | |
| return NULL; | |
| for (i = 0; i < ARRAY_SIZE(test_formats); i++) { | |
| static char name[PATH_MAX]; | |
| struct test_format *format = &test_formats[i]; | |
| FILE *file; | |
| scnprintf(name, PATH_MAX, "%s/%s", dir, format->name); | |
| file = fopen(name, "w"); | |
| if (!file) | |
| return NULL; | |
| if (1 != fwrite(format->value, strlen(format->value), 1, file)) | |
| break; | |
| fclose(file); | |
| } | |
| return dir; | |
| } | |
| /* Cleanup format directory. */ | |
| static int test_format_dir_put(char *dir) | |
| { | |
| char buf[PATH_MAX]; | |
| snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir); | |
| if (system(buf)) | |
| return -1; | |
| snprintf(buf, PATH_MAX, "rmdir %s\n", dir); | |
| return system(buf); | |
| } | |
| static struct list_head *test_terms_list(void) | |
| { | |
| static LIST_HEAD(terms); | |
| unsigned int i; | |
| for (i = 0; i < ARRAY_SIZE(test_terms); i++) | |
| list_add_tail(&test_terms[i].list, &terms); | |
| return &terms; | |
| } | |
| int test__pmu(struct test *test __maybe_unused, int subtest __maybe_unused) | |
| { | |
| char *format = test_format_dir_get(); | |
| LIST_HEAD(formats); | |
| struct list_head *terms = test_terms_list(); | |
| int ret; | |
| if (!format) | |
| return -EINVAL; | |
| do { | |
| struct perf_event_attr attr; | |
| memset(&attr, 0, sizeof(attr)); | |
| ret = perf_pmu__format_parse(format, &formats); | |
| if (ret) | |
| break; | |
| ret = perf_pmu__config_terms(&formats, &attr, terms, | |
| false, NULL); | |
| if (ret) | |
| break; | |
| ret = -EINVAL; | |
| if (attr.config != 0xc00000000002a823) | |
| break; | |
| if (attr.config1 != 0x8000400000000145) | |
| break; | |
| if (attr.config2 != 0x0400000020041d07) | |
| break; | |
| ret = 0; | |
| } while (0); | |
| test_format_dir_put(format); | |
| return ret; | |
| } |