builtin-test.c 14.7 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
2 3 4 5 6
/*
 * builtin-test.c
 *
 * Builtin regression testing command: ever growing number of sanity tests
 */
7
#include <fcntl.h>
8
#include <errno.h>
9 10
#include <unistd.h>
#include <string.h>
11
#include <stdlib.h>
12 13
#include <sys/types.h>
#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 21
#include "debug.h"
#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

J
Jiri Olsa 已提交
30 31
static bool dont_fork;

M
Matt Fleming 已提交
32 33 34 35 36 37 38
struct test __weak arch_tests[] = {
	{
		.func = NULL,
	},
};

static struct test generic_tests[] = {
39 40 41 42
	{
		.desc = "vmlinux symtab matches kallsyms",
		.func = test__vmlinux_matches_kallsyms,
	},
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 54
		.func = test__basic_mmap,
	},
55 56 57 58
	{
		.desc = "Test data source output",
		.func = test__mem,
	},
59
	{
60
		.desc = "Parse event definition strings",
61
		.func = test__parse_events,
62
	},
63 64 65 66
	{
		.desc = "Simple expression parser",
		.func = test__expr,
	},
67
	{
68
		.desc = "PERF_RECORD_* events & perf_sample fields",
69 70
		.func = test__PERF_RECORD,
	},
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 82
		.func = test__dso_data_cache,
	},
83
	{
84
		.desc = "DSO data reopen",
85 86
		.func = test__dso_data_reopen,
	},
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 106
		.func = test__hists_link,
	},
107
	{
108
		.desc = "'import perf' in python",
109 110
		.func = test__python_use,
	},
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 123
	{
		.desc = "Breakpoint accounting",
		.func = test__bp_accounting,
124
		.is_supported = test__bp_account_is_supported,
125
	},
R
Ravi Bangoria 已提交
126 127 128
	{
		.desc = "Watchpoint",
		.func = test__wp,
129
		.is_supported = test__wp_is_supported,
R
Ravi Bangoria 已提交
130 131 132 133 134 135
		.subtest = {
			.skip_if_fail	= false,
			.get_nr		= test__wp_subtest_get_nr,
			.get_desc	= test__wp_subtest_get_desc,
		},
	},
136
	{
137
		.desc = "Number of exit events of a simple workload",
138 139
		.func = test__task_exit,
	},
140
	{
141
		.desc = "Software clock events period values",
142 143
		.func = test__sw_clock_freq,
	},
144
	{
145
		.desc = "Object code reading",
146 147
		.func = test__code_reading,
	},
148
	{
149
		.desc = "Sample parsing",
150 151
		.func = test__sample_parsing,
	},
152
	{
153
		.desc = "Use a dummy software event to keep tracking",
154 155
		.func = test__keep_tracking,
	},
156
	{
157
		.desc = "Parse with no sample_id_all bit set",
158 159
		.func = test__parse_no_sample_id_all,
	},
160
	{
161
		.desc = "Filter hist entries",
162 163
		.func = test__hists_filter,
	},
164
	{
165
		.desc = "Lookup mmap thread",
166 167
		.func = test__mmap_thread_lookup,
	},
168
	{
169
		.desc = "Share thread mg",
170 171
		.func = test__thread_mg_share,
	},
172
	{
173
		.desc = "Sort output of hist entries",
174 175
		.func = test__hists_output,
	},
176
	{
177
		.desc = "Cumulate child hist entries",
178 179
		.func = test__hists_cumulate,
	},
180
	{
181
		.desc = "Track with sched_switch",
182 183
		.func = test__switch_tracking,
	},
184
	{
185 186
		.desc = "Filter fds with revents mask in a fdarray",
		.func = test__fdarray__filter,
187
	},
188
	{
189 190
		.desc = "Add fd to a fdarray, making it autogrow",
		.func = test__fdarray__add,
191
	},
192
	{
193
		.desc = "kmod_path__parse",
194 195
		.func = test__kmod_path__parse,
	},
