~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/tests/builtin-test.c

Version: ~ [ linux-5.12-rc1 ] ~ [ linux-5.11.2 ] ~ [ linux-5.10.19 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.101 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.177 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.222 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.258 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.258 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 30 static bool dont_fork;
 31 
 32 struct test __weak arch_tests[] = {
 33         {
 34                 .func = NULL,
 35         },
 36 };
 37 
 38 static 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 
317 static struct test *tests[] = {
318         generic_tests,
319         arch_tests,
320 };
321 
322 static 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 
346 static 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 
402 static 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 
436 static 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 
460 static 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 
482 static 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 
513 struct shell_test {
514         const char *dir;
515         const char *file;
516 };
517 
518 static 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 
533 static 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 
570 static 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 
645 static 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 
676 static 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 
706 int 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp