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

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

Version: ~ [ linux-6.1-rc7 ] ~ [ linux-6.0.10 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.80 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.156 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.225 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.267 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.300 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.334 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ 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.9 ] ~ [ 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 #include <linux/zalloc.h>
 30 
 31 static bool dont_fork;
 32 
 33 struct test_suite *__weak arch_tests[] = {
 34         NULL,
 35 };
 36 
 37 static struct test_suite *generic_tests[] = {
 38         &suite__vmlinux_matches_kallsyms,
 39         &suite__openat_syscall_event,
 40         &suite__openat_syscall_event_on_all_cpus,
 41         &suite__basic_mmap,
 42         &suite__mem,
 43         &suite__parse_events,
 44         &suite__expr,
 45         &suite__PERF_RECORD,
 46         &suite__pmu,
 47         &suite__pmu_events,
 48         &suite__dso_data,
 49         &suite__dso_data_cache,
 50         &suite__dso_data_reopen,
 51         &suite__perf_evsel__roundtrip_name_test,
 52         &suite__perf_evsel__tp_sched_test,
 53         &suite__syscall_openat_tp_fields,
 54         &suite__attr,
 55         &suite__hists_link,
 56         &suite__python_use,
 57         &suite__bp_signal,
 58         &suite__bp_signal_overflow,
 59         &suite__bp_accounting,
 60         &suite__wp,
 61         &suite__task_exit,
 62         &suite__sw_clock_freq,
 63         &suite__code_reading,
 64         &suite__sample_parsing,
 65         &suite__keep_tracking,
 66         &suite__parse_no_sample_id_all,
 67         &suite__hists_filter,
 68         &suite__mmap_thread_lookup,
 69         &suite__thread_maps_share,
 70         &suite__hists_output,
 71         &suite__hists_cumulate,
 72         &suite__switch_tracking,
 73         &suite__fdarray__filter,
 74         &suite__fdarray__add,
 75         &suite__kmod_path__parse,
 76         &suite__thread_map,
 77         &suite__llvm,
 78         &suite__session_topology,
 79         &suite__bpf,
 80         &suite__thread_map_synthesize,
 81         &suite__thread_map_remove,
 82         &suite__cpu_map_synthesize,
 83         &suite__synthesize_stat_config,
 84         &suite__synthesize_stat,
 85         &suite__synthesize_stat_round,
 86         &suite__event_update,
 87         &suite__event_times,
 88         &suite__backward_ring_buffer,
 89         &suite__cpu_map_print,
 90         &suite__cpu_map_merge,
 91         &suite__sdt_event,
 92         &suite__is_printable_array,
 93         &suite__bitmap_print,
 94         &suite__perf_hooks,
 95         &suite__clang,
 96         &suite__unit_number__scnprint,
 97         &suite__mem2node,
 98         &suite__time_utils,
 99         &suite__jit_write_elf,
100         &suite__pfm,
101         &suite__api_io,
102         &suite__maps__merge_in,
103         &suite__demangle_java,
104         &suite__demangle_ocaml,
105         &suite__parse_metric,
106         &suite__pe_file_parsing,
107         &suite__expand_cgroup_events,
108         &suite__perf_time_to_tsc,
109         &suite__dlfilter,
110         NULL,
111 };
112 
113 static struct test_suite **tests[] = {
114         generic_tests,
115         arch_tests,
116 };
117 
118 static int num_subtests(const struct test_suite *t)
119 {
120         int num;
121 
122         if (!t->test_cases)
123                 return 0;
124 
125         num = 0;
126         while (t->test_cases[num].name)
127                 num++;
128 
129         return num;
130 }
131 
132 static bool has_subtests(const struct test_suite *t)
133 {
134         return num_subtests(t) > 1;
135 }
136 
137 static const char *skip_reason(const struct test_suite *t, int subtest)
138 {
139         if (t->test_cases && subtest >= 0)
140                 return t->test_cases[subtest].skip_reason;
141 
142         return NULL;
143 }
144 
145 static const char *test_description(const struct test_suite *t, int subtest)
146 {
147         if (t->test_cases && subtest >= 0)
148                 return t->test_cases[subtest].desc;
149 
150         return t->desc;
151 }
152 
153 static test_fnptr test_function(const struct test_suite *t, int subtest)
154 {
155         if (subtest <= 0)
156                 return t->test_cases[0].run_case;
157 
158         return t->test_cases[subtest].run_case;
159 }
160 
161 static bool perf_test__matches(const char *desc, int curr, int argc, const char *argv[])
162 {
163         int i;
164 
165         if (argc == 0)
166                 return true;
167 
168         for (i = 0; i < argc; ++i) {
169                 char *end;
170                 long nr = strtoul(argv[i], &end, 10);
171 
172                 if (*end == '\0') {
173                         if (nr == curr + 1)
174                                 return true;
175                         continue;
176                 }
177 
178                 if (strcasestr(desc, argv[i]))
179                         return true;
180         }
181 
182         return false;
183 }
184 
185 static int run_test(struct test_suite *test, int subtest)
186 {
187         int status, err = -1, child = dont_fork ? 0 : fork();
188         char sbuf[STRERR_BUFSIZE];
189 
190         if (child < 0) {
191                 pr_err("failed to fork test: %s\n",
192                         str_error_r(errno, sbuf, sizeof(sbuf)));
193                 return -1;
194         }
195 
196         if (!child) {
197                 if (!dont_fork) {
198                         pr_debug("test child forked, pid %d\n", getpid());
199 
200                         if (verbose <= 0) {
201                                 int nullfd = open("/dev/null", O_WRONLY);
202 
203                                 if (nullfd >= 0) {
204                                         close(STDERR_FILENO);
205                                         close(STDOUT_FILENO);
206 
207                                         dup2(nullfd, STDOUT_FILENO);
208                                         dup2(STDOUT_FILENO, STDERR_FILENO);
209                                         close(nullfd);
210                                 }
211                         } else {
212                                 signal(SIGSEGV, sighandler_dump_stack);
213                                 signal(SIGFPE, sighandler_dump_stack);
214                         }
215                 }
216 
217                 err = test_function(test, subtest)(test, subtest);
218                 if (!dont_fork)
219                         exit(err);
220         }
221 
222         if (!dont_fork) {
223                 wait(&status);
224 
225                 if (WIFEXITED(status)) {
226                         err = (signed char)WEXITSTATUS(status);
227                         pr_debug("test child finished with %d\n", err);
228                 } else if (WIFSIGNALED(status)) {
229                         err = -1;
230                         pr_debug("test child interrupted\n");
231                 }
232         }
233 
234         return err;
235 }
236 
237 #define for_each_test(j, k, t)                  \
238         for (j = 0; j < ARRAY_SIZE(tests); j++) \
239                 for (k = 0, t = tests[j][k]; tests[j][k]; k++, t = tests[j][k])
240 
241 static int test_and_print(struct test_suite *t, int subtest)
242 {
243         int err;
244 
245         pr_debug("\n--- start ---\n");
246         err = run_test(t, subtest);
247         pr_debug("---- end ----\n");
248 
249         if (!has_subtests(t))
250                 pr_debug("%s:", t->desc);
251         else
252                 pr_debug("%s subtest %d:", t->desc, subtest + 1);
253 
254         switch (err) {
255         case TEST_OK:
256                 pr_info(" Ok\n");
257                 break;
258         case TEST_SKIP: {
259                 const char *reason = skip_reason(t, subtest);
260 
261                 if (reason)
262                         color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (%s)\n", reason);
263                 else
264                         color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
265         }
266                 break;
267         case TEST_FAIL:
268         default:
269                 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
270                 break;
271         }
272 
273         return err;
274 }
275 
276 static const char *shell_test__description(char *description, size_t size,
277                                            const char *path, const char *name)
278 {
279         FILE *fp;
280         char filename[PATH_MAX];
281 
282         path__join(filename, sizeof(filename), path, name);
283         fp = fopen(filename, "r");
284         if (!fp)
285                 return NULL;
286 
287         /* Skip shebang */
288         while (fgetc(fp) != '\n');
289 
290         description = fgets(description, size, fp);
291         fclose(fp);
292 
293         return description ? strim(description + 1) : NULL;
294 }
295 
296 #define for_each_shell_test(entlist, nr, base, ent)                     \
297         for (int __i = 0; __i < nr && (ent = entlist[__i]); __i++)      \
298                 if (!is_directory(base, ent) && ent->d_name[0] != '.')
299 
300 static const char *shell_tests__dir(char *path, size_t size)
301 {
302         const char *devel_dirs[] = { "./tools/perf/tests", "./tests", };
303         char *exec_path;
304         unsigned int i;
305 
306         for (i = 0; i < ARRAY_SIZE(devel_dirs); ++i) {
307                 struct stat st;
308                 if (!lstat(devel_dirs[i], &st)) {
309                         scnprintf(path, size, "%s/shell", devel_dirs[i]);
310                         if (!lstat(devel_dirs[i], &st))
311                                 return path;
312                 }
313         }
314 
315         /* Then installed path. */
316         exec_path = get_argv_exec_path();
317         scnprintf(path, size, "%s/tests/shell", exec_path);
318         free(exec_path);
319         return path;
320 }
321 
322 static int shell_tests__max_desc_width(void)
323 {
324         struct dirent **entlist;
325         struct dirent *ent;
326         int n_dirs, e;
327         char path_dir[PATH_MAX];
328         const char *path = shell_tests__dir(path_dir, sizeof(path_dir));
329         int width = 0;
330 
331         if (path == NULL)
332                 return -1;
333 
334         n_dirs = scandir(path, &entlist, NULL, alphasort);
335         if (n_dirs == -1)
336                 return -1;
337 
338         for_each_shell_test(entlist, n_dirs, path, ent) {
339                 char bf[256];
340                 const char *desc = shell_test__description(bf, sizeof(bf), path, ent->d_name);
341 
342                 if (desc) {
343                         int len = strlen(desc);
344 
345                         if (width < len)
346                                 width = len;
347                 }
348         }
349 
350         for (e = 0; e < n_dirs; e++)
351                 zfree(&entlist[e]);
352         free(entlist);
353         return width;
354 }
355 
356 struct shell_test {
357         const char *dir;
358         const char *file;
359 };
360 
361 static int shell_test__run(struct test_suite *test, int subdir __maybe_unused)
362 {
363         int err;
364         char script[PATH_MAX];
365         struct shell_test *st = test->priv;
366 
367         path__join(script, sizeof(script) - 3, st->dir, st->file);
368 
369         if (verbose)
370                 strncat(script, " -v", sizeof(script) - strlen(script) - 1);
371 
372         err = system(script);
373         if (!err)
374                 return TEST_OK;
375 
376         return WEXITSTATUS(err) == 2 ? TEST_SKIP : TEST_FAIL;
377 }
378 
379 static int run_shell_tests(int argc, const char *argv[], int i, int width,
380                                 struct intlist *skiplist)
381 {
382         struct dirent **entlist;
383         struct dirent *ent;
384         int n_dirs, e;
385         char path_dir[PATH_MAX];
386         struct shell_test st = {
387                 .dir = shell_tests__dir(path_dir, sizeof(path_dir)),
388         };
389 
390         if (st.dir == NULL)
391                 return -1;
392 
393         n_dirs = scandir(st.dir, &entlist, NULL, alphasort);
394         if (n_dirs == -1) {
395                 pr_err("failed to open shell test directory: %s\n",
396                         st.dir);
397                 return -1;
398         }
399 
400         for_each_shell_test(entlist, n_dirs, st.dir, ent) {
401                 int curr = i++;
402                 char desc[256];
403                 struct test_case test_cases[] = {
404                         {
405                                 .desc = shell_test__description(desc,
406                                                                 sizeof(desc),
407                                                                 st.dir,
408                                                                 ent->d_name),
409                                 .run_case = shell_test__run,
410                         },
411                         { .name = NULL, }
412                 };
413                 struct test_suite test_suite = {
414                         .desc = test_cases[0].desc,
415                         .test_cases = test_cases,
416                         .priv = &st,
417                 };
418 
419                 if (!perf_test__matches(test_suite.desc, curr, argc, argv))
420                         continue;
421 
422                 st.file = ent->d_name;
423                 pr_info("%2d: %-*s:", i, width, test_suite.desc);
424 
425                 if (intlist__find(skiplist, i)) {
426                         color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
427                         continue;
428                 }
429 
430                 test_and_print(&test_suite, 0);
431         }
432 
433         for (e = 0; e < n_dirs; e++)
434                 zfree(&entlist[e]);
435         free(entlist);
436         return 0;
437 }
438 
439 static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
440 {
441         struct test_suite *t;
442         unsigned int j, k;
443         int i = 0;
444         int width = shell_tests__max_desc_width();
445 
446         for_each_test(j, k, t) {
447                 int len = strlen(test_description(t, -1));
448 
449                 if (width < len)
450                         width = len;
451         }
452 
453         for_each_test(j, k, t) {
454                 int curr = i++;
455                 int subi;
456 
457                 if (!perf_test__matches(test_description(t, -1), curr, argc, argv)) {
458                         bool skip = true;
459                         int subn;
460 
461                         subn = num_subtests(t);
462 
463                         for (subi = 0; subi < subn; subi++) {
464                                 if (perf_test__matches(test_description(t, subi),
465                                                         curr, argc, argv))
466                                         skip = false;
467                         }
468 
469                         if (skip)
470                                 continue;
471                 }
472 
473                 pr_info("%2d: %-*s:", i, width, test_description(t, -1));
474 
475                 if (intlist__find(skiplist, i)) {
476                         color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
477                         continue;
478                 }
479 
480                 if (!has_subtests(t)) {
481                         test_and_print(t, -1);
482                 } else {
483                         int subn = num_subtests(t);
484                         /*
485                          * minus 2 to align with normal testcases.
486                          * For subtest we print additional '.x' in number.
487                          * for example:
488                          *
489                          * 35: Test LLVM searching and compiling                        :
490                          * 35.1: Basic BPF llvm compiling test                          : Ok
491                          */
492                         int subw = width > 2 ? width - 2 : width;
493 
494                         if (subn <= 0) {
495                                 color_fprintf(stderr, PERF_COLOR_YELLOW,
496                                               " Skip (not compiled in)\n");
497                                 continue;
498                         }
499                         pr_info("\n");
500 
501                         for (subi = 0; subi < subn; subi++) {
502                                 int len = strlen(test_description(t, subi));
503 
504                                 if (subw < len)
505                                         subw = len;
506                         }
507 
508                         for (subi = 0; subi < subn; subi++) {
509                                 if (!perf_test__matches(test_description(t, subi),
510                                                         curr, argc, argv))
511                                         continue;
512 
513                                 pr_info("%2d.%1d: %-*s:", i, subi + 1, subw,
514                                         test_description(t, subi));
515                                 test_and_print(t, subi);
516                         }
517                 }
518         }
519 
520         return run_shell_tests(argc, argv, i, width, skiplist);
521 }
522 
523 static int perf_test__list_shell(int argc, const char **argv, int i)
524 {
525         struct dirent **entlist;
526         struct dirent *ent;
527         int n_dirs, e;
528         char path_dir[PATH_MAX];
529         const char *path = shell_tests__dir(path_dir, sizeof(path_dir));
530 
531         if (path == NULL)
532                 return -1;
533 
534         n_dirs = scandir(path, &entlist, NULL, alphasort);
535         if (n_dirs == -1)
536                 return -1;
537 
538         for_each_shell_test(entlist, n_dirs, path, ent) {
539                 int curr = i++;
540                 char bf[256];
541                 struct test_suite t = {
542                         .desc = shell_test__description(bf, sizeof(bf), path, ent->d_name),
543                 };
544 
545                 if (!perf_test__matches(t.desc, curr, argc, argv))
546                         continue;
547 
548                 pr_info("%2d: %s\n", i, t.desc);
549 
550         }
551 
552         for (e = 0; e < n_dirs; e++)
553                 zfree(&entlist[e]);
554         free(entlist);
555         return 0;
556 }
557 
558 static int perf_test__list(int argc, const char **argv)
559 {
560         unsigned int j, k;
561         struct test_suite *t;
562         int i = 0;
563 
564         for_each_test(j, k, t) {
565                 int curr = i++;
566 
567                 if (!perf_test__matches(test_description(t, -1), curr, argc, argv))
568                         continue;
569 
570                 pr_info("%2d: %s\n", i, test_description(t, -1));
571 
572                 if (has_subtests(t)) {
573                         int subn = num_subtests(t);
574                         int subi;
575 
576                         for (subi = 0; subi < subn; subi++)
577                                 pr_info("%2d:%1d: %s\n", i, subi + 1,
578                                         test_description(t, subi));
579                 }
580         }
581 
582         perf_test__list_shell(argc, argv, i);
583 
584         return 0;
585 }
586 
587 int cmd_test(int argc, const char **argv)
588 {
589         const char *test_usage[] = {
590         "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
591         NULL,
592         };
593         const char *skip = NULL;
594         const struct option test_options[] = {
595         OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
596         OPT_INCR('v', "verbose", &verbose,
597                     "be more verbose (show symbol address, etc)"),
598         OPT_BOOLEAN('F', "dont-fork", &dont_fork,
599                     "Do not fork for testcase"),
600         OPT_END()
601         };
602         const char * const test_subcommands[] = { "list", NULL };
603         struct intlist *skiplist = NULL;
604         int ret = hists__init();
605 
606         if (ret < 0)
607                 return ret;
608 
609         argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0);
610         if (argc >= 1 && !strcmp(argv[0], "list"))
611                 return perf_test__list(argc - 1, argv + 1);
612 
613         symbol_conf.priv_size = sizeof(int);
614         symbol_conf.sort_by_name = true;
615         symbol_conf.try_vmlinux_path = true;
616 
617         if (symbol__init(NULL) < 0)
618                 return -1;
619 
620         if (skip != NULL)
621                 skiplist = intlist__new(skip);
622         /*
623          * Tests that create BPF maps, for instance, need more than the 64K
624          * default:
625          */
626         rlimit__bump_memlock();
627 
628         return __cmd_test(argc, argv, skiplist);
629 }
630 

~ [ 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