mirror of
https://github.com/torvalds/linux.git
synced 2024-12-01 16:41:39 +00:00
4f21bfed69
Instead of explicitely initializing just the .name and .alias_name, use struct member named initialization of just the non-null -name field, the compiler will initialize all the other non-explicitely initialized fields to NULL. This makes the code more robust, avoiding the error recently fixed when the .alias_name was used and contained a random value. Reviewed-by: Veronika Molnarova <vmolnaro@redhat.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Ian Rogers <irogers@google.com> Cc: James Clark <james.clark@arm.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Michael Petlan <mpetlan@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Radostin Stoyanov <rstoyano@redhat.com> Link: https://lore.kernel.org/lkml/e26941f9-f86c-4f2e-b812-20c49fb2c0d3@redhat.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
546 lines
17 KiB
C
546 lines
17 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include "evlist.h"
|
|
#include "evsel.h"
|
|
#include "parse-events.h"
|
|
#include "pmu.h"
|
|
#include "pmus.h"
|
|
#include "tests.h"
|
|
#include "debug.h"
|
|
#include "fncache.h"
|
|
#include <api/fs/fs.h>
|
|
#include <ctype.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
/* Cleanup test PMU directory. */
|
|
static int test_pmu_put(const char *dir, struct perf_pmu *pmu)
|
|
{
|
|
char buf[PATH_MAX + 20];
|
|
int ret;
|
|
|
|
if (scnprintf(buf, sizeof(buf), "rm -fr %s", dir) < 0) {
|
|
pr_err("Failure to set up buffer for \"%s\"\n", dir);
|
|
return -EINVAL;
|
|
}
|
|
ret = system(buf);
|
|
if (ret)
|
|
pr_err("Failure to \"%s\"\n", buf);
|
|
|
|
list_del(&pmu->list);
|
|
perf_pmu__delete(pmu);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Prepare test PMU directory data, normally exported by kernel at
|
|
* /sys/bus/event_source/devices/<pmu>/. Give as input a buffer to hold the file
|
|
* path, the result is PMU loaded using that directory.
|
|
*/
|
|
static struct perf_pmu *test_pmu_get(char *dir, size_t sz)
|
|
{
|
|
/* Simulated format definitions. */
|
|
const 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", },
|
|
};
|
|
const char *test_event = "krava01=15,krava02=170,krava03=1,krava11=27,krava12=1,"
|
|
"krava13=2,krava21=119,krava22=11,krava23=2\n";
|
|
|
|
char name[PATH_MAX];
|
|
int dirfd, file;
|
|
struct perf_pmu *pmu = NULL;
|
|
ssize_t len;
|
|
|
|
/* Create equivalent of sysfs mount point. */
|
|
scnprintf(dir, sz, "/tmp/perf-pmu-test-XXXXXX");
|
|
if (!mkdtemp(dir)) {
|
|
pr_err("mkdtemp failed\n");
|
|
dir[0] = '\0';
|
|
return NULL;
|
|
}
|
|
dirfd = open(dir, O_DIRECTORY);
|
|
if (dirfd < 0) {
|
|
pr_err("Failed to open test directory \"%s\"\n", dir);
|
|
goto err_out;
|
|
}
|
|
|
|
/* Create the test PMU directory and give it a perf_event_attr type number. */
|
|
if (mkdirat(dirfd, "perf-pmu-test", 0755) < 0) {
|
|
pr_err("Failed to mkdir PMU directory\n");
|
|
goto err_out;
|
|
}
|
|
file = openat(dirfd, "perf-pmu-test/type", O_WRONLY | O_CREAT, 0600);
|
|
if (!file) {
|
|
pr_err("Failed to open for writing file \"type\"\n");
|
|
goto err_out;
|
|
}
|
|
len = strlen("9999");
|
|
if (write(file, "9999\n", len) < len) {
|
|
close(file);
|
|
pr_err("Failed to write to 'type' file\n");
|
|
goto err_out;
|
|
}
|
|
close(file);
|
|
|
|
/* Create format directory and files. */
|
|
if (mkdirat(dirfd, "perf-pmu-test/format", 0755) < 0) {
|
|
pr_err("Failed to mkdir PMU format directory\n)");
|
|
goto err_out;
|
|
}
|
|
for (size_t i = 0; i < ARRAY_SIZE(test_formats); i++) {
|
|
const struct test_format *format = &test_formats[i];
|
|
|
|
if (scnprintf(name, PATH_MAX, "perf-pmu-test/format/%s", format->name) < 0) {
|
|
pr_err("Failure to set up path for \"%s\"\n", format->name);
|
|
goto err_out;
|
|
}
|
|
file = openat(dirfd, name, O_WRONLY | O_CREAT, 0600);
|
|
if (!file) {
|
|
pr_err("Failed to open for writing file \"%s\"\n", name);
|
|
goto err_out;
|
|
}
|
|
|
|
if (write(file, format->value, strlen(format->value)) < 0) {
|
|
pr_err("Failed to write to file \"%s\"\n", name);
|
|
close(file);
|
|
goto err_out;
|
|
}
|
|
close(file);
|
|
}
|
|
|
|
/* Create test event. */
|
|
if (mkdirat(dirfd, "perf-pmu-test/events", 0755) < 0) {
|
|
pr_err("Failed to mkdir PMU events directory\n");
|
|
goto err_out;
|
|
}
|
|
file = openat(dirfd, "perf-pmu-test/events/test-event", O_WRONLY | O_CREAT, 0600);
|
|
if (!file) {
|
|
pr_err("Failed to open for writing file \"type\"\n");
|
|
goto err_out;
|
|
}
|
|
len = strlen(test_event);
|
|
if (write(file, test_event, len) < len) {
|
|
close(file);
|
|
pr_err("Failed to write to 'test-event' file\n");
|
|
goto err_out;
|
|
}
|
|
close(file);
|
|
|
|
/* Make the PMU reading the files created above. */
|
|
pmu = perf_pmus__add_test_pmu(dirfd, "perf-pmu-test");
|
|
if (!pmu)
|
|
pr_err("Test PMU creation failed\n");
|
|
|
|
err_out:
|
|
if (!pmu)
|
|
test_pmu_put(dir, pmu);
|
|
if (dirfd >= 0)
|
|
close(dirfd);
|
|
return pmu;
|
|
}
|
|
|
|
static int test__pmu_format(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
|
|
{
|
|
char dir[PATH_MAX];
|
|
struct perf_event_attr attr;
|
|
struct parse_events_terms terms;
|
|
int ret = TEST_FAIL;
|
|
struct perf_pmu *pmu = test_pmu_get(dir, sizeof(dir));
|
|
|
|
if (!pmu)
|
|
return TEST_FAIL;
|
|
|
|
parse_events_terms__init(&terms);
|
|
if (parse_events_terms(&terms,
|
|
"krava01=15,krava02=170,krava03=1,krava11=27,krava12=1,"
|
|
"krava13=2,krava21=119,krava22=11,krava23=2",
|
|
NULL)) {
|
|
pr_err("Term parsing failed\n");
|
|
goto err_out;
|
|
}
|
|
|
|
memset(&attr, 0, sizeof(attr));
|
|
ret = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/false, /*err=*/NULL);
|
|
if (ret) {
|
|
pr_err("perf_pmu__config_terms failed");
|
|
goto err_out;
|
|
}
|
|
|
|
if (attr.config != 0xc00000000002a823) {
|
|
pr_err("Unexpected config value %llx\n", attr.config);
|
|
goto err_out;
|
|
}
|
|
if (attr.config1 != 0x8000400000000145) {
|
|
pr_err("Unexpected config1 value %llx\n", attr.config1);
|
|
goto err_out;
|
|
}
|
|
if (attr.config2 != 0x0400000020041d07) {
|
|
pr_err("Unexpected config2 value %llx\n", attr.config2);
|
|
goto err_out;
|
|
}
|
|
|
|
ret = TEST_OK;
|
|
err_out:
|
|
parse_events_terms__exit(&terms);
|
|
test_pmu_put(dir, pmu);
|
|
return ret;
|
|
}
|
|
|
|
static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
|
|
{
|
|
char dir[PATH_MAX];
|
|
struct parse_events_error err;
|
|
struct evlist *evlist;
|
|
struct evsel *evsel;
|
|
struct perf_event_attr *attr;
|
|
int ret = TEST_FAIL;
|
|
struct perf_pmu *pmu = test_pmu_get(dir, sizeof(dir));
|
|
const char *event = "perf-pmu-test/test-event/";
|
|
|
|
|
|
if (!pmu)
|
|
return TEST_FAIL;
|
|
|
|
evlist = evlist__new();
|
|
if (evlist == NULL) {
|
|
pr_err("Failed allocation");
|
|
goto err_out;
|
|
}
|
|
parse_events_error__init(&err);
|
|
ret = parse_events(evlist, event, &err);
|
|
if (ret) {
|
|
pr_debug("failed to parse event '%s', err %d\n", event, ret);
|
|
parse_events_error__print(&err, event);
|
|
if (parse_events_error__contains(&err, "can't access trace events"))
|
|
ret = TEST_SKIP;
|
|
goto err_out;
|
|
}
|
|
evsel = evlist__first(evlist);
|
|
attr = &evsel->core.attr;
|
|
if (attr->config != 0xc00000000002a823) {
|
|
pr_err("Unexpected config value %llx\n", attr->config);
|
|
goto err_out;
|
|
}
|
|
if (attr->config1 != 0x8000400000000145) {
|
|
pr_err("Unexpected config1 value %llx\n", attr->config1);
|
|
goto err_out;
|
|
}
|
|
if (attr->config2 != 0x0400000020041d07) {
|
|
pr_err("Unexpected config2 value %llx\n", attr->config2);
|
|
goto err_out;
|
|
}
|
|
|
|
ret = TEST_OK;
|
|
err_out:
|
|
parse_events_error__exit(&err);
|
|
evlist__delete(evlist);
|
|
test_pmu_put(dir, pmu);
|
|
return ret;
|
|
}
|
|
|
|
static bool permitted_event_name(const char *name)
|
|
{
|
|
bool has_lower = false, has_upper = false;
|
|
__u64 config;
|
|
|
|
for (size_t i = 0; i < strlen(name); i++) {
|
|
char c = name[i];
|
|
|
|
if (islower(c)) {
|
|
if (has_upper)
|
|
goto check_legacy;
|
|
has_lower = true;
|
|
continue;
|
|
}
|
|
if (isupper(c)) {
|
|
if (has_lower)
|
|
goto check_legacy;
|
|
has_upper = true;
|
|
continue;
|
|
}
|
|
if (!isdigit(c) && c != '.' && c != '_' && c != '-')
|
|
goto check_legacy;
|
|
}
|
|
return true;
|
|
check_legacy:
|
|
/*
|
|
* If the event name matches a legacy cache name the legacy encoding
|
|
* will still be used. This isn't quite WAI as sysfs events should take
|
|
* priority, but this case happens on PowerPC and matches the behavior
|
|
* in older perf tools where legacy events were the priority. Be
|
|
* permissive and assume later PMU drivers will use all lower or upper
|
|
* case names.
|
|
*/
|
|
if (parse_events__decode_legacy_cache(name, /*extended_pmu_type=*/0, &config) == 0) {
|
|
pr_warning("sysfs event '%s' should be all lower/upper case, it will be matched using legacy encoding.",
|
|
name);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static int test__pmu_event_names(struct test_suite *test __maybe_unused,
|
|
int subtest __maybe_unused)
|
|
{
|
|
char path[PATH_MAX];
|
|
DIR *pmu_dir, *event_dir;
|
|
struct dirent *pmu_dent, *event_dent;
|
|
const char *sysfs = sysfs__mountpoint();
|
|
int ret = TEST_OK;
|
|
|
|
if (!sysfs) {
|
|
pr_err("Sysfs not mounted\n");
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
snprintf(path, sizeof(path), "%s/bus/event_source/devices/", sysfs);
|
|
pmu_dir = opendir(path);
|
|
if (!pmu_dir) {
|
|
pr_err("Error opening \"%s\"\n", path);
|
|
return TEST_FAIL;
|
|
}
|
|
while ((pmu_dent = readdir(pmu_dir))) {
|
|
if (!strcmp(pmu_dent->d_name, ".") ||
|
|
!strcmp(pmu_dent->d_name, ".."))
|
|
continue;
|
|
|
|
snprintf(path, sizeof(path), "%s/bus/event_source/devices/%s/type",
|
|
sysfs, pmu_dent->d_name);
|
|
|
|
/* Does it look like a PMU? */
|
|
if (!file_available(path))
|
|
continue;
|
|
|
|
/* Process events. */
|
|
snprintf(path, sizeof(path), "%s/bus/event_source/devices/%s/events",
|
|
sysfs, pmu_dent->d_name);
|
|
|
|
event_dir = opendir(path);
|
|
if (!event_dir) {
|
|
pr_debug("Skipping as no event directory \"%s\"\n", path);
|
|
continue;
|
|
}
|
|
while ((event_dent = readdir(event_dir))) {
|
|
const char *event_name = event_dent->d_name;
|
|
|
|
if (!strcmp(event_name, ".") || !strcmp(event_name, ".."))
|
|
continue;
|
|
|
|
if (!permitted_event_name(event_name)) {
|
|
pr_err("Invalid sysfs event name: %s/%s\n",
|
|
pmu_dent->d_name, event_name);
|
|
ret = TEST_FAIL;
|
|
}
|
|
}
|
|
closedir(event_dir);
|
|
}
|
|
closedir(pmu_dir);
|
|
return ret;
|
|
}
|
|
|
|
static const char * const uncore_chas[] = {
|
|
"uncore_cha_0",
|
|
"uncore_cha_1",
|
|
"uncore_cha_2",
|
|
"uncore_cha_3",
|
|
"uncore_cha_4",
|
|
"uncore_cha_5",
|
|
"uncore_cha_6",
|
|
"uncore_cha_7",
|
|
"uncore_cha_8",
|
|
"uncore_cha_9",
|
|
"uncore_cha_10",
|
|
"uncore_cha_11",
|
|
"uncore_cha_12",
|
|
"uncore_cha_13",
|
|
"uncore_cha_14",
|
|
"uncore_cha_15",
|
|
"uncore_cha_16",
|
|
"uncore_cha_17",
|
|
"uncore_cha_18",
|
|
"uncore_cha_19",
|
|
"uncore_cha_20",
|
|
"uncore_cha_21",
|
|
"uncore_cha_22",
|
|
"uncore_cha_23",
|
|
"uncore_cha_24",
|
|
"uncore_cha_25",
|
|
"uncore_cha_26",
|
|
"uncore_cha_27",
|
|
"uncore_cha_28",
|
|
"uncore_cha_29",
|
|
"uncore_cha_30",
|
|
"uncore_cha_31",
|
|
};
|
|
|
|
static const char * const mrvl_ddrs[] = {
|
|
"mrvl_ddr_pmu_87e1b0000000",
|
|
"mrvl_ddr_pmu_87e1b1000000",
|
|
"mrvl_ddr_pmu_87e1b2000000",
|
|
"mrvl_ddr_pmu_87e1b3000000",
|
|
"mrvl_ddr_pmu_87e1b4000000",
|
|
"mrvl_ddr_pmu_87e1b5000000",
|
|
"mrvl_ddr_pmu_87e1b6000000",
|
|
"mrvl_ddr_pmu_87e1b7000000",
|
|
"mrvl_ddr_pmu_87e1b8000000",
|
|
"mrvl_ddr_pmu_87e1b9000000",
|
|
"mrvl_ddr_pmu_87e1ba000000",
|
|
"mrvl_ddr_pmu_87e1bb000000",
|
|
"mrvl_ddr_pmu_87e1bc000000",
|
|
"mrvl_ddr_pmu_87e1bd000000",
|
|
"mrvl_ddr_pmu_87e1be000000",
|
|
"mrvl_ddr_pmu_87e1bf000000",
|
|
};
|
|
|
|
static int test__name_len(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
|
|
{
|
|
TEST_ASSERT_VAL("cpu", pmu_name_len_no_suffix("cpu") == strlen("cpu"));
|
|
TEST_ASSERT_VAL("i915", pmu_name_len_no_suffix("i915") == strlen("i915"));
|
|
TEST_ASSERT_VAL("cpum_cf", pmu_name_len_no_suffix("cpum_cf") == strlen("cpum_cf"));
|
|
for (size_t i = 0; i < ARRAY_SIZE(uncore_chas); i++) {
|
|
TEST_ASSERT_VAL("Strips uncore_cha suffix",
|
|
pmu_name_len_no_suffix(uncore_chas[i]) ==
|
|
strlen("uncore_cha"));
|
|
}
|
|
for (size_t i = 0; i < ARRAY_SIZE(mrvl_ddrs); i++) {
|
|
TEST_ASSERT_VAL("Strips mrvl_ddr_pmu suffix",
|
|
pmu_name_len_no_suffix(mrvl_ddrs[i]) ==
|
|
strlen("mrvl_ddr_pmu"));
|
|
}
|
|
return TEST_OK;
|
|
}
|
|
|
|
static int test__name_cmp(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
|
|
{
|
|
TEST_ASSERT_EQUAL("cpu", pmu_name_cmp("cpu", "cpu"), 0);
|
|
TEST_ASSERT_EQUAL("i915", pmu_name_cmp("i915", "i915"), 0);
|
|
TEST_ASSERT_EQUAL("cpum_cf", pmu_name_cmp("cpum_cf", "cpum_cf"), 0);
|
|
TEST_ASSERT_VAL("i915", pmu_name_cmp("cpu", "i915") < 0);
|
|
TEST_ASSERT_VAL("i915", pmu_name_cmp("i915", "cpu") > 0);
|
|
TEST_ASSERT_VAL("cpum_cf", pmu_name_cmp("cpum_cf", "cpum_ce") > 0);
|
|
TEST_ASSERT_VAL("cpum_cf", pmu_name_cmp("cpum_cf", "cpum_d0") < 0);
|
|
for (size_t i = 1; i < ARRAY_SIZE(uncore_chas); i++) {
|
|
TEST_ASSERT_VAL("uncore_cha suffixes ordered lt",
|
|
pmu_name_cmp(uncore_chas[i-1], uncore_chas[i]) < 0);
|
|
TEST_ASSERT_VAL("uncore_cha suffixes ordered gt",
|
|
pmu_name_cmp(uncore_chas[i], uncore_chas[i-1]) > 0);
|
|
}
|
|
for (size_t i = 1; i < ARRAY_SIZE(mrvl_ddrs); i++) {
|
|
TEST_ASSERT_VAL("mrvl_ddr_pmu suffixes ordered lt",
|
|
pmu_name_cmp(mrvl_ddrs[i-1], mrvl_ddrs[i]) < 0);
|
|
TEST_ASSERT_VAL("mrvl_ddr_pmu suffixes ordered gt",
|
|
pmu_name_cmp(mrvl_ddrs[i], mrvl_ddrs[i-1]) > 0);
|
|
}
|
|
return TEST_OK;
|
|
}
|
|
|
|
/**
|
|
* Test perf_pmu__match() that's used to search for a PMU given a name passed
|
|
* on the command line. The name that's passed may also be a filename type glob
|
|
* match. If the name does not match, perf_pmu__match() attempts to match the
|
|
* alias of the PMU, if provided.
|
|
*/
|
|
static int test__pmu_match(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
|
|
{
|
|
struct perf_pmu test_pmu = {
|
|
.name = "pmuname",
|
|
};
|
|
|
|
TEST_ASSERT_EQUAL("Exact match", perf_pmu__match(&test_pmu, "pmuname"), true);
|
|
TEST_ASSERT_EQUAL("Longer token", perf_pmu__match(&test_pmu, "longertoken"), false);
|
|
TEST_ASSERT_EQUAL("Shorter token", perf_pmu__match(&test_pmu, "pmu"), false);
|
|
|
|
test_pmu.name = "pmuname_10";
|
|
TEST_ASSERT_EQUAL("Diff suffix_", perf_pmu__match(&test_pmu, "pmuname_2"), false);
|
|
TEST_ASSERT_EQUAL("Sub suffix_", perf_pmu__match(&test_pmu, "pmuname_1"), true);
|
|
TEST_ASSERT_EQUAL("Same suffix_", perf_pmu__match(&test_pmu, "pmuname_10"), true);
|
|
TEST_ASSERT_EQUAL("No suffix_", perf_pmu__match(&test_pmu, "pmuname"), true);
|
|
TEST_ASSERT_EQUAL("Underscore_", perf_pmu__match(&test_pmu, "pmuname_"), true);
|
|
TEST_ASSERT_EQUAL("Substring_", perf_pmu__match(&test_pmu, "pmuna"), false);
|
|
|
|
test_pmu.name = "pmuname_ab23";
|
|
TEST_ASSERT_EQUAL("Diff suffix hex_", perf_pmu__match(&test_pmu, "pmuname_2"), false);
|
|
TEST_ASSERT_EQUAL("Sub suffix hex_", perf_pmu__match(&test_pmu, "pmuname_ab"), true);
|
|
TEST_ASSERT_EQUAL("Same suffix hex_", perf_pmu__match(&test_pmu, "pmuname_ab23"), true);
|
|
TEST_ASSERT_EQUAL("No suffix hex_", perf_pmu__match(&test_pmu, "pmuname"), true);
|
|
TEST_ASSERT_EQUAL("Underscore hex_", perf_pmu__match(&test_pmu, "pmuname_"), true);
|
|
TEST_ASSERT_EQUAL("Substring hex_", perf_pmu__match(&test_pmu, "pmuna"), false);
|
|
|
|
test_pmu.name = "pmuname10";
|
|
TEST_ASSERT_EQUAL("Diff suffix", perf_pmu__match(&test_pmu, "pmuname2"), false);
|
|
TEST_ASSERT_EQUAL("Sub suffix", perf_pmu__match(&test_pmu, "pmuname1"), true);
|
|
TEST_ASSERT_EQUAL("Same suffix", perf_pmu__match(&test_pmu, "pmuname10"), true);
|
|
TEST_ASSERT_EQUAL("No suffix", perf_pmu__match(&test_pmu, "pmuname"), true);
|
|
TEST_ASSERT_EQUAL("Underscore", perf_pmu__match(&test_pmu, "pmuname_"), false);
|
|
TEST_ASSERT_EQUAL("Substring", perf_pmu__match(&test_pmu, "pmuna"), false);
|
|
|
|
test_pmu.name = "pmunameab23";
|
|
TEST_ASSERT_EQUAL("Diff suffix hex", perf_pmu__match(&test_pmu, "pmuname2"), false);
|
|
TEST_ASSERT_EQUAL("Sub suffix hex", perf_pmu__match(&test_pmu, "pmunameab"), true);
|
|
TEST_ASSERT_EQUAL("Same suffix hex", perf_pmu__match(&test_pmu, "pmunameab23"), true);
|
|
TEST_ASSERT_EQUAL("No suffix hex", perf_pmu__match(&test_pmu, "pmuname"), true);
|
|
TEST_ASSERT_EQUAL("Underscore hex", perf_pmu__match(&test_pmu, "pmuname_"), false);
|
|
TEST_ASSERT_EQUAL("Substring hex", perf_pmu__match(&test_pmu, "pmuna"), false);
|
|
|
|
/*
|
|
* 2 hex chars or less are not considered suffixes so it shouldn't be
|
|
* possible to wildcard by skipping the suffix. Therefore there are more
|
|
* false results here than above.
|
|
*/
|
|
test_pmu.name = "pmuname_a3";
|
|
TEST_ASSERT_EQUAL("Diff suffix 2 hex_", perf_pmu__match(&test_pmu, "pmuname_2"), false);
|
|
/*
|
|
* This one should be false, but because pmuname_a3 ends in 3 which is
|
|
* decimal, it's not possible to determine if it's a short hex suffix or
|
|
* a normal decimal suffix following text. And we want to match on any
|
|
* length of decimal suffix. Run the test anyway and expect the wrong
|
|
* result. And slightly fuzzy matching shouldn't do too much harm.
|
|
*/
|
|
TEST_ASSERT_EQUAL("Sub suffix 2 hex_", perf_pmu__match(&test_pmu, "pmuname_a"), true);
|
|
TEST_ASSERT_EQUAL("Same suffix 2 hex_", perf_pmu__match(&test_pmu, "pmuname_a3"), true);
|
|
TEST_ASSERT_EQUAL("No suffix 2 hex_", perf_pmu__match(&test_pmu, "pmuname"), false);
|
|
TEST_ASSERT_EQUAL("Underscore 2 hex_", perf_pmu__match(&test_pmu, "pmuname_"), false);
|
|
TEST_ASSERT_EQUAL("Substring 2 hex_", perf_pmu__match(&test_pmu, "pmuna"), false);
|
|
|
|
test_pmu.name = "pmuname_5";
|
|
TEST_ASSERT_EQUAL("Glob 1", perf_pmu__match(&test_pmu, "pmu*"), true);
|
|
TEST_ASSERT_EQUAL("Glob 2", perf_pmu__match(&test_pmu, "nomatch*"), false);
|
|
TEST_ASSERT_EQUAL("Seq 1", perf_pmu__match(&test_pmu, "pmuname_[12345]"), true);
|
|
TEST_ASSERT_EQUAL("Seq 2", perf_pmu__match(&test_pmu, "pmuname_[67890]"), false);
|
|
TEST_ASSERT_EQUAL("? 1", perf_pmu__match(&test_pmu, "pmuname_?"), true);
|
|
TEST_ASSERT_EQUAL("? 2", perf_pmu__match(&test_pmu, "pmuname_1?"), false);
|
|
|
|
return TEST_OK;
|
|
}
|
|
|
|
static struct test_case tests__pmu[] = {
|
|
TEST_CASE("Parsing with PMU format directory", pmu_format),
|
|
TEST_CASE("Parsing with PMU event", pmu_events),
|
|
TEST_CASE("PMU event names", pmu_event_names),
|
|
TEST_CASE("PMU name combining", name_len),
|
|
TEST_CASE("PMU name comparison", name_cmp),
|
|
TEST_CASE("PMU cmdline match", pmu_match),
|
|
{ .name = NULL, }
|
|
};
|
|
|
|
struct test_suite suite__pmu = {
|
|
.desc = "Sysfs PMU tests",
|
|
.test_cases = tests__pmu,
|
|
};
|