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