196
	{
197
		.desc = "Thread map",
198 199
		.func = test__thread_map,
	},
200
	{
201
		.desc = "LLVM search and compile",
202
		.func = test__llvm,
203 204 205 206 207
		.subtest = {
			.skip_if_fail	= true,
			.get_nr		= test__llvm_subtest_get_nr,
			.get_desc	= test__llvm_subtest_get_desc,
		},
208
	},
209
	{
210
		.desc = "Session topology",
211
		.func = test__session_topology,
212
	},
W
Wang Nan 已提交
213
	{
214
		.desc = "BPF filter",
W
Wang Nan 已提交
215
		.func = test__bpf,
216 217 218 219 220
		.subtest = {
			.skip_if_fail	= true,
			.get_nr		= test__bpf_subtest_get_nr,
			.get_desc	= test__bpf_subtest_get_desc,
		},
W
Wang Nan 已提交
221
	},
222
	{
223
		.desc = "Synthesize thread map",
224 225
		.func = test__thread_map_synthesize,
	},
226 227 228 229
	{
		.desc = "Remove thread map",
		.func = test__thread_map_remove,
	},
230
	{
231
		.desc = "Synthesize cpu map",
232 233
		.func = test__cpu_map_synthesize,
	},
234
	{
235
		.desc = "Synthesize stat config",
236 237
		.func = test__synthesize_stat_config,
	},
238
	{
239
		.desc = "Synthesize stat",
240 241
		.func = test__synthesize_stat,
	},
242
	{
243
		.desc = "Synthesize stat round",
244 245
		.func = test__synthesize_stat_round,
	},
246
	{
247
		.desc = "Synthesize attr update",
248 249
		.func = test__event_update,
	},
250
	{
251
		.desc = "Event times",
252 253
		.func = test__event_times,
	},
254
	{
255
		.desc = "Read backward ring buffer",
256 257
		.func = test__backward_ring_buffer,
	},
258
	{
259
		.desc = "Print cpu map",
260 261
		.func = test__cpu_map_print,
	},
262
	{
263
		.desc = "Probe SDT events",
264 265
		.func = test__sdt_event,
	},
266
	{
267
		.desc = "is_printable_array",
268 269
		.func = test__is_printable_array,
	},
270
	{
271
		.desc = "Print bitmap",
272 273
		.func = test__bitmap_print,
	},
W
Wang Nan 已提交
274
	{
275
		.desc = "perf hooks",
W
Wang Nan 已提交
276 277
		.func = test__perf_hooks,
	},
278 279 280 281 282 283 284 285 286
	{
		.desc = "builtin clang support",
		.func = test__clang,
		.subtest = {
			.skip_if_fail	= true,
			.get_nr		= test__clang_subtest_get_nr,
			.get_desc	= test__clang_subtest_get_desc,
		}
	},
287 288 289 290
	{
		.desc = "unit_number__scnprintf",
		.func = test__unit_number__scnprint,
	},
J
Jiri Olsa 已提交
291 292 293 294
	{
		.desc = "mem2node",
		.func = test__mem2node,
	},
295 296 297 298
	{
		.desc = "time utils",
		.func = test__time_utils,
	},
299 300 301 302
	{
		.desc = "map_groups__merge_in",
		.func = test__map_groups__merge_in,
	},
303 304 305 306 307
	{
		.func = NULL,
	},
};

M
Matt Fleming 已提交
308 309 310 311 312
static struct test *tests[] = {
	generic_tests,
	arch_tests,
};

313
static bool perf_test__matches(struct test *test, int curr, int argc, const char *argv[])
314
{
315 316 317 318 319 320 321 322 323 324 325 326 327 328
	int i;

	if (argc == 0)
		return true;

	for (i = 0; i < argc; ++i) {
		char *end;
		long nr = strtoul(argv[i], &end, 10);

		if (*end == '\0') {
			if (nr == curr + 1)
				return true;
			continue;
		}
329

330
		if (strcasestr(test->desc, argv[i]))
331 332 333 334 335 336
			return true;
	}

	return false;
}

