1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * builtin-test.c 4 * 5 * Builtin regression testing command: ever growing number of sanity tests 6 */ 7 #include <fcntl.h> 8 #include <errno.h> 9 #include <unistd.h> 10 #include <string.h> 11 #include <sys/types.h> 12 #include <dirent.h> 13 #include <sys/wait.h> 14 #include <sys/stat.h> 15 #include "builtin.h" 16 #include "hist.h" 17 #include "intlist.h" 18 #include "tests.h" 19 #include "debug.h" 20 #include "color.h" 21 #include <subcmd/parse-options.h> 22 #include "string2.h" 23 #include "symbol.h" 24 #include <linux/kernel.h> 25 #include <subcmd/exec-cmd.h> 26 27 static bool dont_fork; 28 29 struct test __weak arch_tests[] = { 30 { 31 .func = NULL, 32 }, 33 }; 34 35 static struct test generic_tests[] = { 36 { 37 .desc = "vmlinux symtab matches kallsyms", 38 .func = test__vmlinux_matches_kallsyms, 39 }, 40 { 41 .desc = "Detect openat syscall event", 42 .func = test__openat_syscall_event, 43 }, 44 { 45 .desc = "Detect openat syscall event on all cpus", 46 .func = test__openat_syscall_event_on_all_cpus, 47 }, 48 { 49 .desc = "Read samples using the mmap interface", 50 .func = test__basic_mmap, 51 }, 52 { 53 .desc = "Test data source output", 54 .func = test__mem, 55 }, 56 { 57 .desc = "Parse event definition strings", 58 .func = test__parse_events, 59 }, 60 { 61 .desc = "Simple expression parser", 62 .func = test__expr, 63 }, 64 { 65 .desc = "PERF_RECORD_* events & perf_sample fields", 66 .func = test__PERF_RECORD, 67 }, 68 { 69 .desc = "Parse perf pmu format", 70 .func = test__pmu, 71 }, 72 { 73 .desc = "DSO data read", 74 .func = test__dso_data, 75 }, 76 { 77 .desc = "DSO data cache", 78 .func = test__dso_data_cache, 79 }, 80 { 81 .desc = "DSO data reopen", 82 .func = test__dso_data_reopen, 83 }, 84 { 85 .desc = "Roundtrip evsel->name", 86 .func = test__perf_evsel__roundtrip_name_test, 87 }, 88 { 89 .desc = "Parse sched tracepoints fields", 90 .func = test__perf_evsel__tp_sched_test, 91 }, 92 { 93 .desc = "syscalls:sys_enter_openat event fields", 94 .func = test__syscall_openat_tp_fields, 95 }, 96 { 97 .desc = "Setup struct perf_event_attr", 98 .func = test__attr, 99 }, 100 { 101 .desc = "Match and link multiple hists", 102 .func = test__hists_link, 103 }, 104 { 105 .desc = "'import perf' in python", 106 .func = test__python_use, 107 }, 108 { 109 .desc = "Breakpoint overflow signal handler", 110 .func = test__bp_signal, 111 .is_supported = test__bp_signal_is_supported, 112 }, 113 { 114 .desc = "Breakpoint overflow sampling", 115 .func = test__bp_signal_overflow, 116 .is_supported = test__bp_signal_is_supported, 117 }, 118 { 119 .desc = "Number of exit events of a simple workload", 120 .func = test__task_exit, 121 }, 122 { 123 .desc = "Software clock events period values", 124 .func = test__sw_clock_freq, 125 }, 126 { 127 .desc = "Object code reading", 128 .func = test__code_reading, 129 }, 130 { 131 .desc = "Sample parsing", 132 .func = test__sample_parsing, 133 }, 134 { 135 .desc = "Use a dummy software event to keep tracking", 136 .func = test__keep_tracking, 137 }, 138 { 139 .desc = "Parse with no sample_id_all bit set", 140 .func = test__parse_no_sample_id_all, 141 }, 142 { 143 .desc = "Filter hist entries", 144 .func = test__hists_filter, 145 }, 146 { 147 .desc = "Lookup mmap thread", 148 .func = test__mmap_thread_lookup, 149 }, 150 { 151 .desc = "Share thread mg", 152 .func = test__thread_mg_share, 153 }, 154 { 155 .desc = "Sort output of hist entries", 156 .func = test__hists_output, 157 }, 158 { 159 .desc = "Cumulate child hist entries", 160 .func = test__hists_cumulate, 161 }, 162 { 163 .desc = "Track with sched_switch", 164 .func = test__switch_tracking, 165 }, 166 { 167 .desc = "Filter fds with revents mask in a fdarray", 168 .func = test__fdarray__filter, 169 }, 170 { 171 .desc = "Add fd to a fdarray, making it autogrow", 172 .func = test__fdarray__add, 173 }, 174 { 175 .desc = "kmod_path__parse", 176 .func = test__kmod_path__parse, 177 }, 178 { 179 .desc = "Thread map", 180 .func = test__thread_map, 181 }, 182 { 183 .desc = "LLVM search and compile", 184 .func = test__llvm, 185 .subtest = { 186 .skip_if_fail = true, 187 .get_nr = test__llvm_subtest_get_nr, 188 .get_desc = test__llvm_subtest_get_desc, 189 }, 190 }, 191 { 192 .desc = "Session topology", 193 .func = test__session_topology, 194 }, 195 { 196 .desc = "BPF filter", 197 .func = test__bpf, 198 .subtest = { 199 .skip_if_fail = true, 200 .get_nr = test__bpf_subtest_get_nr, 201 .get_desc = test__bpf_subtest_get_desc, 202 }, 203 }, 204 { 205 .desc = "Synthesize thread map", 206 .func = test__thread_map_synthesize, 207 }, 208 { 209 .desc = "Remove thread map", 210 .func = test__thread_map_remove, 211 }, 212 { 213 .desc = "Synthesize cpu map", 214 .func = test__cpu_map_synthesize, 215 }, 216 { 217 .desc = "Synthesize stat config", 218 .func = test__synthesize_stat_config, 219 }, 220 { 221 .desc = "Synthesize stat", 222 .func = test__synthesize_stat, 223 }, 224 { 225 .desc = "Synthesize stat round", 226 .func = test__synthesize_stat_round, 227 }, 228 { 229 .desc = "Synthesize attr update", 230 .func = test__event_update, 231 }, 232 { 233 .desc = "Event times", 234 .func = test__event_times, 235 }, 236 { 237 .desc = "Read backward ring buffer", 238 .func = test__backward_ring_buffer, 239 }, 240 { 241 .desc = "Print cpu map", 242 .func = test__cpu_map_print, 243 }, 244 { 245 .desc = "Probe SDT events", 246 .func = test__sdt_event, 247 }, 248 { 249 .desc = "is_printable_array", 250 .func = test__is_printable_array, 251 }, 252 { 253 .desc = "Print bitmap", 254 .func = test__bitmap_print, 255 }, 256 { 257 .desc = "perf hooks", 258 .func = test__perf_hooks, 259 }, 260 { 261 .desc = "builtin clang support", 262 .func = test__clang, 263 .subtest = { 264 .skip_if_fail = true, 265 .get_nr = test__clang_subtest_get_nr, 266 .get_desc = test__clang_subtest_get_desc, 267 } 268 }, 269 { 270 .desc = "unit_number__scnprintf", 271 .func = test__unit_number__scnprint, 272 }, 273 { 274 .func = NULL, 275 }, 276 }; 277 278 static struct test *tests[] = { 279 generic_tests, 280 arch_tests, 281 }; 282 283 static bool perf_test__matches(struct test *test, int curr, int argc, const char *argv[]) 284 { 285 int i; 286 287 if (argc == 0) 288 return true; 289 290 for (i = 0; i < argc; ++i) { 291 char *end; 292 long nr = strtoul(argv[i], &end, 10); 293 294 if (*end == '\0') { 295 if (nr == curr + 1) 296 return true; 297 continue; 298 } 299 300 if (strcasestr(test->desc, argv[i])) 301 return true; 302 } 303 304 return false; 305 } 306 307 static int run_test(struct test *test, int subtest) 308 { 309 int status, err = -1, child = dont_fork ? 0 : fork(); 310 char sbuf[STRERR_BUFSIZE]; 311 312 if (child < 0) { 313 pr_err("failed to fork test: %s\n", 314 str_error_r(errno, sbuf, sizeof(sbuf))); 315 return -1; 316 } 317 318 if (!child) { 319 if (!dont_fork) { 320 pr_debug("test child forked, pid %d\n", getpid()); 321 322 if (verbose <= 0) { 323 int nullfd = open("/dev/null", O_WRONLY); 324 325 if (nullfd >= 0) { 326 close(STDERR_FILENO); 327 close(STDOUT_FILENO); 328 329 dup2(nullfd, STDOUT_FILENO); 330 dup2(STDOUT_FILENO, STDERR_FILENO); 331 close(nullfd); 332 } 333 } else { 334 signal(SIGSEGV, sighandler_dump_stack); 335 signal(SIGFPE, sighandler_dump_stack); 336 } 337 } 338 339 err = test->func(test, subtest); 340 if (!dont_fork) 341 exit(err); 342 } 343 344 if (!dont_fork) { 345 wait(&status); 346 347 if (WIFEXITED(status)) { 348 err = (signed char)WEXITSTATUS(status); 349 pr_debug("test child finished with %d\n", err); 350 } else if (WIFSIGNALED(status)) { 351 err = -1; 352 pr_debug("test child interrupted\n"); 353 } 354 } 355 356 return err; 357 } 358 359 #define for_each_test(j, t) \ 360 for (j = 0; j < ARRAY_SIZE(tests); j++) \ 361 for (t = &tests[j][0]; t->func; t++) 362 363 static int test_and_print(struct test *t, bool force_skip, int subtest) 364 { 365 int err; 366 367 if (!force_skip) { 368 pr_debug("\n--- start ---\n"); 369 err = run_test(t, subtest); 370 pr_debug("---- end ----\n"); 371 } else { 372 pr_debug("\n--- force skipped ---\n"); 373 err = TEST_SKIP; 374 } 375 376 if (!t->subtest.get_nr) 377 pr_debug("%s:", t->desc); 378 else 379 pr_debug("%s subtest %d:", t->desc, subtest); 380 381 switch (err) { 382 case TEST_OK: 383 pr_info(" Ok\n"); 384 break; 385 case TEST_SKIP: 386 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n"); 387 break; 388 case TEST_FAIL: 389 default: 390 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); 391 break; 392 } 393 394 return err; 395 } 396 397 static const char *shell_test__description(char *description, size_t size, 398 const char *path, const char *name) 399 { 400 FILE *fp; 401 char filename[PATH_MAX]; 402 403 path__join(filename, sizeof(filename), path, name); 404 fp = fopen(filename, "r"); 405 if (!fp) 406 return NULL; 407 408 description = fgets(description, size, fp); 409 fclose(fp); 410 411 return description ? trim(description + 1) : NULL; 412 } 413 414 #define for_each_shell_test(dir, ent) \ 415 while ((ent = readdir(dir)) != NULL) \ 416 if (ent->d_type == DT_REG && ent->d_name[0] != '.') 417 418 static const char *shell_tests__dir(char *path, size_t size) 419 { 420 const char *devel_dirs[] = { "./tools/perf/tests", "./tests", }; 421 char *exec_path; 422 unsigned int i; 423 424 for (i = 0; i < ARRAY_SIZE(devel_dirs); ++i) { 425 struct stat st; 426 if (!lstat(devel_dirs[i], &st)) { 427 scnprintf(path, size, "%s/shell", devel_dirs[i]); 428 if (!lstat(devel_dirs[i], &st)) 429 return path; 430 } 431 } 432 433 /* Then installed path. */ 434 exec_path = get_argv_exec_path(); 435 scnprintf(path, size, "%s/tests/shell", exec_path); 436 free(exec_path); 437 return path; 438 } 439 440 static int shell_tests__max_desc_width(void) 441 { 442 DIR *dir; 443 struct dirent *ent; 444 char path_dir[PATH_MAX]; 445 const char *path = shell_tests__dir(path_dir, sizeof(path_dir)); 446 int width = 0; 447 448 if (path == NULL) 449 return -1; 450 451 dir = opendir(path); 452 if (!dir) 453 return -1; 454 455 for_each_shell_test(dir, ent) { 456 char bf[256]; 457 const char *desc = shell_test__description(bf, sizeof(bf), path, ent->d_name); 458 459 if (desc) { 460 int len = strlen(desc); 461 462 if (width < len) 463 width = len; 464 } 465 } 466 467 closedir(dir); 468 return width; 469 } 470 471 struct shell_test { 472 const char *dir; 473 const char *file; 474 }; 475 476 static int shell_test__run(struct test *test, int subdir __maybe_unused) 477 { 478 int err; 479 char script[PATH_MAX]; 480 struct shell_test *st = test->priv; 481 482 path__join(script, sizeof(script), st->dir, st->file); 483 484 err = system(script); 485 if (!err) 486 return TEST_OK; 487 488 return WEXITSTATUS(err) == 2 ? TEST_SKIP : TEST_FAIL; 489 } 490 491 static int run_shell_tests(int argc, const char *argv[], int i, int width) 492 { 493 DIR *dir; 494 struct dirent *ent; 495 char path_dir[PATH_MAX]; 496 struct shell_test st = { 497 .dir = shell_tests__dir(path_dir, sizeof(path_dir)), 498 }; 499 500 if (st.dir == NULL) 501 return -1; 502 503 dir = opendir(st.dir); 504 if (!dir) 505 return -1; 506 507 for_each_shell_test(dir, ent) { 508 int curr = i++; 509 char desc[256]; 510 struct test test = { 511 .desc = shell_test__description(desc, sizeof(desc), st.dir, ent->d_name), 512 .func = shell_test__run, 513 .priv = &st, 514 }; 515 516 if (!perf_test__matches(&test, curr, argc, argv)) 517 continue; 518 519 st.file = ent->d_name; 520 pr_info("%2d: %-*s:", i, width, test.desc); 521 test_and_print(&test, false, -1); 522 } 523 524 closedir(dir); 525 return 0; 526 } 527 528 static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) 529 { 530 struct test *t; 531 unsigned int j; 532 int i = 0; 533 int width = shell_tests__max_desc_width(); 534 535 for_each_test(j, t) { 536 int len = strlen(t->desc); 537 538 if (width < len) 539 width = len; 540 } 541 542 for_each_test(j, t) { 543 int curr = i++, err; 544 545 if (!perf_test__matches(t, curr, argc, argv)) 546 continue; 547 548 if (t->is_supported && !t->is_supported()) { 549 pr_debug("%2d: %-*s: Disabled\n", i, width, t->desc); 550 continue; 551 } 552 553 pr_info("%2d: %-*s:", i, width, t->desc); 554 555 if (intlist__find(skiplist, i)) { 556 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); 557 continue; 558 } 559 560 if (!t->subtest.get_nr) { 561 test_and_print(t, false, -1); 562 } else { 563 int subn = t->subtest.get_nr(); 564 /* 565 * minus 2 to align with normal testcases. 566 * For subtest we print additional '.x' in number. 567 * for example: 568 * 569 * 35: Test LLVM searching and compiling : 570 * 35.1: Basic BPF llvm compiling test : Ok 571 */ 572 int subw = width > 2 ? width - 2 : width; 573 bool skip = false; 574 int subi; 575 576 if (subn <= 0) { 577 color_fprintf(stderr, PERF_COLOR_YELLOW, 578 " Skip (not compiled in)\n"); 579 continue; 580 } 581 pr_info("\n"); 582 583 for (subi = 0; subi < subn; subi++) { 584 int len = strlen(t->subtest.get_desc(subi)); 585 586 if (subw < len) 587 subw = len; 588 } 589 590 for (subi = 0; subi < subn; subi++) { 591 pr_info("%2d.%1d: %-*s:", i, subi + 1, subw, 592 t->subtest.get_desc(subi)); 593 err = test_and_print(t, skip, subi); 594 if (err != TEST_OK && t->subtest.skip_if_fail) 595 skip = true; 596 } 597 } 598 } 599 600 return run_shell_tests(argc, argv, i, width); 601 } 602 603 static int perf_test__list_shell(int argc, const char **argv, int i) 604 { 605 DIR *dir; 606 struct dirent *ent; 607 char path_dir[PATH_MAX]; 608 const char *path = shell_tests__dir(path_dir, sizeof(path_dir)); 609 610 if (path == NULL) 611 return -1; 612 613 dir = opendir(path); 614 if (!dir) 615 return -1; 616 617 for_each_shell_test(dir, ent) { 618 int curr = i++; 619 char bf[256]; 620 struct test t = { 621 .desc = shell_test__description(bf, sizeof(bf), path, ent->d_name), 622 }; 623 624 if (!perf_test__matches(&t, curr, argc, argv)) 625 continue; 626 627 pr_info("%2d: %s\n", i, t.desc); 628 } 629 630 closedir(dir); 631 return 0; 632 } 633 634 static int perf_test__list(int argc, const char **argv) 635 { 636 unsigned int j; 637 struct test *t; 638 int i = 0; 639 640 for_each_test(j, t) { 641 int curr = i++; 642 643 if (!perf_test__matches(t, curr, argc, argv) || 644 (t->is_supported && !t->is_supported())) 645 continue; 646 647 pr_info("%2d: %s\n", i, t->desc); 648 } 649 650 perf_test__list_shell(argc, argv, i); 651 652 return 0; 653 } 654 655 int cmd_test(int argc, const char **argv) 656 { 657 const char *test_usage[] = { 658 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", 659 NULL, 660 }; 661 const char *skip = NULL; 662 const struct option test_options[] = { 663 OPT_STRING('s', "skip", &skip, "tests", "tests to skip"), 664 OPT_INCR('v', "verbose", &verbose, 665 "be more verbose (show symbol address, etc)"), 666 OPT_BOOLEAN('F', "dont-fork", &dont_fork, 667 "Do not fork for testcase"), 668 OPT_END() 669 }; 670 const char * const test_subcommands[] = { "list", NULL }; 671 struct intlist *skiplist = NULL; 672 int ret = hists__init(); 673 674 if (ret < 0) 675 return ret; 676 677 argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0); 678 if (argc >= 1 && !strcmp(argv[0], "list")) 679 return perf_test__list(argc - 1, argv + 1); 680 681 symbol_conf.priv_size = sizeof(int); 682 symbol_conf.sort_by_name = true; 683 symbol_conf.try_vmlinux_path = true; 684 685 if (symbol__init(NULL) < 0) 686 return -1; 687 688 if (skip != NULL) 689 skiplist = intlist__new(skip); 690 691 return __cmd_test(argc, argv, skiplist); 692 } 693