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