1 // SPDX-License-Identifier: GPL-2.0 2 #include "math.h" 3 #include "parse-events.h" 4 #include "pmu.h" 5 #include "pmus.h" 6 #include "tests.h" 7 #include <errno.h> 8 #include <stdio.h> 9 #include <linux/kernel.h> 10 #include <linux/zalloc.h> 11 #include "debug.h" 12 #include "../pmu-events/pmu-events.h" 13 #include <perf/evlist.h> 14 #include "util/evlist.h" 15 #include "util/expr.h" 16 #include "util/hashmap.h" 17 #include "util/parse-events.h" 18 #include "metricgroup.h" 19 #include "stat.h" 20 21 struct perf_pmu_test_event { 22 /* used for matching against events from generated pmu-events.c */ 23 struct pmu_event event; 24 25 /* used for matching against event aliases */ 26 /* extra events for aliases */ 27 const char *alias_str; 28 29 /* 30 * Note: For when PublicDescription does not exist in the JSON, we 31 * will have no long_desc in pmu_event.long_desc, but long_desc may 32 * be set in the alias. 33 */ 34 const char *alias_long_desc; 35 36 /* PMU which we should match against */ 37 const char *matching_pmu; 38 }; 39 40 struct perf_pmu_test_pmu { 41 const char *pmu_name; 42 bool pmu_is_uncore; 43 const char *pmu_id; 44 struct perf_pmu_test_event const *aliases[10]; 45 }; 46 47 static const struct perf_pmu_test_event bp_l1_btb_correct = { 48 .event = { 49 .pmu = "default_core", 50 .name = "bp_l1_btb_correct", 51 .event = "event=0x8a", 52 .desc = "L1 BTB Correction", 53 .topic = "branch", 54 }, 55 .alias_str = "event=0x8a", 56 }; 57 58 static const struct perf_pmu_test_event bp_l2_btb_correct = { 59 .event = { 60 .pmu = "default_core", 61 .name = "bp_l2_btb_correct", 62 .event = "event=0x8b", 63 .desc = "L2 BTB Correction", 64 .topic = "branch", 65 }, 66 .alias_str = "event=0x8b", 67 }; 68 69 static const struct perf_pmu_test_event segment_reg_loads_any = { 70 .event = { 71 .pmu = "default_core", 72 .name = "segment_reg_loads.any", 73 .event = "event=6,period=200000,umask=0x80", 74 .desc = "Number of segment register loads", 75 .topic = "other", 76 }, 77 .alias_str = "event=0x6,period=0x30d40,umask=0x80", 78 }; 79 80 static const struct perf_pmu_test_event dispatch_blocked_any = { 81 .event = { 82 .pmu = "default_core", 83 .name = "dispatch_blocked.any", 84 .event = "event=9,period=200000,umask=0x20", 85 .desc = "Memory cluster signals to block micro-op dispatch for any reason", 86 .topic = "other", 87 }, 88 .alias_str = "event=0x9,period=0x30d40,umask=0x20", 89 }; 90 91 static const struct perf_pmu_test_event eist_trans = { 92 .event = { 93 .pmu = "default_core", 94 .name = "eist_trans", 95 .event = "event=0x3a,period=200000", 96 .desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", 97 .topic = "other", 98 }, 99 .alias_str = "event=0x3a,period=0x30d40", 100 }; 101 102 static const struct perf_pmu_test_event l3_cache_rd = { 103 .event = { 104 .pmu = "default_core", 105 .name = "l3_cache_rd", 106 .event = "event=0x40", 107 .desc = "L3 cache access, read", 108 .long_desc = "Attributable Level 3 cache access, read", 109 .topic = "cache", 110 }, 111 .alias_str = "event=0x40", 112 .alias_long_desc = "Attributable Level 3 cache access, read", 113 }; 114 115 static const struct perf_pmu_test_event *core_events[] = { 116 &bp_l1_btb_correct, 117 &bp_l2_btb_correct, 118 &segment_reg_loads_any, 119 &dispatch_blocked_any, 120 &eist_trans, 121 &l3_cache_rd, 122 NULL 123 }; 124 125 static const struct perf_pmu_test_event uncore_hisi_ddrc_flux_wcmd = { 126 .event = { 127 .name = "uncore_hisi_ddrc.flux_wcmd", 128 .event = "event=2", 129 .desc = "DDRC write commands", 130 .topic = "uncore", 131 .pmu = "hisi_sccl,ddrc", 132 }, 133 .alias_str = "event=0x2", 134 .matching_pmu = "hisi_sccl1_ddrc2", 135 }; 136 137 static const struct perf_pmu_test_event unc_cbo_xsnp_response_miss_eviction = { 138 .event = { 139 .name = "unc_cbo_xsnp_response.miss_eviction", 140 .event = "event=0x22,umask=0x81", 141 .desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", 142 .topic = "uncore", 143 .pmu = "uncore_cbox", 144 }, 145 .alias_str = "event=0x22,umask=0x81", 146 .matching_pmu = "uncore_cbox_0", 147 }; 148 149 static const struct perf_pmu_test_event uncore_hyphen = { 150 .event = { 151 .name = "event-hyphen", 152 .event = "event=0xe0", 153 .desc = "UNC_CBO_HYPHEN", 154 .topic = "uncore", 155 .pmu = "uncore_cbox", 156 }, 157 .alias_str = "event=0xe0", 158 .matching_pmu = "uncore_cbox_0", 159 }; 160 161 static const struct perf_pmu_test_event uncore_two_hyph = { 162 .event = { 163 .name = "event-two-hyph", 164 .event = "event=0xc0", 165 .desc = "UNC_CBO_TWO_HYPH", 166 .topic = "uncore", 167 .pmu = "uncore_cbox", 168 }, 169 .alias_str = "event=0xc0", 170 .matching_pmu = "uncore_cbox_0", 171 }; 172 173 static const struct perf_pmu_test_event uncore_hisi_l3c_rd_hit_cpipe = { 174 .event = { 175 .name = "uncore_hisi_l3c.rd_hit_cpipe", 176 .event = "event=7", 177 .desc = "Total read hits", 178 .topic = "uncore", 179 .pmu = "hisi_sccl,l3c", 180 }, 181 .alias_str = "event=0x7", 182 .matching_pmu = "hisi_sccl3_l3c7", 183 }; 184 185 static const struct perf_pmu_test_event uncore_imc_free_running_cache_miss = { 186 .event = { 187 .name = "uncore_imc_free_running.cache_miss", 188 .event = "event=0x12", 189 .desc = "Total cache misses", 190 .topic = "uncore", 191 .pmu = "uncore_imc_free_running", 192 }, 193 .alias_str = "event=0x12", 194 .matching_pmu = "uncore_imc_free_running_0", 195 }; 196 197 static const struct perf_pmu_test_event uncore_imc_cache_hits = { 198 .event = { 199 .name = "uncore_imc.cache_hits", 200 .event = "event=0x34", 201 .desc = "Total cache hits", 202 .topic = "uncore", 203 .pmu = "uncore_imc", 204 }, 205 .alias_str = "event=0x34", 206 .matching_pmu = "uncore_imc_0", 207 }; 208 209 static const struct perf_pmu_test_event *uncore_events[] = { 210 &uncore_hisi_ddrc_flux_wcmd, 211 &unc_cbo_xsnp_response_miss_eviction, 212 &uncore_hyphen, 213 &uncore_two_hyph, 214 &uncore_hisi_l3c_rd_hit_cpipe, 215 &uncore_imc_free_running_cache_miss, 216 &uncore_imc_cache_hits, 217 NULL 218 }; 219 220 static const struct perf_pmu_test_event sys_ddr_pmu_write_cycles = { 221 .event = { 222 .name = "sys_ddr_pmu.write_cycles", 223 .event = "event=0x2b", 224 .desc = "ddr write-cycles event", 225 .topic = "uncore", 226 .pmu = "uncore_sys_ddr_pmu", 227 .compat = "v8", 228 }, 229 .alias_str = "event=0x2b", 230 .matching_pmu = "uncore_sys_ddr_pmu0", 231 }; 232 233 static const struct perf_pmu_test_event sys_ccn_pmu_read_cycles = { 234 .event = { 235 .name = "sys_ccn_pmu.read_cycles", 236 .event = "config=0x2c", 237 .desc = "ccn read-cycles event", 238 .topic = "uncore", 239 .pmu = "uncore_sys_ccn_pmu", 240 .compat = "0x01", 241 }, 242 .alias_str = "config=0x2c", 243 .matching_pmu = "uncore_sys_ccn_pmu4", 244 }; 245 246 static const struct perf_pmu_test_event sys_cmn_pmu_hnf_cache_miss = { 247 .event = { 248 .name = "sys_cmn_pmu.hnf_cache_miss", 249 .event = "eventid=1,type=5", 250 .desc = "Counts total cache misses in first lookup result (high priority)", 251 .topic = "uncore", 252 .pmu = "uncore_sys_cmn_pmu", 253 .compat = "(434|436|43c|43a).*", 254 }, 255 .alias_str = "eventid=0x1,type=0x5", 256 .matching_pmu = "uncore_sys_cmn_pmu0", 257 }; 258 259 static const struct perf_pmu_test_event *sys_events[] = { 260 &sys_ddr_pmu_write_cycles, 261 &sys_ccn_pmu_read_cycles, 262 &sys_cmn_pmu_hnf_cache_miss, 263 NULL 264 }; 265 266 static bool is_same(const char *reference, const char *test) 267 { 268 if (!reference && !test) 269 return true; 270 271 if (reference && !test) 272 return false; 273 274 if (!reference && test) 275 return false; 276 277 return !strcmp(reference, test); 278 } 279 280 static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event *e2) 281 { 282 if (!is_same(e1->name, e2->name)) { 283 pr_debug2("testing event e1 %s: mismatched name string, %s vs %s\n", 284 e1->name, e1->name, e2->name); 285 return -1; 286 } 287 288 if (!is_same(e1->compat, e2->compat)) { 289 pr_debug2("testing event e1 %s: mismatched compat string, %s vs %s\n", 290 e1->name, e1->compat, e2->compat); 291 return -1; 292 } 293 294 if (!is_same(e1->event, e2->event)) { 295 pr_debug2("testing event e1 %s: mismatched event, %s vs %s\n", 296 e1->name, e1->event, e2->event); 297 return -1; 298 } 299 300 if (!is_same(e1->desc, e2->desc)) { 301 pr_debug2("testing event e1 %s: mismatched desc, %s vs %s\n", 302 e1->name, e1->desc, e2->desc); 303 return -1; 304 } 305 306 if (!is_same(e1->topic, e2->topic)) { 307 pr_debug2("testing event e1 %s: mismatched topic, %s vs %s\n", 308 e1->name, e1->topic, e2->topic); 309 return -1; 310 } 311 312 if (!is_same(e1->long_desc, e2->long_desc)) { 313 pr_debug2("testing event e1 %s: mismatched long_desc, %s vs %s\n", 314 e1->name, e1->long_desc, e2->long_desc); 315 return -1; 316 } 317 318 if (!is_same(e1->pmu, e2->pmu)) { 319 pr_debug2("testing event e1 %s: mismatched pmu string, %s vs %s\n", 320 e1->name, e1->pmu, e2->pmu); 321 return -1; 322 } 323 324 if (!is_same(e1->unit, e2->unit)) { 325 pr_debug2("testing event e1 %s: mismatched unit, %s vs %s\n", 326 e1->name, e1->unit, e2->unit); 327 return -1; 328 } 329 330 if (e1->perpkg != e2->perpkg) { 331 pr_debug2("testing event e1 %s: mismatched perpkg, %d vs %d\n", 332 e1->name, e1->perpkg, e2->perpkg); 333 return -1; 334 } 335 336 if (e1->deprecated != e2->deprecated) { 337 pr_debug2("testing event e1 %s: mismatched deprecated, %d vs %d\n", 338 e1->name, e1->deprecated, e2->deprecated); 339 return -1; 340 } 341 342 return 0; 343 } 344 345 static int compare_alias_to_test_event(struct pmu_event_info *alias, 346 struct perf_pmu_test_event const *test_event, 347 char const *pmu_name) 348 { 349 struct pmu_event const *event = &test_event->event; 350 351 /* An alias was found, ensure everything is in order */ 352 if (!is_same(alias->name, event->name)) { 353 pr_debug("testing aliases PMU %s: mismatched name, %s vs %s\n", 354 pmu_name, alias->name, event->name); 355 return -1; 356 } 357 358 if (!is_same(alias->desc, event->desc)) { 359 pr_debug("testing aliases PMU %s: mismatched desc, %s vs %s\n", 360 pmu_name, alias->desc, event->desc); 361 return -1; 362 } 363 364 if (!is_same(alias->long_desc, test_event->alias_long_desc)) { 365 pr_debug("testing aliases PMU %s: mismatched long_desc, %s vs %s\n", 366 pmu_name, alias->long_desc, 367 test_event->alias_long_desc); 368 return -1; 369 } 370 371 if (!is_same(alias->topic, event->topic)) { 372 pr_debug("testing aliases PMU %s: mismatched topic, %s vs %s\n", 373 pmu_name, alias->topic, event->topic); 374 return -1; 375 } 376 377 if (!is_same(alias->str, test_event->alias_str)) { 378 pr_debug("testing aliases PMU %s: mismatched str, %s vs %s\n", 379 pmu_name, alias->str, test_event->alias_str); 380 return -1; 381 } 382 383 if (!is_same(alias->long_desc, test_event->alias_long_desc)) { 384 pr_debug("testing aliases PMU %s: mismatched long desc, %s vs %s\n", 385 pmu_name, alias->str, test_event->alias_long_desc); 386 return -1; 387 } 388 389 if (!is_same(alias->pmu_name, test_event->event.pmu) && 390 !is_same(alias->pmu_name, "default_core")) { 391 pr_debug("testing aliases PMU %s: mismatched pmu_name, %s vs %s\n", 392 pmu_name, alias->pmu_name, test_event->event.pmu); 393 return -1; 394 } 395 396 return 0; 397 } 398 399 static int test__pmu_event_table_core_callback(const struct pmu_event *pe, 400 const struct pmu_events_table *table __maybe_unused, 401 void *data) 402 { 403 int *map_events = data; 404 struct perf_pmu_test_event const **test_event_table; 405 bool found = false; 406 407 if (strcmp(pe->pmu, "default_core")) 408 test_event_table = &uncore_events[0]; 409 else 410 test_event_table = &core_events[0]; 411 412 for (; *test_event_table; test_event_table++) { 413 struct perf_pmu_test_event const *test_event = *test_event_table; 414 struct pmu_event const *event = &test_event->event; 415 416 if (strcmp(pe->name, event->name)) 417 continue; 418 found = true; 419 (*map_events)++; 420 421 if (compare_pmu_events(pe, event)) 422 return -1; 423 424 pr_debug("testing event table %s: pass\n", pe->name); 425 } 426 if (!found) { 427 pr_err("testing event table: could not find event %s\n", pe->name); 428 return -1; 429 } 430 return 0; 431 } 432 433 static int test__pmu_event_table_sys_callback(const struct pmu_event *pe, 434 const struct pmu_events_table *table __maybe_unused, 435 void *data) 436 { 437 int *map_events = data; 438 struct perf_pmu_test_event const **test_event_table; 439 bool found = false; 440 441 test_event_table = &sys_events[0]; 442 443 for (; *test_event_table; test_event_table++) { 444 struct perf_pmu_test_event const *test_event = *test_event_table; 445 struct pmu_event const *event = &test_event->event; 446 447 if (strcmp(pe->name, event->name)) 448 continue; 449 found = true; 450 (*map_events)++; 451 452 if (compare_pmu_events(pe, event)) 453 return TEST_FAIL; 454 455 pr_debug("testing sys event table %s: pass\n", pe->name); 456 } 457 if (!found) { 458 pr_debug("testing sys event table: could not find event %s\n", pe->name); 459 return TEST_FAIL; 460 } 461 return TEST_OK; 462 } 463 464 /* Verify generated events from pmu-events.c are as expected */ 465 static int test__pmu_event_table(struct test_suite *test __maybe_unused, 466 int subtest __maybe_unused) 467 { 468 const struct pmu_events_table *sys_event_table = 469 find_sys_events_table("pmu_events__test_soc_sys"); 470 const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu"); 471 int map_events = 0, expected_events, err; 472 473 /* ignore 3x sentinels */ 474 expected_events = ARRAY_SIZE(core_events) + 475 ARRAY_SIZE(uncore_events) + 476 ARRAY_SIZE(sys_events) - 3; 477 478 if (!table || !sys_event_table) 479 return -1; 480 481 err = pmu_events_table__for_each_event(table, /*pmu=*/ NULL, 482 test__pmu_event_table_core_callback, 483 &map_events); 484 if (err) 485 return err; 486 487 err = pmu_events_table__for_each_event(sys_event_table, /*pmu=*/ NULL, 488 test__pmu_event_table_sys_callback, 489 &map_events); 490 if (err) 491 return err; 492 493 if (map_events != expected_events) { 494 pr_err("testing event table: found %d, but expected %d\n", 495 map_events, expected_events); 496 return TEST_FAIL; 497 } 498 499 return 0; 500 } 501 502 struct test_core_pmu_event_aliases_cb_args { 503 struct perf_pmu_test_event const *test_event; 504 int *count; 505 }; 506 507 static int test_core_pmu_event_aliases_cb(void *state, struct pmu_event_info *alias) 508 { 509 struct test_core_pmu_event_aliases_cb_args *args = state; 510 511 if (compare_alias_to_test_event(alias, args->test_event, alias->pmu->name)) 512 return -1; 513 (*args->count)++; 514 pr_debug2("testing aliases core PMU %s: matched event %s\n", 515 alias->pmu_name, alias->name); 516 return 0; 517 } 518 519 /* Verify aliases are as expected */ 520 static int __test_core_pmu_event_aliases(const char *pmu_name, int *count) 521 { 522 struct perf_pmu_test_event const **test_event_table; 523 struct perf_pmu *pmu; 524 int res = 0; 525 const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu"); 526 527 if (!table) 528 return -1; 529 530 test_event_table = &core_events[0]; 531 532 pmu = zalloc(sizeof(*pmu)); 533 if (!pmu) 534 return -1; 535 536 if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, pmu_name) != 0) { 537 perf_pmu__delete(pmu); 538 return -1; 539 } 540 pmu->is_core = true; 541 542 pmu->events_table = table; 543 pmu_add_cpu_aliases_table(pmu, table); 544 pmu->cpu_aliases_added = true; 545 pmu->sysfs_aliases_loaded = true; 546 547 res = pmu_events_table__find_event(table, pmu, "bp_l1_btb_correct", NULL, NULL); 548 if (res != 0) { 549 pr_debug("Missing test event in test architecture"); 550 return res; 551 } 552 for (; *test_event_table; test_event_table++) { 553 struct perf_pmu_test_event test_event = **test_event_table; 554 struct pmu_event const *event = &test_event.event; 555 struct test_core_pmu_event_aliases_cb_args args = { 556 .test_event = &test_event, 557 .count = count, 558 }; 559 int err; 560 561 test_event.event.pmu = pmu_name; 562 err = perf_pmu__find_event(pmu, event->name, &args, 563 test_core_pmu_event_aliases_cb); 564 if (err) 565 res = err; 566 } 567 perf_pmu__delete(pmu); 568 569 return res; 570 } 571 572 static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu) 573 { 574 int alias_count = 0, to_match_count = 0, matched_count = 0; 575 struct perf_pmu_test_event const **table; 576 struct perf_pmu *pmu; 577 const struct pmu_events_table *events_table; 578 int res = 0; 579 580 events_table = find_core_events_table("testarch", "testcpu"); 581 if (!events_table) 582 return -1; 583 584 pmu = zalloc(sizeof(*pmu)); 585 if (!pmu) 586 return -1; 587 588 if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, test_pmu->pmu_name) != 0) { 589 perf_pmu__delete(pmu); 590 return -1; 591 } 592 pmu->is_uncore = test_pmu->pmu_is_uncore; 593 if (test_pmu->pmu_id) { 594 pmu->id = strdup(test_pmu->pmu_id); 595 if (!pmu->id) { 596 perf_pmu__delete(pmu); 597 return -1; 598 } 599 } 600 pmu->events_table = events_table; 601 pmu_add_cpu_aliases_table(pmu, events_table); 602 pmu->cpu_aliases_added = true; 603 pmu->sysfs_aliases_loaded = true; 604 pmu_add_sys_aliases(pmu); 605 606 /* Count how many aliases we generated */ 607 alias_count = perf_pmu__num_events(pmu); 608 609 /* Count how many aliases we expect from the known table */ 610 for (table = &test_pmu->aliases[0]; *table; table++) 611 to_match_count++; 612 613 if (alias_count != to_match_count) { 614 pr_debug("testing aliases uncore PMU %s: mismatch expected aliases (%d) vs found (%d)\n", 615 pmu->name, to_match_count, alias_count); 616 perf_pmu__delete(pmu); 617 return -1; 618 } 619 620 for (table = &test_pmu->aliases[0]; *table; table++) { 621 struct perf_pmu_test_event test_event = **table; 622 struct pmu_event const *event = &test_event.event; 623 int err; 624 struct test_core_pmu_event_aliases_cb_args args = { 625 .test_event = &test_event, 626 .count = &matched_count, 627 }; 628 629 if (strcmp(pmu->name, test_event.matching_pmu)) { 630 pr_debug("testing aliases uncore PMU %s: mismatched matching_pmu, %s vs %s\n", 631 pmu->name, test_event.matching_pmu, pmu->name); 632 perf_pmu__delete(pmu); 633 return -1; 634 } 635 636 err = perf_pmu__find_event(pmu, event->name, &args, 637 test_core_pmu_event_aliases_cb); 638 if (err) { 639 res = err; 640 pr_debug("testing aliases uncore PMU %s: could not match alias %s\n", 641 pmu->name, event->name); 642 perf_pmu__delete(pmu); 643 return -1; 644 } 645 } 646 647 if (alias_count != matched_count) { 648 pr_debug("testing aliases uncore PMU %s: mismatch found aliases (%d) vs matched (%d)\n", 649 pmu->name, matched_count, alias_count); 650 res = -1; 651 } 652 perf_pmu__delete(pmu); 653 return res; 654 } 655 656 static struct perf_pmu_test_pmu test_pmus[] = { 657 { 658 .pmu_name = "hisi_sccl1_ddrc2", 659 .pmu_is_uncore = 1, 660 .aliases = { 661 &uncore_hisi_ddrc_flux_wcmd, 662 }, 663 }, 664 { 665 .pmu_name = "uncore_cbox_0", 666 .pmu_is_uncore = 1, 667 .aliases = { 668 &unc_cbo_xsnp_response_miss_eviction, 669 &uncore_hyphen, 670 &uncore_two_hyph, 671 }, 672 }, 673 { 674 .pmu_name = "hisi_sccl3_l3c7", 675 .pmu_is_uncore = 1, 676 .aliases = { 677 &uncore_hisi_l3c_rd_hit_cpipe, 678 }, 679 }, 680 { 681 .pmu_name = "uncore_imc_free_running_0", 682 .pmu_is_uncore = 1, 683 .aliases = { 684 &uncore_imc_free_running_cache_miss, 685 }, 686 }, 687 { 688 .pmu_name = "uncore_imc_0", 689 .pmu_is_uncore = 1, 690 .aliases = { 691 &uncore_imc_cache_hits, 692 }, 693 }, 694 { 695 .pmu_name = "uncore_sys_ddr_pmu0", 696 .pmu_is_uncore = 1, 697 .pmu_id = "v8", 698 .aliases = { 699 &sys_ddr_pmu_write_cycles, 700 }, 701 }, 702 { 703 .pmu_name = "uncore_sys_ccn_pmu4", 704 .pmu_is_uncore = 1, 705 .pmu_id = "0x01", 706 .aliases = { 707 &sys_ccn_pmu_read_cycles, 708 }, 709 }, 710 { 711 .pmu_name = "uncore_sys_cmn_pmu0", 712 .pmu_is_uncore = 1, 713 .pmu_id = "43401", 714 .aliases = { 715 &sys_cmn_pmu_hnf_cache_miss, 716 }, 717 }, 718 { 719 .pmu_name = "uncore_sys_cmn_pmu0", 720 .pmu_is_uncore = 1, 721 .pmu_id = "43602", 722 .aliases = { 723 &sys_cmn_pmu_hnf_cache_miss, 724 }, 725 }, 726 { 727 .pmu_name = "uncore_sys_cmn_pmu0", 728 .pmu_is_uncore = 1, 729 .pmu_id = "43c03", 730 .aliases = { 731 &sys_cmn_pmu_hnf_cache_miss, 732 }, 733 }, 734 { 735 .pmu_name = "uncore_sys_cmn_pmu0", 736 .pmu_is_uncore = 1, 737 .pmu_id = "43a01", 738 .aliases = { 739 &sys_cmn_pmu_hnf_cache_miss, 740 }, 741 } 742 }; 743 744 /* Test that aliases generated are as expected */ 745 static int test__aliases(struct test_suite *test __maybe_unused, 746 int subtest __maybe_unused) 747 { 748 struct perf_pmu *pmu = NULL; 749 unsigned long i; 750 751 while ((pmu = perf_pmus__scan_core(pmu)) != NULL) { 752 int count = 0; 753 754 if (list_empty(&pmu->format)) { 755 pr_debug2("skipping testing core PMU %s\n", pmu->name); 756 continue; 757 } 758 759 if (__test_core_pmu_event_aliases(pmu->name, &count)) { 760 pr_debug("testing core PMU %s aliases: failed\n", pmu->name); 761 return -1; 762 } 763 764 if (count == 0) { 765 pr_debug("testing core PMU %s aliases: no events to match\n", 766 pmu->name); 767 return -1; 768 } 769 770 pr_debug("testing core PMU %s aliases: pass\n", pmu->name); 771 } 772 773 for (i = 0; i < ARRAY_SIZE(test_pmus); i++) { 774 int res; 775 776 res = __test_uncore_pmu_event_aliases(&test_pmus[i]); 777 if (res) 778 return res; 779 } 780 781 return 0; 782 } 783 784 static bool is_number(const char *str) 785 { 786 char *end_ptr; 787 double v; 788 789 errno = 0; 790 v = strtod(str, &end_ptr); 791 (void)v; // We're not interested in this value, only if it is valid 792 return errno == 0 && end_ptr != str; 793 } 794 795 static int check_parse_id(const char *id, struct parse_events_error *error) 796 { 797 struct evlist *evlist; 798 int ret; 799 char *dup, *cur; 800 801 /* Numbers are always valid. */ 802 if (is_number(id)) 803 return 0; 804 805 evlist = evlist__new(); 806 if (!evlist) 807 return -ENOMEM; 808 809 dup = strdup(id); 810 if (!dup) 811 return -ENOMEM; 812 813 for (cur = strchr(dup, '@') ; cur; cur = strchr(++cur, '@')) 814 *cur = '/'; 815 816 ret = __parse_events(evlist, dup, /*pmu_filter=*/NULL, error, /*fake_pmu=*/true, 817 /*warn_if_reordered=*/true, /*fake_tp=*/false); 818 free(dup); 819 820 evlist__delete(evlist); 821 return ret; 822 } 823 824 static int check_parse_fake(const char *id) 825 { 826 struct parse_events_error error; 827 int ret; 828 829 parse_events_error__init(&error); 830 ret = check_parse_id(id, &error); 831 parse_events_error__exit(&error); 832 return ret; 833 } 834 835 struct metric { 836 struct list_head list; 837 struct metric_ref metric_ref; 838 }; 839 840 static int test__parsing_callback(const struct pmu_metric *pm, 841 const struct pmu_metrics_table *table, 842 void *data) 843 { 844 int *failures = data; 845 int k; 846 struct evlist *evlist; 847 struct perf_cpu_map *cpus; 848 struct evsel *evsel; 849 int err = 0; 850 851 if (!pm->metric_expr) 852 return 0; 853 854 pr_debug("Found metric '%s'\n", pm->metric_name); 855 (*failures)++; 856 857 /* 858 * We need to prepare evlist for stat mode running on CPU 0 859 * because that's where all the stats are going to be created. 860 */ 861 evlist = evlist__new(); 862 if (!evlist) 863 return -ENOMEM; 864 865 cpus = perf_cpu_map__new("0"); 866 if (!cpus) { 867 evlist__delete(evlist); 868 return -ENOMEM; 869 } 870 871 perf_evlist__set_maps(&evlist->core, cpus, NULL); 872 873 err = metricgroup__parse_groups_test(evlist, table, pm->metric_name); 874 if (err) { 875 if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") || 876 !strcmp(pm->metric_name, "M3")) { 877 (*failures)--; 878 pr_debug("Expected broken metric %s skipping\n", pm->metric_name); 879 err = 0; 880 } 881 goto out_err; 882 } 883 884 err = evlist__alloc_stats(/*config=*/NULL, evlist, /*alloc_raw=*/false); 885 if (err) 886 goto out_err; 887 /* 888 * Add all ids with a made up value. The value may trigger divide by 889 * zero when subtracted and so try to make them unique. 890 */ 891 k = 1; 892 evlist__alloc_aggr_stats(evlist, 1); 893 evlist__for_each_entry(evlist, evsel) { 894 evsel->stats->aggr->counts.val = k; 895 if (evsel__name_is(evsel, "duration_time")) 896 update_stats(&walltime_nsecs_stats, k); 897 k++; 898 } 899 evlist__for_each_entry(evlist, evsel) { 900 struct metric_event *me = metricgroup__lookup(&evlist->metric_events, evsel, false); 901 902 if (me != NULL) { 903 struct metric_expr *mexp; 904 905 list_for_each_entry (mexp, &me->head, nd) { 906 if (strcmp(mexp->metric_name, pm->metric_name)) 907 continue; 908 pr_debug("Result %f\n", test_generic_metric(mexp, 0)); 909 err = 0; 910 (*failures)--; 911 goto out_err; 912 } 913 } 914 } 915 pr_debug("Didn't find parsed metric %s", pm->metric_name); 916 err = 1; 917 out_err: 918 if (err) 919 pr_debug("Broken metric %s\n", pm->metric_name); 920 921 /* ... cleanup. */ 922 evlist__free_stats(evlist); 923 perf_cpu_map__put(cpus); 924 evlist__delete(evlist); 925 return err; 926 } 927 928 static int test__parsing(struct test_suite *test __maybe_unused, 929 int subtest __maybe_unused) 930 { 931 int failures = 0; 932 933 pmu_for_each_core_metric(test__parsing_callback, &failures); 934 pmu_for_each_sys_metric(test__parsing_callback, &failures); 935 936 return failures == 0 ? TEST_OK : TEST_FAIL; 937 } 938 939 struct test_metric { 940 const char *str; 941 }; 942 943 static struct test_metric metrics[] = { 944 { "(unc_p_power_state_occupancy.cores_c0 / unc_p_clockticks) * 100." }, 945 { "imx8_ddr0@read\\-cycles@ * 4 * 4", }, 946 { "imx8_ddr0@axid\\-read\\,axi_mask\\=0xffff\\,axi_id\\=0x0000@ * 4", }, 947 { "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100", }, 948 { "(imx8_ddr0@read\\-cycles@ + imx8_ddr0@write\\-cycles@)", }, 949 }; 950 951 static int metric_parse_fake(const char *metric_name, const char *str) 952 { 953 struct expr_parse_ctx *ctx; 954 struct hashmap_entry *cur; 955 double result; 956 int ret = -1; 957 size_t bkt; 958 int i; 959 960 pr_debug("parsing '%s': '%s'\n", metric_name, str); 961 962 ctx = expr__ctx_new(); 963 if (!ctx) { 964 pr_debug("expr__ctx_new failed"); 965 return TEST_FAIL; 966 } 967 ctx->sctx.is_test = true; 968 if (expr__find_ids(str, NULL, ctx) < 0) { 969 pr_err("expr__find_ids failed\n"); 970 return -1; 971 } 972 973 /* 974 * Add all ids with a made up value. The value may 975 * trigger divide by zero when subtracted and so try to 976 * make them unique. 977 */ 978 i = 1; 979 hashmap__for_each_entry(ctx->ids, cur, bkt) 980 expr__add_id_val(ctx, strdup(cur->pkey), i++); 981 982 hashmap__for_each_entry(ctx->ids, cur, bkt) { 983 if (check_parse_fake(cur->pkey)) { 984 pr_err("check_parse_fake failed\n"); 985 goto out; 986 } 987 } 988 989 ret = 0; 990 if (expr__parse(&result, ctx, str)) { 991 /* 992 * Parsing failed, make numbers go from large to small which can 993 * resolve divide by zero issues. 994 */ 995 i = 1024; 996 hashmap__for_each_entry(ctx->ids, cur, bkt) 997 expr__add_id_val(ctx, strdup(cur->pkey), i--); 998 if (expr__parse(&result, ctx, str)) { 999 pr_err("expr__parse failed for %s\n", metric_name); 1000 /* The following have hard to avoid divide by zero. */ 1001 if (!strcmp(metric_name, "tma_clears_resteers") || 1002 !strcmp(metric_name, "tma_mispredicts_resteers")) 1003 ret = 0; 1004 else 1005 ret = -1; 1006 } 1007 } 1008 1009 out: 1010 expr__ctx_free(ctx); 1011 return ret; 1012 } 1013 1014 static int test__parsing_fake_callback(const struct pmu_metric *pm, 1015 const struct pmu_metrics_table *table __maybe_unused, 1016 void *data __maybe_unused) 1017 { 1018 return metric_parse_fake(pm->metric_name, pm->metric_expr); 1019 } 1020 1021 /* 1022 * Parse all the metrics for current architecture, or all defined cpus via the 1023 * 'fake_pmu' in parse_events. 1024 */ 1025 static int test__parsing_fake(struct test_suite *test __maybe_unused, 1026 int subtest __maybe_unused) 1027 { 1028 int err = 0; 1029 1030 for (size_t i = 0; i < ARRAY_SIZE(metrics); i++) { 1031 err = metric_parse_fake("", metrics[i].str); 1032 if (err) 1033 return err; 1034 } 1035 1036 err = pmu_for_each_core_metric(test__parsing_fake_callback, NULL); 1037 if (err) 1038 return err; 1039 1040 return pmu_for_each_sys_metric(test__parsing_fake_callback, NULL); 1041 } 1042 1043 static int test__parsing_threshold_callback(const struct pmu_metric *pm, 1044 const struct pmu_metrics_table *table __maybe_unused, 1045 void *data __maybe_unused) 1046 { 1047 if (!pm->metric_threshold) 1048 return 0; 1049 return metric_parse_fake(pm->metric_name, pm->metric_threshold); 1050 } 1051 1052 static int test__parsing_threshold(struct test_suite *test __maybe_unused, 1053 int subtest __maybe_unused) 1054 { 1055 int err = 0; 1056 1057 err = pmu_for_each_core_metric(test__parsing_threshold_callback, NULL); 1058 if (err) 1059 return err; 1060 1061 return pmu_for_each_sys_metric(test__parsing_threshold_callback, NULL); 1062 } 1063 1064 static struct test_case pmu_events_tests[] = { 1065 TEST_CASE("PMU event table sanity", pmu_event_table), 1066 TEST_CASE("PMU event map aliases", aliases), 1067 TEST_CASE_REASON("Parsing of PMU event table metrics", parsing, 1068 "some metrics failed"), 1069 TEST_CASE("Parsing of PMU event table metrics with fake PMUs", parsing_fake), 1070 TEST_CASE("Parsing of metric thresholds with fake PMUs", parsing_threshold), 1071 { .name = NULL, } 1072 }; 1073 1074 struct test_suite suite__pmu_events = { 1075 .desc = "PMU JSON event tests", 1076 .test_cases = pmu_events_tests, 1077 }; 1078