337
static int run_test(struct test *test, int subtest)
338
{
J
Jiri Olsa 已提交
339
	int status, err = -1, child = dont_fork ? 0 : fork();
340
	char sbuf[STRERR_BUFSIZE];
341 342

	if (child < 0) {
343
		pr_err("failed to fork test: %s\n",
344
			str_error_r(errno, sbuf, sizeof(sbuf)));
345 346 347 348
		return -1;
	}

	if (!child) {
J
Jiri Olsa 已提交
349 350 351
		if (!dont_fork) {
			pr_debug("test child forked, pid %d\n", getpid());

352
			if (verbose <= 0) {
J
Jiri Olsa 已提交
353 354 355 356 357 358 359 360 361 362 363 364 365
				int nullfd = open("/dev/null", O_WRONLY);

				if (nullfd >= 0) {
					close(STDERR_FILENO);
					close(STDOUT_FILENO);

					dup2(nullfd, STDOUT_FILENO);
					dup2(STDOUT_FILENO, STDERR_FILENO);
					close(nullfd);
				}
			} else {
				signal(SIGSEGV, sighandler_dump_stack);
				signal(SIGFPE, sighandler_dump_stack);
366 367 368
			}
		}

369
		err = test->func(test, subtest);
J
Jiri Olsa 已提交
370 371
		if (!dont_fork)
			exit(err);
372 373
	}

J
Jiri Olsa 已提交
374 375
	if (!dont_fork) {
		wait(&status);
376

J
Jiri Olsa 已提交
377 378 379 380 381 382 383
		if (WIFEXITED(status)) {
			err = (signed char)WEXITSTATUS(status);
			pr_debug("test child finished with %d\n", err);
		} else if (WIFSIGNALED(status)) {
			err = -1;
			pr_debug("test child interrupted\n");
		}
384 385 386 387 388
	}

	return err;
}

M
Matt Fleming 已提交
389 390 391
#define for_each_test(j, t)	 				\
	for (j = 0; j < ARRAY_SIZE(tests); j++)	\
		for (t = &tests[j][0]; t->func; t++)
392

393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
static int test_and_print(struct test *t, bool force_skip, int subtest)
{
	int err;

	if (!force_skip) {
		pr_debug("\n--- start ---\n");
		err = run_test(t, subtest);
		pr_debug("---- end ----\n");
	} else {
		pr_debug("\n--- force skipped ---\n");
		err = TEST_SKIP;
	}

	if (!t->subtest.get_nr)
		pr_debug("%s:", t->desc);
	else
409
		pr_debug("%s subtest %d:", t->desc, subtest + 1);
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426

	switch (err) {
	case TEST_OK:
		pr_info(" Ok\n");
		break;
	case TEST_SKIP:
		color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
		break;
	case TEST_FAIL:
	default:
		color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
		break;
	}

	return err;
}

427 428 429 430 431 432 433 434 435 436 437
static const char *shell_test__description(char *description, size_t size,
					   const char *path, const char *name)
{
	FILE *fp;
	char filename[PATH_MAX];

	path__join(filename, sizeof(filename), path, name);
	fp = fopen(filename, "r");
	if (!fp)
		return NULL;

438 439 440
	/* Skip shebang */
	while (fgetc(fp) != '\n');

441 442 443
	description = fgets(description, size, fp);
	fclose(fp);

444
	return description ? strim(description + 1) : NULL;
445 446
}

447
#define for_each_shell_test(dir, base, ent)	\
448
	while ((ent = readdir(dir)) != NULL)	\
449
		if (!is_directory(base, ent) && ent->d_name[0] != '.')
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487

