1/*
2 * builtin-test.c
3 *
4 * Builtin regression testing command: ever growing number of sanity tests
5 */
6#include <unistd.h>
7#include <string.h>
8#include "builtin.h"
9#include "hist.h"
10#include "intlist.h"
11#include "tests.h"
12#include "debug.h"
13#include "color.h"
14#include "parse-options.h"
15#include "symbol.h"
16
17static struct test {
18	const char *desc;
19	int (*func)(void);
20} tests[] = {
21	{
22		.desc = "vmlinux symtab matches kallsyms",
23		.func = test__vmlinux_matches_kallsyms,
24	},
25	{
26		.desc = "detect open syscall event",
27		.func = test__open_syscall_event,
28	},
29	{
30		.desc = "detect open syscall event on all cpus",
31		.func = test__open_syscall_event_on_all_cpus,
32	},
33	{
34		.desc = "read samples using the mmap interface",
35		.func = test__basic_mmap,
36	},
37	{
38		.desc = "parse events tests",
39		.func = test__parse_events,
40	},
41#if defined(__x86_64__) || defined(__i386__)
42	{
43		.desc = "x86 rdpmc test",
44		.func = test__rdpmc,
45	},
46#endif
47	{
48		.desc = "Validate PERF_RECORD_* events & perf_sample fields",
49		.func = test__PERF_RECORD,
50	},
51	{
52		.desc = "Test perf pmu format parsing",
53		.func = test__pmu,
54	},
55	{
56		.desc = "Test dso data read",
57		.func = test__dso_data,
58	},
59	{
60		.desc = "Test dso data cache",
61		.func = test__dso_data_cache,
62	},
63	{
64		.desc = "Test dso data reopen",
65		.func = test__dso_data_reopen,
66	},
67	{
68		.desc = "roundtrip evsel->name check",
69		.func = test__perf_evsel__roundtrip_name_test,
70	},
71	{
72		.desc = "Check parsing of sched tracepoints fields",
73		.func = test__perf_evsel__tp_sched_test,
74	},
75	{
76		.desc = "Generate and check syscalls:sys_enter_open event fields",
77		.func = test__syscall_open_tp_fields,
78	},
79	{
80		.desc = "struct perf_event_attr setup",
81		.func = test__attr,
82	},
83	{
84		.desc = "Test matching and linking multiple hists",
85		.func = test__hists_link,
86	},
87	{
88		.desc = "Try 'import perf' in python, checking link problems",
89		.func = test__python_use,
90	},
91	{
92		.desc = "Test breakpoint overflow signal handler",
93		.func = test__bp_signal,
94	},
95	{
96		.desc = "Test breakpoint overflow sampling",
97		.func = test__bp_signal_overflow,
98	},
99	{
100		.desc = "Test number of exit event of a simple workload",
101		.func = test__task_exit,
102	},
103	{
104		.desc = "Test software clock events have valid period values",
105		.func = test__sw_clock_freq,
106	},
107#if defined(__x86_64__) || defined(__i386__)
108	{
109		.desc = "Test converting perf time to TSC",
110		.func = test__perf_time_to_tsc,
111	},
112#endif
113	{
114		.desc = "Test object code reading",
115		.func = test__code_reading,
116	},
117	{
118		.desc = "Test sample parsing",
119		.func = test__sample_parsing,
120	},
121	{
122		.desc = "Test using a dummy software event to keep tracking",
123		.func = test__keep_tracking,
124	},
125	{
126		.desc = "Test parsing with no sample_id_all bit set",
127		.func = test__parse_no_sample_id_all,
128	},
129#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
130#ifdef HAVE_DWARF_UNWIND_SUPPORT
131	{
132		.desc = "Test dwarf unwind",
133		.func = test__dwarf_unwind,
134	},
135#endif
136#endif
137	{
138		.desc = "Test filtering hist entries",
139		.func = test__hists_filter,
140	},
141	{
142		.desc = "Test mmap thread lookup",
143		.func = test__mmap_thread_lookup,
144	},
145	{
146		.desc = "Test thread mg sharing",
147		.func = test__thread_mg_share,
148	},
149	{
150		.desc = "Test output sorting of hist entries",
151		.func = test__hists_output,
152	},
153	{
154		.desc = "Test cumulation of child hist entries",
155		.func = test__hists_cumulate,
156	},
157	{
158		.desc = "Test tracking with sched_switch",
159		.func = test__switch_tracking,
160	},
161	{
162		.desc = "Filter fds with revents mask in a fdarray",
163		.func = test__fdarray__filter,
164	},
165	{
166		.desc = "Add fd to a fdarray, making it autogrow",
167		.func = test__fdarray__add,
168	},
169	{
170		.desc = "Test kmod_path__parse function",
171		.func = test__kmod_path__parse,
172	},
173	{
174		.func = NULL,
175	},
176};
177
178static bool perf_test__matches(int curr, int argc, const char *argv[])
179{
180	int i;
181
182	if (argc == 0)
183		return true;
184
185	for (i = 0; i < argc; ++i) {
186		char *end;
187		long nr = strtoul(argv[i], &end, 10);
188
189		if (*end == '\0') {
190			if (nr == curr + 1)
191				return true;
192			continue;
193		}
194
195		if (strstr(tests[curr].desc, argv[i]))
196			return true;
197	}
198
199	return false;
200}
201
202static int run_test(struct test *test)
203{
204	int status, err = -1, child = fork();
205	char sbuf[STRERR_BUFSIZE];
206
207	if (child < 0) {
208		pr_err("failed to fork test: %s\n",
209			strerror_r(errno, sbuf, sizeof(sbuf)));
210		return -1;
211	}
212
213	if (!child) {
214		pr_debug("test child forked, pid %d\n", getpid());
215		err = test->func();
216		exit(err);
217	}
218
219	wait(&status);
220
221	if (WIFEXITED(status)) {
222		err = WEXITSTATUS(status);
223		pr_debug("test child finished with %d\n", err);
224	} else if (WIFSIGNALED(status)) {
225		err = -1;
226		pr_debug("test child interrupted\n");
227	}
228
229	return err;
230}
231
232static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
233{
234	int i = 0;
235	int width = 0;
236
237	while (tests[i].func) {
238		int len = strlen(tests[i].desc);
239
240		if (width < len)
241			width = len;
242		++i;
243	}
244
245	i = 0;
246	while (tests[i].func) {
247		int curr = i++, err;
248
249		if (!perf_test__matches(curr, argc, argv))
250			continue;
251
252		pr_info("%2d: %-*s:", i, width, tests[curr].desc);
253
254		if (intlist__find(skiplist, i)) {
255			color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
256			continue;
257		}
258
259		pr_debug("\n--- start ---\n");
260		err = run_test(&tests[curr]);
261		pr_debug("---- end ----\n%s:", tests[curr].desc);
262
263		switch (err) {
264		case TEST_OK:
265			pr_info(" Ok\n");
266			break;
267		case TEST_SKIP:
268			color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
269			break;
270		case TEST_FAIL:
271		default:
272			color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
273			break;
274		}
275	}
276
277	return 0;
278}
279
280static int perf_test__list(int argc, const char **argv)
281{
282	int i = 0;
283
284	while (tests[i].func) {
285		int curr = i++;
286
287		if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
288			continue;
289
290		pr_info("%2d: %s\n", i, tests[curr].desc);
291	}
292
293	return 0;
294}
295
296int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
297{
298	const char *test_usage[] = {
299	"perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
300	NULL,
301	};
302	const char *skip = NULL;
303	const struct option test_options[] = {
304	OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
305	OPT_INCR('v', "verbose", &verbose,
306		    "be more verbose (show symbol address, etc)"),
307	OPT_END()
308	};
309	const char * const test_subcommands[] = { "list", NULL };
310	struct intlist *skiplist = NULL;
311        int ret = hists__init();
312
313        if (ret < 0)
314                return ret;
315
316	argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0);
317	if (argc >= 1 && !strcmp(argv[0], "list"))
318		return perf_test__list(argc, argv);
319
320	symbol_conf.priv_size = sizeof(int);
321	symbol_conf.sort_by_name = true;
322	symbol_conf.try_vmlinux_path = true;
323
324	if (symbol__init(NULL) < 0)
325		return -1;
326
327	if (skip != NULL)
328		skiplist = intlist__new(skip);
329
330	return __cmd_test(argc, argv, skiplist);
331}
332