xref: /openbmc/linux/tools/perf/tests/builtin-test.c (revision f94059f8)
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 	&suite__sigtrap,
111 	NULL,
112 };
113 
114 static struct test_suite **tests[] = {
115 	generic_tests,
116 	arch_tests,
117 };
118 
119 static int num_subtests(const struct test_suite *t)
120 {
121 	int num;
122 
123 	if (!t->test_cases)
124 		return 0;
125 
126 	num = 0;
127 	while (t->test_cases[num].name)
128 		num++;
129 
130 	return num;
131 }
132 
133 static bool has_subtests(const struct test_suite *t)
134 {
135 	return num_subtests(t) > 1;
136 }
137 
138 static const char *skip_reason(const struct test_suite *t, int subtest)
139 {
140 	if (!t->test_cases)
141 		return NULL;
142 
143 	return t->test_cases[subtest >= 0 ? subtest : 0].skip_reason;
144 }
145 
146 static const char *test_description(const struct test_suite *t, int subtest)
147 {
148 	if (t->test_cases && subtest >= 0)
149 		return t->test_cases[subtest].desc;
150 
151 	return t->desc;
152 }
153 
154 static test_fnptr test_function(const struct test_suite *t, int subtest)
155 {
156 	if (subtest <= 0)
157 		return t->test_cases[0].run_case;
158 
159 	return t->test_cases[subtest].run_case;
160 }
161 
162 static bool perf_test__matches(const char *desc, int curr, int argc, const char *argv[])
163 {
164 	int i;
165 
166 	if (argc == 0)
167 		return true;
168 
169 	for (i = 0; i < argc; ++i) {
170 		char *end;
171 		long nr = strtoul(argv[i], &end, 10);
172 
173 		if (*end == '\0') {
174 			if (nr == curr + 1)
175 				return true;
176 			continue;
177 		}
178 
179 		if (strcasestr(desc, argv[i]))
180 			return true;
181 	}
182 
183 	return false;
184 }
185 
186 static int run_test(struct test_suite *test, int subtest)
187 {
188 	int status, err = -1, child = dont_fork ? 0 : fork();
189 	char sbuf[STRERR_BUFSIZE];
190 
191 	if (child < 0) {
192 		pr_err("failed to fork test: %s\n",
193 			str_error_r(errno, sbuf, sizeof(sbuf)));
194 		return -1;
195 	}
196 
197 	if (!child) {
198 		if (!dont_fork) {
199 			pr_debug("test child forked, pid %d\n", getpid());
200 
201 			if (verbose <= 0) {
202 				int nullfd = open("/dev/null", O_WRONLY);
203 
204 				if (nullfd >= 0) {
205 					close(STDERR_FILENO);
206 					close(STDOUT_FILENO);
207 
208 					dup2(nullfd, STDOUT_FILENO);
209 					dup2(STDOUT_FILENO, STDERR_FILENO);
210 					close(nullfd);
211 				}
212 			} else {
213 				signal(SIGSEGV, sighandler_dump_stack);
214 				signal(SIGFPE, sighandler_dump_stack);
215 			}
216 		}
217 
218 		err = test_function(test, subtest)(test, subtest);
219 		if (!dont_fork)
220 			exit(err);
221 	}
222 
223 	if (!dont_fork) {
224 		wait(&status);
225 
226 		if (WIFEXITED(status)) {
227 			err = (signed char)WEXITSTATUS(status);
228 			pr_debug("test child finished with %d\n", err);
229 		} else if (WIFSIGNALED(status)) {
230 			err = -1;
231 			pr_debug("test child interrupted\n");
232 		}
233 	}
234 
235 	return err;
236 }
237 
238 #define for_each_test(j, k, t)			\
239 	for (j = 0; j < ARRAY_SIZE(tests); j++)	\
240 		for (k = 0, t = tests[j][k]; tests[j][k]; k++, t = tests[j][k])
241 
242 static int test_and_print(struct test_suite *t, int subtest)
243 {
244 	int err;
245 
246 	pr_debug("\n--- start ---\n");
247 	err = run_test(t, subtest);
248 	pr_debug("---- end ----\n");
249 
250 	if (!has_subtests(t))
251 		pr_debug("%s:", t->desc);
252 	else
253 		pr_debug("%s subtest %d:", t->desc, subtest + 1);
254 
255 	switch (err) {
256 	case TEST_OK:
257 		pr_info(" Ok\n");
258 		break;
259 	case TEST_SKIP: {
260 		const char *reason = skip_reason(t, subtest);
261 
262 		if (reason)
263 			color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (%s)\n", reason);
264 		else
265 			color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
266 	}
267 		break;
268 	case TEST_FAIL:
269 	default:
270 		color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
271 		break;
272 	}
273 
274 	return err;
275 }
276 
277 static const char *shell_test__description(char *description, size_t size,
278 					   const char *path, const char *name)
279 {
280 	FILE *fp;
281 	char filename[PATH_MAX];
282 	int ch;
283 
284 	path__join(filename, sizeof(filename), path, name);
285 	fp = fopen(filename, "r");
286 	if (!fp)
287 		return NULL;
288 
289 	/* Skip shebang */
290 	do {
291 		ch = fgetc(fp);
292 	} while (ch != EOF && ch != '\n');
293 
294 	description = fgets(description, size, fp);
295 	fclose(fp);
296 
297 	return description ? strim(description + 1) : NULL;
298 }
299 
300 #define for_each_shell_test(entlist, nr, base, ent)	                \
301 	for (int __i = 0; __i < nr && (ent = entlist[__i]); __i++)	\
302 		if (!is_directory(base, ent) && \
303 			is_executable_file(base, ent) && \
304 			ent->d_name[0] != '.')
305 
306 static const char *shell_tests__dir(char *path, size_t size)
307 {
308 	const char *devel_dirs[] = { "./tools/perf/tests", "./tests", };
309         char *exec_path;
310 	unsigned int i;
311 
312 	for (i = 0; i < ARRAY_SIZE(devel_dirs); ++i) {
313 		struct stat st;
314 		if (!lstat(devel_dirs[i], &st)) {
315 			scnprintf(path, size, "%s/shell", devel_dirs[i]);
316 			if (!lstat(devel_dirs[i], &st))
317 				return path;
318 		}
319 	}
320 
321         /* Then installed path. */
322         exec_path = get_argv_exec_path();
323         scnprintf(path, size, "%s/tests/shell", exec_path);
324 	free(exec_path);
325 	return path;
326 }
327 
328 static int shell_tests__max_desc_width(void)
329 {
330 	struct dirent **entlist;
331 	struct dirent *ent;
332 	int n_dirs, e;
333 	char path_dir[PATH_MAX];
334 	const char *path = shell_tests__dir(path_dir, sizeof(path_dir));
335 	int width = 0;
336 
337 	if (path == NULL)
338 		return -1;
339 
340 	n_dirs = scandir(path, &entlist, NULL, alphasort);
341 	if (n_dirs == -1)
342 		return -1;
343 
344 	for_each_shell_test(entlist, n_dirs, path, ent) {
345 		char bf[256];
346 		const char *desc = shell_test__description(bf, sizeof(bf), path, ent->d_name);
347 
348 		if (desc) {
349 			int len = strlen(desc);
350 
351 			if (width < len)
352 				width = len;
353 		}
354 	}
355 
356 	for (e = 0; e < n_dirs; e++)
357 		zfree(&entlist[e]);
358 	free(entlist);
359 	return width;
360 }
361 
362 struct shell_test {
363 	const char *dir;
364 	const char *file;
365 };
366 
367 static int shell_test__run(struct test_suite *test, int subdir __maybe_unused)
368 {
369 	int err;
370 	char script[PATH_MAX];
371 	struct shell_test *st = test->priv;
372 
373 	path__join(script, sizeof(script) - 3, st->dir, st->file);
374 
375 	if (verbose)
376 		strncat(script, " -v", sizeof(script) - strlen(script) - 1);
377 
378 	err = system(script);
379 	if (!err)
380 		return TEST_OK;
381 
382 	return WEXITSTATUS(err) == 2 ? TEST_SKIP : TEST_FAIL;
383 }
384 
385 static int run_shell_tests(int argc, const char *argv[], int i, int width,
386 				struct intlist *skiplist)
387 {
388 	struct dirent **entlist;
389 	struct dirent *ent;
390 	int n_dirs, e;
391 	char path_dir[PATH_MAX];
392 	struct shell_test st = {
393 		.dir = shell_tests__dir(path_dir, sizeof(path_dir)),
394 	};
395 
396 	if (st.dir == NULL)
397 		return -1;
398 
399 	n_dirs = scandir(st.dir, &entlist, NULL, alphasort);
400 	if (n_dirs == -1) {
401 		pr_err("failed to open shell test directory: %s\n",
402 			st.dir);
403 		return -1;
404 	}
405 
406 	for_each_shell_test(entlist, n_dirs, st.dir, ent) {
407 		int curr = i++;
408 		char desc[256];
409 		struct test_case test_cases[] = {
410 			{
411 				.desc = shell_test__description(desc,
412 								sizeof(desc),
413 								st.dir,
414 								ent->d_name),
415 				.run_case = shell_test__run,
416 			},
417 			{ .name = NULL, }
418 		};
419 		struct test_suite test_suite = {
420 			.desc = test_cases[0].desc,
421 			.test_cases = test_cases,
422 			.priv = &st,
423 		};
424 
425 		if (test_suite.desc == NULL ||
426 		    !perf_test__matches(test_suite.desc, curr, argc, argv))
427 			continue;
428 
429 		st.file = ent->d_name;
430 		pr_info("%3d: %-*s:", i, width, test_suite.desc);
431 
432 		if (intlist__find(skiplist, i)) {
433 			color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
434 			continue;
435 		}
436 
437 		test_and_print(&test_suite, 0);
438 	}
439 
440 	for (e = 0; e < n_dirs; e++)
441 		zfree(&entlist[e]);
442 	free(entlist);
443 	return 0;
444 }
445 
446 static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
447 {
448 	struct test_suite *t;
449 	unsigned int j, k;
450 	int i = 0;
451 	int width = shell_tests__max_desc_width();
452 
453 	for_each_test(j, k, t) {
454 		int len = strlen(test_description(t, -1));
455 
456 		if (width < len)
457 			width = len;
458 	}
459 
460 	for_each_test(j, k, t) {
461 		int curr = i++;
462 		int subi;
463 
464 		if (!perf_test__matches(test_description(t, -1), curr, argc, argv)) {
465 			bool skip = true;
466 			int subn;
467 
468 			subn = num_subtests(t);
469 
470 			for (subi = 0; subi < subn; subi++) {
471 				if (perf_test__matches(test_description(t, subi),
472 							curr, argc, argv))
473 					skip = false;
474 			}
475 
476 			if (skip)
477 				continue;
478 		}
479 
480 		pr_info("%3d: %-*s:", i, width, test_description(t, -1));
481 
482 		if (intlist__find(skiplist, i)) {
483 			color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
484 			continue;
485 		}
486 
487 		if (!has_subtests(t)) {
488 			test_and_print(t, -1);
489 		} else {
490 			int subn = num_subtests(t);
491 			/*
492 			 * minus 2 to align with normal testcases.
493 			 * For subtest we print additional '.x' in number.
494 			 * for example:
495 			 *
496 			 * 35: Test LLVM searching and compiling                        :
497 			 * 35.1: Basic BPF llvm compiling test                          : Ok
498 			 */
499 			int subw = width > 2 ? width - 2 : width;
500 
501 			if (subn <= 0) {
502 				color_fprintf(stderr, PERF_COLOR_YELLOW,
503 					      " Skip (not compiled in)\n");
504 				continue;
505 			}
506 			pr_info("\n");
507 
508 			for (subi = 0; subi < subn; subi++) {
509 				int len = strlen(test_description(t, subi));
510 
511 				if (subw < len)
512 					subw = len;
513 			}
514 
515 			for (subi = 0; subi < subn; subi++) {
516 				if (!perf_test__matches(test_description(t, subi),
517 							curr, argc, argv))
518 					continue;
519 
520 				pr_info("%3d.%1d: %-*s:", i, subi + 1, subw,
521 					test_description(t, subi));
522 				test_and_print(t, subi);
523 			}
524 		}
525 	}
526 
527 	return run_shell_tests(argc, argv, i, width, skiplist);
528 }
529 
530 static int perf_test__list_shell(int argc, const char **argv, int i)
531 {
532 	struct dirent **entlist;
533 	struct dirent *ent;
534 	int n_dirs, e;
535 	char path_dir[PATH_MAX];
536 	const char *path = shell_tests__dir(path_dir, sizeof(path_dir));
537 
538 	if (path == NULL)
539 		return -1;
540 
541 	n_dirs = scandir(path, &entlist, NULL, alphasort);
542 	if (n_dirs == -1)
543 		return -1;
544 
545 	for_each_shell_test(entlist, n_dirs, path, ent) {
546 		int curr = i++;
547 		char bf[256];
548 		struct test_suite t = {
549 			.desc = shell_test__description(bf, sizeof(bf), path, ent->d_name),
550 		};
551 
552 		if (!perf_test__matches(t.desc, curr, argc, argv))
553 			continue;
554 
555 		pr_info("%3d: %s\n", i, t.desc);
556 
557 	}
558 
559 	for (e = 0; e < n_dirs; e++)
560 		zfree(&entlist[e]);
561 	free(entlist);
562 	return 0;
563 }
564 
565 static int perf_test__list(int argc, const char **argv)
566 {
567 	unsigned int j, k;
568 	struct test_suite *t;
569 	int i = 0;
570 
571 	for_each_test(j, k, t) {
572 		int curr = i++;
573 
574 		if (!perf_test__matches(test_description(t, -1), curr, argc, argv))
575 			continue;
576 
577 		pr_info("%3d: %s\n", i, test_description(t, -1));
578 
579 		if (has_subtests(t)) {
580 			int subn = num_subtests(t);
581 			int subi;
582 
583 			for (subi = 0; subi < subn; subi++)
584 				pr_info("%3d:%1d: %s\n", i, subi + 1,
585 					test_description(t, subi));
586 		}
587 	}
588 
589 	perf_test__list_shell(argc, argv, i);
590 
591 	return 0;
592 }
593 
594 int cmd_test(int argc, const char **argv)
595 {
596 	const char *test_usage[] = {
597 	"perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
598 	NULL,
599 	};
600 	const char *skip = NULL;
601 	const struct option test_options[] = {
602 	OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
603 	OPT_INCR('v', "verbose", &verbose,
604 		    "be more verbose (show symbol address, etc)"),
605 	OPT_BOOLEAN('F', "dont-fork", &dont_fork,
606 		    "Do not fork for testcase"),
607 	OPT_END()
608 	};
609 	const char * const test_subcommands[] = { "list", NULL };
610 	struct intlist *skiplist = NULL;
611         int ret = hists__init();
612 
613         if (ret < 0)
614                 return ret;
615 
616 	/* Unbuffered output */
617 	setvbuf(stdout, NULL, _IONBF, 0);
618 
619 	argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0);
620 	if (argc >= 1 && !strcmp(argv[0], "list"))
621 		return perf_test__list(argc - 1, argv + 1);
622 
623 	symbol_conf.priv_size = sizeof(int);
624 	symbol_conf.sort_by_name = true;
625 	symbol_conf.try_vmlinux_path = true;
626 
627 	if (symbol__init(NULL) < 0)
628 		return -1;
629 
630 	if (skip != NULL)
631 		skiplist = intlist__new(skip);
632 	/*
633 	 * Tests that create BPF maps, for instance, need more than the 64K
634 	 * default:
635 	 */
636 	rlimit__bump_memlock();
637 
638 	return __cmd_test(argc, argv, skiplist);
639 }
640