static const char *shell_tests__dir(char *path, size_t size)
{
	const char *devel_dirs[] = { "./tools/perf/tests", "./tests", };
        char *exec_path;
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(devel_dirs); ++i) {
		struct stat st;
		if (!lstat(devel_dirs[i], &st)) {
			scnprintf(path, size, "%s/shell", devel_dirs[i]);
			if (!lstat(devel_dirs[i], &st))
				return path;
		}
	}

        /* Then installed path. */
        exec_path = get_argv_exec_path();
        scnprintf(path, size, "%s/tests/shell", exec_path);
	free(exec_path);
	return path;
}

static int shell_tests__max_desc_width(void)
{
	DIR *dir;
	struct dirent *ent;
	char path_dir[PATH_MAX];
	const char *path = shell_tests__dir(path_dir, sizeof(path_dir));
	int width = 0;

	if (path == NULL)
		return -1;

	dir = opendir(path);
	if (!dir)
		return -1;

488
	for_each_shell_test(dir, path, ent) {
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
		char bf[256];
		const char *desc = shell_test__description(bf, sizeof(bf), path, ent->d_name);

		if (desc) {
			int len = strlen(desc);

			if (width < len)
				width = len;
		}
	}

	closedir(dir);
	return width;
}

struct shell_test {
	const char *dir;
	const char *file;
};

static int shell_test__run(struct test *test, int subdir __maybe_unused)
{
	int err;
	char script[PATH_MAX];
	struct shell_test *st = test->priv;

	path__join(script, sizeof(script), st->dir, st->file);

	err = system(script);
	if (!err)
		return TEST_OK;

	return WEXITSTATUS(err) == 2 ? TEST_SKIP : TEST_FAIL;
}

static int run_shell_tests(int argc, const char *argv[], int i, int width)
{
	DIR *dir;
	struct dirent *ent;
	char path_dir[PATH_MAX];
	struct shell_test st = {
		.dir = shell_tests__dir(path_dir, sizeof(path_dir)),
	};

	if (st.dir == NULL)
		return -1;

	dir = opendir(st.dir);
	if (!dir)
		return -1;

540
	for_each_shell_test(dir, st.dir, ent) {
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
		int curr = i++;
		char desc[256];
		struct test test = {
			.desc = shell_test__description(desc, sizeof(desc), st.dir, ent->d_name),
			.func = shell_test__run,
			.priv = &st,
		};

		if (!perf_test__matches(&test, curr, argc, argv))
			continue;

		st.file = ent->d_name;
		pr_info("%2d: %-*s:", i, width, test.desc);
		test_and_print(&test, false, -1);
	}

	closedir(dir);
	return 0;
}

561
static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
562
{
563
	struct test *t;
M
Matt Fleming 已提交
564
	unsigned int j;
565
	int i = 0;
566
	int width = shell_tests__max_desc_width();
567

M
Matt Fleming 已提交
568
	for_each_test(j, t) {
569
		int len = strlen(t->desc);
570 571 572 573

		if (width < len)
			width = len;
	}
574

M
Matt Fleming 已提交
575
	for_each_test(j, t) {
576 577
		int curr = i++, err;

578
		if (!perf_test__matches(t, curr, argc, argv))
579 580
			continue;

581 582 583 584 585
		if (t->is_supported && !t->is_supported()) {
			pr_debug("%2d: %-*s: Disabled\n", i, width, t->desc);
			continue;
		}

586
		pr_info("%2d: %-*s:", i, width, t->desc);
587 588 589 590 591 592

		if (intlist__find(skiplist, i)) {
			color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
			continue;
		}

593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
		if (!t->subtest.get_nr) {
			test_and_print(t, false, -1);
		} else {
			int subn = t->subtest.get_nr();
			/*
			 * minus 2 to align with normal testcases.
			 * For subtest we print additional '.x' in number.
			 * for example:
			 *
			 * 35: Test LLVM searching and compiling                        :
			 * 35.1: Basic BPF llvm compiling test                          : Ok
			 */
			int subw = width > 2 ? width - 2 : width;
			bool skip = false;
			int subi;

			if (subn <= 0) {
				color_fprintf(stderr, PERF_COLOR_YELLOW,
					      " Skip (not compiled in)\n");
				continue;
			}
			pr_info("\n");

			for (subi = 0; subi < subn; subi++) {
				int len = strlen(t->subtest.get_desc(subi));

				if (subw < len)
					subw = len;
			}

			for (subi = 0; subi < subn; subi++) {
				pr_info("%2d.%1d: %-*s:", i, subi + 1, subw,
					t->subtest.get_desc(subi));
626
				err = test_and_print(t, skip, subi);
627 628 629
				if (err != TEST_OK && t->subtest.skip_if_fail)
					skip = true;
			}
630
		}
631 632
	}

633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
	return run_shell_tests(argc, argv, i, width);
}

