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