| 1 | |
| 2 | #include "evlist.h"
|
| 3 | #include "evsel.h"
|
| 4 | #include "parse-events.h"
|
| 5 | #include "pmu.h"
|
| 6 | #include "pmus.h"
|
| 7 | #include "tests.h"
|
| 8 | #include "debug.h"
|
| 9 | #include "fncache.h"
|
| 10 | #include <api/fs/fs.h>
|
| 11 | #include <ctype.h>
|
| 12 | #include <dirent.h>
|
| 13 | #include <errno.h>
|
| 14 | #include <fcntl.h>
|
| 15 | #include <stdio.h>
|
| 16 | #include <stdlib.h>
|
| 17 | #include <unistd.h>
|
| 18 | #include <sys/stat.h>
|
| 19 | #include <sys/types.h>
|
| 20 |
|
| 21 |
|
| 22 | static int test_pmu_put(const char *dir, struct perf_pmu *pmu)
|
| 23 | {
|
| 24 | char buf[PATH_MAX + 20];
|
| 25 | int ret;
|
| 26 |
|
| 27 | if (scnprintf(buf, sizeof(buf), "rm -fr %s", dir) < 0) {
|
| 28 | pr_err("Failure to set up buffer for \"%s\"\n", dir);
|
| 29 | return -EINVAL;
|
| 30 | }
|
| 31 | ret = system(buf);
|
| 32 | if (ret)
|
| 33 | pr_err("Failure to \"%s\"\n", buf);
|
| 34 |
|
| 35 | list_del(&pmu->list);
|
| 36 | perf_pmu__delete(pmu);
|
| 37 | return ret;
|
| 38 | }
|
| 39 |
|
| 40 | |
| 41 | * Prepare test PMU directory data, normally exported by kernel at
|
| 42 | * /sys/bus/event_source/devices/<pmu>/. Give as input a buffer to hold the file
|
| 43 | * path, the result is PMU loaded using that directory.
|
| 44 |
|
| 45 | static struct perf_pmu *test_pmu_get(char *dir, size_t sz)
|
| 46 | {
|
| 47 |
|
| 48 | const struct test_format {
|
| 49 | const char *name;
|
| 50 | const char *value;
|
| 51 | } test_formats[] = {
|
| 52 | { "krava01", "config:0-1,62-63\n", },
|
| 53 | { "krava02", "config:10-17\n", },
|
| 54 | { "krava03", "config:5\n", },
|
| 55 | { "krava11", "config1:0,2,4,6,8,20-28\n", },
|
| 56 | { "krava12", "config1:63\n", },
|
| 57 | { "krava13", "config1:45-47\n", },
|
| 58 | { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
|
| 59 | { "krava22", "config2:8,18,48,58\n", },
|
| 60 | { "krava23", "config2:28-29,38\n", },
|
| 61 | };
|
| 62 | const char *test_event = "krava01=15,krava02=170,krava03=1,krava11=27,krava12=1,"
|
| 63 | "krava13=2,krava21=119,krava22=11,krava23=2\n";
|
| 64 |
|
| 65 | char name[PATH_MAX];
|
| 66 | int dirfd, file;
|
| 67 | struct perf_pmu *pmu = NULL;
|
| 68 | ssize_t len;
|
| 69 |
|
| 70 |
|
| 71 | scnprintf(dir, sz, "/tmp/perf-pmu-test-XXXXXX");
|
| 72 | if (!mkdtemp(dir)) {
|
| 73 | pr_err("mkdtemp failed\n");
|
| 74 | dir[0] = '\0';
|
| 75 | return NULL;
|
| 76 | }
|
| 77 | dirfd = open(dir, O_DIRECTORY);
|
| 78 | if (dirfd < 0) {
|
| 79 | pr_err("Failed to open test directory \"%s\"\n", dir);
|
| 80 | goto err_out;
|
| 81 | }
|
| 82 |
|
| 83 |
|
| 84 | if (mkdirat(dirfd, "perf-pmu-test", 0755) < 0) {
|
| 85 | pr_err("Failed to mkdir PMU directory\n");
|
| 86 | goto err_out;
|
| 87 | }
|
| 88 | file = openat(dirfd, "perf-pmu-test/type", O_WRONLY | O_CREAT, 0600);
|
| 89 | if (!file) {
|
| 90 | pr_err("Failed to open for writing file \"type\"\n");
|
| 91 | goto err_out;
|
| 92 | }
|
| 93 | len = strlen("9999");
|
| 94 | if (write(file, "9999\n", len) < len) {
|
| 95 | close(file);
|
| 96 | pr_err("Failed to write to 'type' file\n");
|
| 97 | goto err_out;
|
| 98 | }
|
| 99 | close(file);
|
| 100 |
|
| 101 |
|
| 102 | if (mkdirat(dirfd, "perf-pmu-test/format", 0755) < 0) {
|
| 103 | pr_err("Failed to mkdir PMU format directory\n)");
|
| 104 | goto err_out;
|
| 105 | }
|
| 106 | for (size_t i = 0; i < ARRAY_SIZE(test_formats); i++) {
|
| 107 | const struct test_format *format = &test_formats[i];
|
| 108 |
|
| 109 | if (scnprintf(name, PATH_MAX, "perf-pmu-test/format/%s", format->name) < 0) {
|
| 110 | pr_err("Failure to set up path for \"%s\"\n", format->name);
|
| 111 | goto err_out;
|
| 112 | }
|
| 113 | file = openat(dirfd, name, O_WRONLY | O_CREAT, 0600);
|
| 114 | if (!file) {
|
| 115 | pr_err("Failed to open for writing file \"%s\"\n", name);
|
| 116 | goto err_out;
|
| 117 | }
|
| 118 |
|
| 119 | if (write(file, format->value, strlen(format->value)) < 0) {
|
| 120 | pr_err("Failed to write to file \"%s\"\n", name);
|
| 121 | close(file);
|
| 122 | goto err_out;
|
| 123 | }
|
| 124 | close(file);
|
| 125 | }
|
| 126 |
|
| 127 |
|
| 128 | if (mkdirat(dirfd, "perf-pmu-test/events", 0755) < 0) {
|
| 129 | pr_err("Failed to mkdir PMU events directory\n");
|
| 130 | goto err_out;
|
| 131 | }
|
| 132 | file = openat(dirfd, "perf-pmu-test/events/test-event", O_WRONLY | O_CREAT, 0600);
|
| 133 | if (!file) {
|
| 134 | pr_err("Failed to open for writing file \"type\"\n");
|
| 135 | goto err_out;
|
| 136 | }
|
| 137 | len = strlen(test_event);
|
| 138 | if (write(file, test_event, len) < len) {
|
| 139 | close(file);
|
| 140 | pr_err("Failed to write to 'test-event' file\n");
|
| 141 | goto err_out;
|
| 142 | }
|
| 143 | close(file);
|
| 144 |
|
| 145 |
|
| 146 | pmu = perf_pmus__add_test_pmu(dirfd, "perf-pmu-test");
|
| 147 | if (!pmu)
|
| 148 | pr_err("Test PMU creation failed\n");
|
| 149 |
|
| 150 | err_out:
|
| 151 | if (!pmu)
|
| 152 | test_pmu_put(dir, pmu);
|
| 153 | if (dirfd >= 0)
|
| 154 | close(dirfd);
|
| 155 | return pmu;
|
| 156 | }
|
| 157 |
|
| 158 | static int test__pmu_format(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
|
| 159 | {
|
| 160 | char dir[PATH_MAX];
|
| 161 | struct perf_event_attr attr;
|
| 162 | struct parse_events_terms terms;
|
| 163 | int ret = TEST_FAIL;
|
| 164 | struct perf_pmu *pmu = test_pmu_get(dir, sizeof(dir));
|
| 165 |
|
| 166 | if (!pmu)
|
| 167 | return TEST_FAIL;
|
| 168 |
|
| 169 | parse_events_terms__init(&terms);
|
| 170 | if (parse_events_terms(&terms,
|
| 171 | "krava01=15,krava02=170,krava03=1,krava11=27,krava12=1,"
|
| 172 | "krava13=2,krava21=119,krava22=11,krava23=2")) {
|
| 173 | pr_err("Term parsing failed\n");
|
| 174 | goto err_out;
|
| 175 | }
|
| 176 |
|
| 177 | memset(&attr, 0, sizeof(attr));
|
| 178 | ret = perf_pmu__config_terms(pmu, &attr, &terms, false,
|
| 179 | false, NULL);
|
| 180 | if (ret) {
|
| 181 | pr_err("perf_pmu__config_terms failed");
|
| 182 | goto err_out;
|
| 183 | }
|
| 184 |
|
| 185 | if (attr.config != 0xc00000000002a823) {
|
| 186 | pr_err("Unexpected config value %llx\n", attr.config);
|
| 187 | goto err_out;
|
| 188 | }
|
| 189 | if (attr.config1 != 0x8000400000000145) {
|
| 190 | pr_err("Unexpected config1 value %llx\n", attr.config1);
|
| 191 | goto err_out;
|
| 192 | }
|
| 193 | if (attr.config2 != 0x0400000020041d07) {
|
| 194 | pr_err("Unexpected config2 value %llx\n", attr.config2);
|
| 195 | }
|
| 196 |
|
| 197 | ret = TEST_OK;
|
| 198 | err_out:
|
| 199 | parse_events_terms__exit(&terms);
|
| 200 | test_pmu_put(dir, pmu);
|
| 201 | return ret;
|
| 202 | }
|
| 203 |
|
| 204 | static int test__pmu_config_helpers(struct test_suite *test __maybe_unused,
|
| 205 | int subtest __maybe_unused)
|
| 206 | {
|
| 207 | const char *event = "perf-pmu-test/config=15,config1=4,krava02=170,"
|
| 208 | "krava03=1,krava11=27,krava12=1/";
|
| 209 | struct parse_events_terms terms;
|
| 210 | struct parse_events_error err;
|
| 211 | LIST_HEAD(config_terms);
|
| 212 | struct evlist *evlist;
|
| 213 | struct perf_pmu *pmu;
|
| 214 | struct evsel *evsel;
|
| 215 | int ret = TEST_FAIL;
|
| 216 | char dir[PATH_MAX];
|
| 217 | u64 val;
|
| 218 |
|
| 219 | pmu = test_pmu_get(dir, sizeof(dir));
|
| 220 | if (!pmu)
|
| 221 | return TEST_FAIL;
|
| 222 |
|
| 223 | evlist = evlist__new();
|
| 224 | if (evlist == NULL) {
|
| 225 | pr_err("Failed allocation");
|
| 226 | goto err_out;
|
| 227 | }
|
| 228 |
|
| 229 | parse_events_terms__init(&terms);
|
| 230 | ret = parse_events(evlist, event, &err);
|
| 231 | if (ret) {
|
| 232 | pr_debug("failed to parse event '%s', err %d\n", event, ret);
|
| 233 | parse_events_error__print(&err, event);
|
| 234 | if (parse_events_error__contains(&err, "can't access trace events"))
|
| 235 | ret = TEST_SKIP;
|
| 236 | goto err_out;
|
| 237 | }
|
| 238 | evsel = evlist__first(evlist);
|
| 239 |
|
| 240 |
|
| 241 | TEST_ASSERT_EQUAL("krava01 should exist",
|
| 242 | evsel__config_exists(evsel, "krava01"), true);
|
| 243 | TEST_ASSERT_EQUAL("krava99 should not exist",
|
| 244 | evsel__config_exists(evsel, "krava99"), false);
|
| 245 |
|
| 246 | |
| 247 | * Set via config=15, krava01 bits 0-1
|
| 248 | * Set via config1=4, krava11 bit 1
|
| 249 | * Set values: krava02=170, krava03=1, krava11=27, krava12=1
|
| 250 | *
|
| 251 | * Test that already set values aren't overwritten.
|
| 252 |
|
| 253 | evsel__set_config_if_unset(evsel, "krava01", 16);
|
| 254 | evsel__get_config_val(evsel, "krava01", &val);
|
| 255 | TEST_ASSERT_EQUAL("krava01 overwritten", (int) val, (15 & 0b11));
|
| 256 |
|
| 257 | evsel__set_config_if_unset(evsel, "krava11", 45);
|
| 258 | evsel__get_config_val(evsel, "krava11", &val);
|
| 259 | TEST_ASSERT_EQUAL("krava11 overwritten", (int) val, (27 | (4 << 1)));
|
| 260 |
|
| 261 | evsel__set_config_if_unset(evsel, "krava02", 32);
|
| 262 | evsel__get_config_val(evsel, "krava02", &val);
|
| 263 | TEST_ASSERT_EQUAL("krava02 overwritten", (int) val, 170);
|
| 264 |
|
| 265 | evsel__set_config_if_unset(evsel, "krava03", 0);
|
| 266 | evsel__get_config_val(evsel, "krava03", &val);
|
| 267 | TEST_ASSERT_EQUAL("krava03 overwritten", (int) val, 1);
|
| 268 |
|
| 269 | |
| 270 | * krava13 doesn't have any bits set by either krava13= or config1=
|
| 271 | * but setting _any_ raw value for config1 implies that krava13
|
| 272 | * shouldn't be overwritten. So it's value should remain as 0.
|
| 273 |
|
| 274 | evsel__set_config_if_unset(evsel, "krava13", 5);
|
| 275 | evsel__get_config_val(evsel, "krava13", &val);
|
| 276 | TEST_ASSERT_EQUAL("krava13 overwritten", (int) val, 0);
|
| 277 |
|
| 278 | |
| 279 | * Unset values: krava21, krava22, krava23
|
| 280 | *
|
| 281 | * Test that unset values are overwritten.
|
| 282 |
|
| 283 | evsel__set_config_if_unset(evsel, "krava21", 13905);
|
| 284 | evsel__get_config_val(evsel, "krava21", &val);
|
| 285 | TEST_ASSERT_EQUAL("krava21 not overwritten", (int) val, 13905);
|
| 286 |
|
| 287 | evsel__set_config_if_unset(evsel, "krava22", 11);
|
| 288 | evsel__get_config_val(evsel, "krava22", &val);
|
| 289 | TEST_ASSERT_EQUAL("krava22 not overwritten", (int) val, 11);
|
| 290 |
|
| 291 | evsel__set_config_if_unset(evsel, "krava23", 0);
|
| 292 | evsel__get_config_val(evsel, "krava23", &val);
|
| 293 | TEST_ASSERT_EQUAL("krava23 not overwritten", (int) val, 0);
|
| 294 | ret = TEST_OK;
|
| 295 | err_out:
|
| 296 | parse_events_terms__exit(&terms);
|
| 297 | evlist__put(evlist);
|
| 298 | test_pmu_put(dir, pmu);
|
| 299 | return ret;
|
| 300 | }
|
| 301 |
|
| 302 | static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
|
| 303 | {
|
| 304 | char dir[PATH_MAX];
|
| 305 | struct parse_events_error err;
|
| 306 | struct evlist *evlist;
|
| 307 | struct evsel *evsel;
|
| 308 | struct perf_event_attr *attr;
|
| 309 | int ret = TEST_FAIL;
|
| 310 | struct perf_pmu *pmu = test_pmu_get(dir, sizeof(dir));
|
| 311 | const char *event = "perf-pmu-test/test-event/";
|
| 312 |
|
| 313 |
|
| 314 | if (!pmu)
|
| 315 | return TEST_FAIL;
|
| 316 |
|
| 317 | evlist = evlist__new();
|
| 318 | if (evlist == NULL) {
|
| 319 | pr_err("Failed allocation");
|
| 320 | goto err_out;
|
| 321 | }
|
| 322 | parse_events_error__init(&err);
|
| 323 | ret = parse_events(evlist, event, &err);
|
| 324 | if (ret) {
|
| 325 | pr_debug("failed to parse event '%s', err %d\n", event, ret);
|
| 326 | parse_events_error__print(&err, event);
|
| 327 | if (parse_events_error__contains(&err, "can't access trace events"))
|
| 328 | ret = TEST_SKIP;
|
| 329 | goto err_out;
|
| 330 | }
|
| 331 | evsel = evlist__first(evlist);
|
| 332 | attr = &evsel->core.attr;
|
| 333 | if (attr->config != 0xc00000000002a823) {
|
| 334 | pr_err("Unexpected config value %llx\n", attr->config);
|
| 335 | goto err_out;
|
| 336 | }
|
| 337 | if (attr->config1 != 0x8000400000000145) {
|
| 338 | pr_err("Unexpected config1 value %llx\n", attr->config1);
|
| 339 | goto err_out;
|
| 340 | }
|
| 341 | if (attr->config2 != 0x0400000020041d07) {
|
| 342 | pr_err("Unexpected config2 value %llx\n", attr->config2);
|
| 343 | goto err_out;
|
| 344 | }
|
| 345 |
|
| 346 | ret = TEST_OK;
|
| 347 | err_out:
|
| 348 | parse_events_error__exit(&err);
|
| 349 | evlist__put(evlist);
|
| 350 | test_pmu_put(dir, pmu);
|
| 351 | return ret;
|
| 352 | }
|
| 353 |
|
| 354 | static bool permitted_event_name(const char *name)
|
| 355 | {
|
| 356 | bool has_lower = false, has_upper = false;
|
| 357 | __u64 config;
|
| 358 |
|
| 359 | for (size_t i = 0; i < strlen(name); i++) {
|
| 360 | char c = name[i];
|
| 361 |
|
| 362 | if (islower(c)) {
|
| 363 | if (has_upper)
|
| 364 | goto check_legacy;
|
| 365 | has_lower = true;
|
| 366 | continue;
|
| 367 | }
|
| 368 | if (isupper(c)) {
|
| 369 | if (has_lower)
|
| 370 | goto check_legacy;
|
| 371 | has_upper = true;
|
| 372 | continue;
|
| 373 | }
|
| 374 | if (!isdigit(c) && c != '.' && c != '_' && c != '-')
|
| 375 | goto check_legacy;
|
| 376 | }
|
| 377 | return true;
|
| 378 | check_legacy:
|
| 379 | |
| 380 | * If the event name matches a legacy cache name the legacy encoding
|
| 381 | * will still be used. This isn't quite WAI as sysfs events should take
|
| 382 | * priority, but this case happens on PowerPC and matches the behavior
|
| 383 | * in older perf tools where legacy events were the priority. Be
|
| 384 | * permissive and assume later PMU drivers will use all lower or upper
|
| 385 | * case names.
|
| 386 |
|
| 387 | if (parse_events__decode_legacy_cache(name, 0, &config) == 0) {
|
| 388 | pr_warning("sysfs event '%s' should be all lower/upper case, it will be matched using legacy encoding.",
|
| 389 | name);
|
| 390 | return true;
|
| 391 | }
|
| 392 | return false;
|
| 393 | }
|
| 394 |
|
| 395 | static int test__pmu_event_names(struct test_suite *test __maybe_unused,
|
| 396 | int subtest __maybe_unused)
|
| 397 | {
|
| 398 | char path[PATH_MAX];
|
| 399 | DIR *pmu_dir, *event_dir;
|
| 400 | struct dirent *pmu_dent, *event_dent;
|
| 401 | const char *sysfs = sysfs__mountpoint();
|
| 402 | int ret = TEST_OK;
|
| 403 |
|
| 404 | if (!sysfs) {
|
| 405 | pr_err("Sysfs not mounted\n");
|
| 406 | return TEST_FAIL;
|
| 407 | }
|
| 408 |
|
| 409 | snprintf(path, sizeof(path), "%s/bus/event_source/devices/", sysfs);
|
| 410 | pmu_dir = opendir(path);
|
| 411 | if (!pmu_dir) {
|
| 412 | pr_err("Error opening \"%s\"\n", path);
|
| 413 | return TEST_FAIL;
|
| 414 | }
|
| 415 | while ((pmu_dent = readdir(pmu_dir))) {
|
| 416 | if (!strcmp(pmu_dent->d_name, ".") ||
|
| 417 | !strcmp(pmu_dent->d_name, ".."))
|
| 418 | continue;
|
| 419 |
|
| 420 | snprintf(path, sizeof(path), "%s/bus/event_source/devices/%s/type",
|
| 421 | sysfs, pmu_dent->d_name);
|
| 422 |
|
| 423 |
|
| 424 | if (!file_available(path))
|
| 425 | continue;
|
| 426 |
|
| 427 |
|
| 428 | snprintf(path, sizeof(path), "%s/bus/event_source/devices/%s/events",
|
| 429 | sysfs, pmu_dent->d_name);
|
| 430 |
|
| 431 | event_dir = opendir(path);
|
| 432 | if (!event_dir) {
|
| 433 | pr_debug("Skipping as no event directory \"%s\"\n", path);
|
| 434 | continue;
|
| 435 | }
|
| 436 | while ((event_dent = readdir(event_dir))) {
|
| 437 | const char *event_name = event_dent->d_name;
|
| 438 |
|
| 439 | if (!strcmp(event_name, ".") || !strcmp(event_name, ".."))
|
| 440 | continue;
|
| 441 |
|
| 442 | if (!permitted_event_name(event_name)) {
|
| 443 | pr_err("Invalid sysfs event name: %s/%s\n",
|
| 444 | pmu_dent->d_name, event_name);
|
| 445 | ret = TEST_FAIL;
|
| 446 | }
|
| 447 | }
|
| 448 | closedir(event_dir);
|
| 449 | }
|
| 450 | closedir(pmu_dir);
|
| 451 | return ret;
|
| 452 | }
|
| 453 |
|
| 454 | static const char * const uncore_chas[] = {
|
| 455 | "uncore_cha_0",
|
| 456 | "uncore_cha_1",
|
| 457 | "uncore_cha_2",
|
| 458 | "uncore_cha_3",
|
| 459 | "uncore_cha_4",
|
| 460 | "uncore_cha_5",
|
| 461 | "uncore_cha_6",
|
| 462 | "uncore_cha_7",
|
| 463 | "uncore_cha_8",
|
| 464 | "uncore_cha_9",
|
| 465 | "uncore_cha_10",
|
| 466 | "uncore_cha_11",
|
| 467 | "uncore_cha_12",
|
| 468 | "uncore_cha_13",
|
| 469 | "uncore_cha_14",
|
| 470 | "uncore_cha_15",
|
| 471 | "uncore_cha_16",
|
| 472 | "uncore_cha_17",
|
| 473 | "uncore_cha_18",
|
| 474 | "uncore_cha_19",
|
| 475 | "uncore_cha_20",
|
| 476 | "uncore_cha_21",
|
| 477 | "uncore_cha_22",
|
| 478 | "uncore_cha_23",
|
| 479 | "uncore_cha_24",
|
| 480 | "uncore_cha_25",
|
| 481 | "uncore_cha_26",
|
| 482 | "uncore_cha_27",
|
| 483 | "uncore_cha_28",
|
| 484 | "uncore_cha_29",
|
| 485 | "uncore_cha_30",
|
| 486 | "uncore_cha_31",
|
| 487 | };
|
| 488 |
|
| 489 | static const char * const mrvl_ddrs[] = {
|
| 490 | "mrvl_ddr_pmu_87e1b0000000",
|
| 491 | "mrvl_ddr_pmu_87e1b1000000",
|
| 492 | "mrvl_ddr_pmu_87e1b2000000",
|
| 493 | "mrvl_ddr_pmu_87e1b3000000",
|
| 494 | "mrvl_ddr_pmu_87e1b4000000",
|
| 495 | "mrvl_ddr_pmu_87e1b5000000",
|
| 496 | "mrvl_ddr_pmu_87e1b6000000",
|
| 497 | "mrvl_ddr_pmu_87e1b7000000",
|
| 498 | "mrvl_ddr_pmu_87e1b8000000",
|
| 499 | "mrvl_ddr_pmu_87e1b9000000",
|
| 500 | "mrvl_ddr_pmu_87e1ba000000",
|
| 501 | "mrvl_ddr_pmu_87e1bb000000",
|
| 502 | "mrvl_ddr_pmu_87e1bc000000",
|
| 503 | "mrvl_ddr_pmu_87e1bd000000",
|
| 504 | "mrvl_ddr_pmu_87e1be000000",
|
| 505 | "mrvl_ddr_pmu_87e1bf000000",
|
| 506 | };
|
| 507 |
|
| 508 | static int test__name_len(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
|
| 509 | {
|
| 510 | TEST_ASSERT_VAL("cpu", pmu_name_len_no_suffix("cpu") == strlen("cpu"));
|
| 511 | TEST_ASSERT_VAL("i915", pmu_name_len_no_suffix("i915") == strlen("i915"));
|
| 512 | TEST_ASSERT_VAL("cpum_cf", pmu_name_len_no_suffix("cpum_cf") == strlen("cpum_cf"));
|
| 513 | for (size_t i = 0; i < ARRAY_SIZE(uncore_chas); i++) {
|
| 514 | TEST_ASSERT_VAL("Strips uncore_cha suffix",
|
| 515 | pmu_name_len_no_suffix(uncore_chas[i]) ==
|
| 516 | strlen("uncore_cha"));
|
| 517 | }
|
| 518 | for (size_t i = 0; i < ARRAY_SIZE(mrvl_ddrs); i++) {
|
| 519 | TEST_ASSERT_VAL("Strips mrvl_ddr_pmu suffix",
|
| 520 | pmu_name_len_no_suffix(mrvl_ddrs[i]) ==
|
| 521 | strlen("mrvl_ddr_pmu"));
|
| 522 | }
|
| 523 | return TEST_OK;
|
| 524 | }
|
| 525 |
|
| 526 | static int test__name_cmp(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
|
| 527 | {
|
| 528 | TEST_ASSERT_EQUAL("cpu", pmu_name_cmp("cpu", "cpu"), 0);
|
| 529 | TEST_ASSERT_EQUAL("i915", pmu_name_cmp("i915", "i915"), 0);
|
| 530 | TEST_ASSERT_EQUAL("cpum_cf", pmu_name_cmp("cpum_cf", "cpum_cf"), 0);
|
| 531 | TEST_ASSERT_VAL("i915", pmu_name_cmp("cpu", "i915") < 0);
|
| 532 | TEST_ASSERT_VAL("i915", pmu_name_cmp("i915", "cpu") > 0);
|
| 533 | TEST_ASSERT_VAL("cpum_cf", pmu_name_cmp("cpum_cf", "cpum_ce") > 0);
|
| 534 | TEST_ASSERT_VAL("cpum_cf", pmu_name_cmp("cpum_cf", "cpum_d0") < 0);
|
| 535 | for (size_t i = 1; i < ARRAY_SIZE(uncore_chas); i++) {
|
| 536 | TEST_ASSERT_VAL("uncore_cha suffixes ordered lt",
|
| 537 | pmu_name_cmp(uncore_chas[i-1], uncore_chas[i]) < 0);
|
| 538 | TEST_ASSERT_VAL("uncore_cha suffixes ordered gt",
|
| 539 | pmu_name_cmp(uncore_chas[i], uncore_chas[i-1]) > 0);
|
| 540 | }
|
| 541 | for (size_t i = 1; i < ARRAY_SIZE(mrvl_ddrs); i++) {
|
| 542 | TEST_ASSERT_VAL("mrvl_ddr_pmu suffixes ordered lt",
|
| 543 | pmu_name_cmp(mrvl_ddrs[i-1], mrvl_ddrs[i]) < 0);
|
| 544 | TEST_ASSERT_VAL("mrvl_ddr_pmu suffixes ordered gt",
|
| 545 | pmu_name_cmp(mrvl_ddrs[i], mrvl_ddrs[i-1]) > 0);
|
| 546 | }
|
| 547 | return TEST_OK;
|
| 548 | }
|
| 549 |
|
| 550 | |
| 551 | * Test perf_pmu__wildcard_match() that's used to search for a PMU given a name passed
|
| 552 | * on the command line. The name that's passed may also be a filename type glob
|
| 553 | * match. If the name does not match, perf_pmu__wildcard_match() attempts to match the
|
| 554 | * alias of the PMU, if provided.
|
| 555 |
|
| 556 | static int test__pmu_match(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
|
| 557 | {
|
| 558 | struct perf_pmu test_pmu = {
|
| 559 | .name = "pmuname",
|
| 560 | };
|
| 561 |
|
| 562 | #define TEST_PMU_MATCH(msg, to_match, expect) \
|
| 563 | TEST_ASSERT_EQUAL(msg, perf_pmu__wildcard_match(&test_pmu, to_match), expect)
|
| 564 |
|
| 565 | TEST_PMU_MATCH("Exact match", "pmuname", true);
|
| 566 | TEST_PMU_MATCH("Longer token", "longertoken", false);
|
| 567 | TEST_PMU_MATCH("Shorter token", "pmu", false);
|
| 568 |
|
| 569 | test_pmu.name = "pmuname_10";
|
| 570 | TEST_PMU_MATCH("Diff suffix_", "pmuname_2", false);
|
| 571 | TEST_PMU_MATCH("Sub suffix_", "pmuname_1", true);
|
| 572 | TEST_PMU_MATCH("Same suffix_", "pmuname_10", true);
|
| 573 | TEST_PMU_MATCH("No suffix_", "pmuname", true);
|
| 574 | TEST_PMU_MATCH("Underscore_", "pmuname_", true);
|
| 575 | TEST_PMU_MATCH("Substring_", "pmuna", false);
|
| 576 |
|
| 577 | test_pmu.name = "pmuname_ab23";
|
| 578 | TEST_PMU_MATCH("Diff suffix hex_", "pmuname_2", false);
|
| 579 | TEST_PMU_MATCH("Sub suffix hex_", "pmuname_ab", true);
|
| 580 | TEST_PMU_MATCH("Same suffix hex_", "pmuname_ab23", true);
|
| 581 | TEST_PMU_MATCH("No suffix hex_", "pmuname", true);
|
| 582 | TEST_PMU_MATCH("Underscore hex_", "pmuname_", true);
|
| 583 | TEST_PMU_MATCH("Substring hex_", "pmuna", false);
|
| 584 |
|
| 585 | test_pmu.name = "pmuname10";
|
| 586 | TEST_PMU_MATCH("Diff suffix", "pmuname2", false);
|
| 587 | TEST_PMU_MATCH("Sub suffix", "pmuname1", true);
|
| 588 | TEST_PMU_MATCH("Same suffix", "pmuname10", true);
|
| 589 | TEST_PMU_MATCH("No suffix", "pmuname", true);
|
| 590 | TEST_PMU_MATCH("Underscore", "pmuname_", false);
|
| 591 | TEST_PMU_MATCH("Substring", "pmuna", false);
|
| 592 |
|
| 593 | test_pmu.name = "pmunameab23";
|
| 594 | TEST_PMU_MATCH("Diff suffix hex", "pmuname2", false);
|
| 595 | TEST_PMU_MATCH("Sub suffix hex", "pmunameab", true);
|
| 596 | TEST_PMU_MATCH("Same suffix hex", "pmunameab23", true);
|
| 597 | TEST_PMU_MATCH("No suffix hex", "pmuname", true);
|
| 598 | TEST_PMU_MATCH("Underscore hex", "pmuname_", false);
|
| 599 | TEST_PMU_MATCH("Substring hex", "pmuna", false);
|
| 600 |
|
| 601 | |
| 602 | * 2 hex chars or less are not considered suffixes so it shouldn't be
|
| 603 | * possible to wildcard by skipping the suffix. Therefore there are more
|
| 604 | * false results here than above.
|
| 605 |
|
| 606 | test_pmu.name = "pmuname_a3";
|
| 607 | TEST_PMU_MATCH("Diff suffix 2 hex_", "pmuname_2", false);
|
| 608 | |
| 609 | * This one should be false, but because pmuname_a3 ends in 3 which is
|
| 610 | * decimal, it's not possible to determine if it's a short hex suffix or
|
| 611 | * a normal decimal suffix following text. And we want to match on any
|
| 612 | * length of decimal suffix. Run the test anyway and expect the wrong
|
| 613 | * result. And slightly fuzzy matching shouldn't do too much harm.
|
| 614 |
|
| 615 | TEST_PMU_MATCH("Sub suffix 2 hex_", "pmuname_a", true);
|
| 616 | TEST_PMU_MATCH("Same suffix 2 hex_", "pmuname_a3", true);
|
| 617 | TEST_PMU_MATCH("No suffix 2 hex_", "pmuname", false);
|
| 618 | TEST_PMU_MATCH("Underscore 2 hex_", "pmuname_", false);
|
| 619 | TEST_PMU_MATCH("Substring 2 hex_", "pmuna", false);
|
| 620 |
|
| 621 | test_pmu.name = "pmuname_5";
|
| 622 | TEST_PMU_MATCH("Glob 1", "pmu*", true);
|
| 623 | TEST_PMU_MATCH("Glob 2", "nomatch*", false);
|
| 624 | TEST_PMU_MATCH("Seq 1", "pmuname_[12345]", true);
|
| 625 | TEST_PMU_MATCH("Seq 2", "pmuname_[67890]", false);
|
| 626 | TEST_PMU_MATCH("? 1", "pmuname_?", true);
|
| 627 | TEST_PMU_MATCH("? 2", "pmuname_1?", false);
|
| 628 |
|
| 629 | return TEST_OK;
|
| 630 | }
|
| 631 |
|
| 632 | static struct test_case tests__pmu[] = {
|
| 633 | TEST_CASE("Parsing with PMU format directory", pmu_format),
|
| 634 | TEST_CASE("Parsing with PMU event", pmu_events),
|
| 635 | TEST_CASE("PMU event names", pmu_event_names),
|
| 636 | TEST_CASE("PMU name combining", name_len),
|
| 637 | TEST_CASE("PMU name comparison", name_cmp),
|
| 638 | TEST_CASE("PMU cmdline match", pmu_match),
|
| 639 | TEST_CASE("PMU config helpers", pmu_config_helpers),
|
| 640 | { .name = NULL, }
|
| 641 | };
|
| 642 |
|
| 643 | struct test_suite suite__pmu = {
|
| 644 | .desc = "Sysfs PMU tests",
|
| 645 | .test_cases = tests__pmu,
|
| 646 | };
|