static int perf_test__list_shell(int argc, const char **argv, int i)
{
	DIR *dir;
	struct dirent *ent;
	char path_dir[PATH_MAX];
	const char *path = shell_tests__dir(path_dir, sizeof(path_dir));

	if (path == NULL)
		return -1;

	dir = opendir(path);
	if (!dir)
		return -1;

650
	for_each_shell_test(dir, path, ent) {
651
		int curr = i++;
652
		char bf[256];
653 654 655
		struct test t = {
			.desc = shell_test__description(bf, sizeof(bf), path, ent->d_name),
		};
656

657
		if (!perf_test__matches(&t, curr, argc, argv))
658 659
			continue;

660
		pr_info("%2d: %s\n", i, t.desc);
661 662 663
	}

	closedir(dir);
664 665 666
	return 0;
}

667 668
static int perf_test__list(int argc, const char **argv)
{
M
Matt Fleming 已提交
669
	unsigned int j;
670
	struct test *t;
671 672
	int i = 0;

M
Matt Fleming 已提交
673
	for_each_test(j, t) {
674
		int curr = i++;
675

676 677
		if (!perf_test__matches(t, curr, argc, argv) ||
		    (t->is_supported && !t->is_supported()))
678 679
			continue;

680
		pr_info("%2d: %s\n", i, t->desc);
681 682 683 684 685 686 687 688 689

		if (t->subtest.get_nr) {
			int subn = t->subtest.get_nr();
			int subi;

			for (subi = 0; subi < subn; subi++)
				pr_info("%2d:%1d: %s\n", i, subi + 1,
					t->subtest.get_desc(subi));
		}
690 691
	}

692 693
	perf_test__list_shell(argc, argv, i);

694 695
	return 0;
}
696

697
int cmd_test(int argc, const char **argv)
698
{
699
	const char *test_usage[] = {
700 701 702
	"perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
	NULL,
	};
703
	const char *skip = NULL;
704
	const struct option test_options[] = {
705
	OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
706
	OPT_INCR('v', "verbose", &verbose,
707
		    "be more verbose (show symbol address, etc)"),
J
Jiri Olsa 已提交
708 709
	OPT_BOOLEAN('F', "dont-fork", &dont_fork,
		    "Do not fork for testcase"),
710
	OPT_END()
711
	};
712
	const char * const test_subcommands[] = { "list", NULL };
713
	struct intlist *skiplist = NULL;
714 715 716 717
        int ret = hists__init();

        if (ret < 0)
                return ret;
718

719
	argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0);
720
	if (argc >= 1 && !strcmp(argv[0], "list"))
721
		return perf_test__list(argc - 1, argv + 1);
722 723 724 725 726

	symbol_conf.priv_size = sizeof(int);
	symbol_conf.sort_by_name = true;
	symbol_conf.try_vmlinux_path = true;

727
	if (symbol__init(NULL) < 0)
728 729
		return -1;

730 731
	if (skip != NULL)
		skiplist = intlist__new(skip);
732 733 734 735 736
	/*
	 * Tests that create BPF maps, for instance, need more than the 64K
	 * default:
	 */
	rlimit__bump_memlock();
737 738

	return __cmd_test(argc, argv, skiplist);
739
}