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