Commit | Line | Data |
---|---|---|
1c6a800c ACM |
1 | /* |
2 | * builtin-test.c | |
3 | * | |
4 | * Builtin regression testing command: ever growing number of sanity tests | |
5 | */ | |
0d8a5faa JO |
6 | #include <unistd.h> |
7 | #include <string.h> | |
1c6a800c | 8 | #include "builtin.h" |
a635fc51 | 9 | #include "hist.h" |
2ae82878 | 10 | #include "intlist.h" |
0a4e1ae6 | 11 | #include "tests.h" |
c81251e8 JO |
12 | #include "debug.h" |
13 | #include "color.h" | |
4b6ab94e | 14 | #include <subcmd/parse-options.h> |
c81251e8 | 15 | #include "symbol.h" |
0252208e | 16 | |
31b6753f MF |
17 | struct test __weak arch_tests[] = { |
18 | { | |
19 | .func = NULL, | |
20 | }, | |
21 | }; | |
22 | ||
23 | static struct test generic_tests[] = { | |
1c6a800c ACM |
24 | { |
25 | .desc = "vmlinux symtab matches kallsyms", | |
26 | .func = test__vmlinux_matches_kallsyms, | |
27 | }, | |
d854861c | 28 | { |
43f322b4 RV |
29 | .desc = "detect openat syscall event", |
30 | .func = test__openat_syscall_event, | |
d854861c | 31 | }, |
0252208e | 32 | { |
43f322b4 RV |
33 | .desc = "detect openat syscall event on all cpus", |
34 | .func = test__openat_syscall_event_on_all_cpus, | |
0252208e | 35 | }, |
de5fa3a8 ACM |
36 | { |
37 | .desc = "read samples using the mmap interface", | |
38 | .func = test__basic_mmap, | |
39 | }, | |
13b62567 JO |
40 | { |
41 | .desc = "parse events tests", | |
c81251e8 | 42 | .func = test__parse_events, |
13b62567 | 43 | }, |
3e7c439a ACM |
44 | { |
45 | .desc = "Validate PERF_RECORD_* events & perf_sample fields", | |
46 | .func = test__PERF_RECORD, | |
47 | }, | |
cd82a32e JO |
48 | { |
49 | .desc = "Test perf pmu format parsing", | |
cff7f956 | 50 | .func = test__pmu, |
cd82a32e | 51 | }, |
f7add556 | 52 | { |
4ebbcb84 | 53 | .desc = "Test dso data read", |
c81251e8 | 54 | .func = test__dso_data, |
f7add556 | 55 | }, |
4ebbcb84 JO |
56 | { |
57 | .desc = "Test dso data cache", | |
58 | .func = test__dso_data_cache, | |
59 | }, | |
45dc1bb5 JO |
60 | { |
61 | .desc = "Test dso data reopen", | |
62 | .func = test__dso_data_reopen, | |
63 | }, | |
8ad7013b ACM |
64 | { |
65 | .desc = "roundtrip evsel->name check", | |
cfffae2e | 66 | .func = test__perf_evsel__roundtrip_name_test, |
8ad7013b | 67 | }, |
6a6cd11d ACM |
68 | { |
69 | .desc = "Check parsing of sched tracepoints fields", | |
5e24a090 | 70 | .func = test__perf_evsel__tp_sched_test, |
6a6cd11d | 71 | }, |
eb2f2703 | 72 | { |
43f322b4 RV |
73 | .desc = "Generate and check syscalls:sys_enter_openat event fields", |
74 | .func = test__syscall_openat_tp_fields, | |
eb2f2703 | 75 | }, |
d898b241 JO |
76 | { |
77 | .desc = "struct perf_event_attr setup", | |
c81251e8 | 78 | .func = test__attr, |
d898b241 | 79 | }, |
f8ebb0cd | 80 | { |
ffcbaa14 | 81 | .desc = "Test matching and linking multiple hists", |
f8ebb0cd NK |
82 | .func = test__hists_link, |
83 | }, | |
54359d33 | 84 | { |
887e73d7 | 85 | .desc = "Try 'import perf' in python, checking link problems", |
54359d33 ACM |
86 | .func = test__python_use, |
87 | }, | |
5a6bef47 JO |
88 | { |
89 | .desc = "Test breakpoint overflow signal handler", | |
90 | .func = test__bp_signal, | |
91 | }, | |
06933e3a JO |
92 | { |
93 | .desc = "Test breakpoint overflow sampling", | |
94 | .func = test__bp_signal_overflow, | |
95 | }, | |
d723a550 NK |
96 | { |
97 | .desc = "Test number of exit event of a simple workload", | |
98 | .func = test__task_exit, | |
99 | }, | |
bc96b361 NK |
100 | { |
101 | .desc = "Test software clock events have valid period values", | |
102 | .func = test__sw_clock_freq, | |
103 | }, | |
b55ae0a9 AH |
104 | { |
105 | .desc = "Test object code reading", | |
106 | .func = test__code_reading, | |
107 | }, | |
045f8cd8 AH |
108 | { |
109 | .desc = "Test sample parsing", | |
110 | .func = test__sample_parsing, | |
111 | }, | |
395c3070 AH |
112 | { |
113 | .desc = "Test using a dummy software event to keep tracking", | |
114 | .func = test__keep_tracking, | |
115 | }, | |
53a277e5 AH |
116 | { |
117 | .desc = "Test parsing with no sample_id_all bit set", | |
118 | .func = test__parse_no_sample_id_all, | |
119 | }, | |
3c3cfd99 NK |
120 | { |
121 | .desc = "Test filtering hist entries", | |
122 | .func = test__hists_filter, | |
123 | }, | |
4e85edfc JO |
124 | { |
125 | .desc = "Test mmap thread lookup", | |
126 | .func = test__mmap_thread_lookup, | |
127 | }, | |
fabf0123 JO |
128 | { |
129 | .desc = "Test thread mg sharing", | |
130 | .func = test__thread_mg_share, | |
131 | }, | |
f21d1815 NK |
132 | { |
133 | .desc = "Test output sorting of hist entries", | |
134 | .func = test__hists_output, | |
135 | }, | |
0506aecc NK |
136 | { |
137 | .desc = "Test cumulation of child hist entries", | |
138 | .func = test__hists_cumulate, | |
139 | }, | |
d44bc558 AH |
140 | { |
141 | .desc = "Test tracking with sched_switch", | |
142 | .func = test__switch_tracking, | |
143 | }, | |
54dbfae3 | 144 | { |
1b85337d ACM |
145 | .desc = "Filter fds with revents mask in a fdarray", |
146 | .func = test__fdarray__filter, | |
54dbfae3 | 147 | }, |
9ae28035 | 148 | { |
1b85337d ACM |
149 | .desc = "Add fd to a fdarray, making it autogrow", |
150 | .func = test__fdarray__add, | |
9ae28035 | 151 | }, |
3c8a67f5 JO |
152 | { |
153 | .desc = "Test kmod_path__parse function", | |
154 | .func = test__kmod_path__parse, | |
155 | }, | |
134aa44f JO |
156 | { |
157 | .desc = "Test thread map", | |
158 | .func = test__thread_map, | |
159 | }, | |
9bc898c7 WN |
160 | { |
161 | .desc = "Test LLVM searching and compiling", | |
162 | .func = test__llvm, | |
e8c6d500 WN |
163 | .subtest = { |
164 | .skip_if_fail = true, | |
165 | .get_nr = test__llvm_subtest_get_nr, | |
166 | .get_desc = test__llvm_subtest_get_desc, | |
167 | }, | |
9bc898c7 | 168 | }, |
c84974ed KL |
169 | { |
170 | .desc = "Test topology in session", | |
171 | .func = test_session_topology, | |
172 | }, | |
ba1fae43 WN |
173 | { |
174 | .desc = "Test BPF filter", | |
175 | .func = test__bpf, | |
77a0cf68 WN |
176 | .subtest = { |
177 | .skip_if_fail = true, | |
178 | .get_nr = test__bpf_subtest_get_nr, | |
179 | .get_desc = test__bpf_subtest_get_desc, | |
180 | }, | |
ba1fae43 | 181 | }, |
99471c96 JO |
182 | { |
183 | .desc = "Test thread map synthesize", | |
184 | .func = test__thread_map_synthesize, | |
185 | }, | |
6c872901 JO |
186 | { |
187 | .desc = "Test cpu map synthesize", | |
188 | .func = test__cpu_map_synthesize, | |
189 | }, | |
67424342 JO |
190 | { |
191 | .desc = "Test stat config synthesize", | |
192 | .func = test__synthesize_stat_config, | |
193 | }, | |
5796f8f0 JO |
194 | { |
195 | .desc = "Test stat synthesize", | |
196 | .func = test__synthesize_stat, | |
197 | }, | |
d4c22591 JO |
198 | { |
199 | .desc = "Test stat round synthesize", | |
200 | .func = test__synthesize_stat_round, | |
201 | }, | |
a6e52817 JO |
202 | { |
203 | .desc = "Test attr update synthesize", | |
204 | .func = test__event_update, | |
205 | }, | |
b31d660d JO |
206 | { |
207 | .desc = "Test events times", | |
208 | .func = test__event_times, | |
209 | }, | |
ee74701e WN |
210 | { |
211 | .desc = "Test backward reading from ring buffer", | |
212 | .func = test__backward_ring_buffer, | |
213 | }, | |
1c6a800c ACM |
214 | { |
215 | .func = NULL, | |
216 | }, | |
217 | }; | |
218 | ||
31b6753f MF |
219 | static struct test *tests[] = { |
220 | generic_tests, | |
221 | arch_tests, | |
222 | }; | |
223 | ||
e8210cef | 224 | static bool perf_test__matches(struct test *test, int curr, int argc, const char *argv[]) |
1c6a800c | 225 | { |
e60770a0 ACM |
226 | int i; |
227 | ||
228 | if (argc == 0) | |
229 | return true; | |
230 | ||
231 | for (i = 0; i < argc; ++i) { | |
232 | char *end; | |
233 | long nr = strtoul(argv[i], &end, 10); | |
234 | ||
235 | if (*end == '\0') { | |
236 | if (nr == curr + 1) | |
237 | return true; | |
238 | continue; | |
239 | } | |
1c6a800c | 240 | |
345c99a3 | 241 | if (strcasestr(test->desc, argv[i])) |
e60770a0 ACM |
242 | return true; |
243 | } | |
244 | ||
245 | return false; | |
246 | } | |
247 | ||
721a1f53 | 248 | static int run_test(struct test *test, int subtest) |
0d8a5faa JO |
249 | { |
250 | int status, err = -1, child = fork(); | |
ba3dfff8 | 251 | char sbuf[STRERR_BUFSIZE]; |
0d8a5faa JO |
252 | |
253 | if (child < 0) { | |
ba3dfff8 MH |
254 | pr_err("failed to fork test: %s\n", |
255 | strerror_r(errno, sbuf, sizeof(sbuf))); | |
0d8a5faa JO |
256 | return -1; |
257 | } | |
258 | ||
259 | if (!child) { | |
260 | pr_debug("test child forked, pid %d\n", getpid()); | |
5bcf2fe0 WN |
261 | if (!verbose) { |
262 | int nullfd = open("/dev/null", O_WRONLY); | |
263 | if (nullfd >= 0) { | |
264 | close(STDERR_FILENO); | |
265 | close(STDOUT_FILENO); | |
266 | ||
267 | dup2(nullfd, STDOUT_FILENO); | |
268 | dup2(STDOUT_FILENO, STDERR_FILENO); | |
269 | close(nullfd); | |
270 | } | |
b6847d2c ACM |
271 | } else { |
272 | signal(SIGSEGV, sighandler_dump_stack); | |
273 | signal(SIGFPE, sighandler_dump_stack); | |
5bcf2fe0 WN |
274 | } |
275 | ||
721a1f53 | 276 | err = test->func(subtest); |
0d8a5faa JO |
277 | exit(err); |
278 | } | |
279 | ||
280 | wait(&status); | |
281 | ||
282 | if (WIFEXITED(status)) { | |
189c466f | 283 | err = (signed char)WEXITSTATUS(status); |
0d8a5faa JO |
284 | pr_debug("test child finished with %d\n", err); |
285 | } else if (WIFSIGNALED(status)) { | |
286 | err = -1; | |
287 | pr_debug("test child interrupted\n"); | |
288 | } | |
289 | ||
290 | return err; | |
291 | } | |
292 | ||
31b6753f MF |
293 | #define for_each_test(j, t) \ |
294 | for (j = 0; j < ARRAY_SIZE(tests); j++) \ | |
295 | for (t = &tests[j][0]; t->func; t++) | |
e8210cef | 296 | |
e8c6d500 WN |
297 | static int test_and_print(struct test *t, bool force_skip, int subtest) |
298 | { | |
299 | int err; | |
300 | ||
301 | if (!force_skip) { | |
302 | pr_debug("\n--- start ---\n"); | |
303 | err = run_test(t, subtest); | |
304 | pr_debug("---- end ----\n"); | |
305 | } else { | |
306 | pr_debug("\n--- force skipped ---\n"); | |
307 | err = TEST_SKIP; | |
308 | } | |
309 | ||
310 | if (!t->subtest.get_nr) | |
311 | pr_debug("%s:", t->desc); | |
312 | else | |
313 | pr_debug("%s subtest %d:", t->desc, subtest); | |
314 | ||
315 | switch (err) { | |
316 | case TEST_OK: | |
317 | pr_info(" Ok\n"); | |
318 | break; | |
319 | case TEST_SKIP: | |
320 | color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n"); | |
321 | break; | |
322 | case TEST_FAIL: | |
323 | default: | |
324 | color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); | |
325 | break; | |
326 | } | |
327 | ||
328 | return err; | |
329 | } | |
330 | ||
2ae82878 | 331 | static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) |
e60770a0 | 332 | { |
e8210cef | 333 | struct test *t; |
31b6753f | 334 | unsigned int j; |
e60770a0 | 335 | int i = 0; |
9a8e85ad | 336 | int width = 0; |
1c6a800c | 337 | |
31b6753f | 338 | for_each_test(j, t) { |
e8210cef | 339 | int len = strlen(t->desc); |
9a8e85ad ACM |
340 | |
341 | if (width < len) | |
342 | width = len; | |
9a8e85ad | 343 | } |
945aea22 | 344 | |
31b6753f | 345 | for_each_test(j, t) { |
e60770a0 ACM |
346 | int curr = i++, err; |
347 | ||
e8210cef | 348 | if (!perf_test__matches(t, curr, argc, argv)) |
e60770a0 ACM |
349 | continue; |
350 | ||
e8210cef | 351 | pr_info("%2d: %-*s:", i, width, t->desc); |
2ae82878 ACM |
352 | |
353 | if (intlist__find(skiplist, i)) { | |
354 | color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); | |
355 | continue; | |
356 | } | |
357 | ||
e8c6d500 WN |
358 | if (!t->subtest.get_nr) { |
359 | test_and_print(t, false, -1); | |
360 | } else { | |
361 | int subn = t->subtest.get_nr(); | |
362 | /* | |
363 | * minus 2 to align with normal testcases. | |
364 | * For subtest we print additional '.x' in number. | |
365 | * for example: | |
366 | * | |
367 | * 35: Test LLVM searching and compiling : | |
368 | * 35.1: Basic BPF llvm compiling test : Ok | |
369 | */ | |
370 | int subw = width > 2 ? width - 2 : width; | |
371 | bool skip = false; | |
372 | int subi; | |
373 | ||
374 | if (subn <= 0) { | |
375 | color_fprintf(stderr, PERF_COLOR_YELLOW, | |
376 | " Skip (not compiled in)\n"); | |
377 | continue; | |
378 | } | |
379 | pr_info("\n"); | |
380 | ||
381 | for (subi = 0; subi < subn; subi++) { | |
382 | int len = strlen(t->subtest.get_desc(subi)); | |
383 | ||
384 | if (subw < len) | |
385 | subw = len; | |
386 | } | |
387 | ||
388 | for (subi = 0; subi < subn; subi++) { | |
389 | pr_info("%2d.%1d: %-*s:", i, subi + 1, subw, | |
390 | t->subtest.get_desc(subi)); | |
391 | err = test_and_print(t, skip, subi); | |
392 | if (err != TEST_OK && t->subtest.skip_if_fail) | |
393 | skip = true; | |
394 | } | |
f4c1ea5f | 395 | } |
1c6a800c ACM |
396 | } |
397 | ||
398 | return 0; | |
399 | } | |
400 | ||
e60770a0 ACM |
401 | static int perf_test__list(int argc, const char **argv) |
402 | { | |
31b6753f | 403 | unsigned int j; |
e8210cef | 404 | struct test *t; |
e60770a0 ACM |
405 | int i = 0; |
406 | ||
31b6753f | 407 | for_each_test(j, t) { |
e8210cef | 408 | if (argc > 1 && !strstr(t->desc, argv[1])) |
e60770a0 ACM |
409 | continue; |
410 | ||
e8210cef | 411 | pr_info("%2d: %s\n", ++i, t->desc); |
e60770a0 ACM |
412 | } |
413 | ||
414 | return 0; | |
415 | } | |
1c6a800c | 416 | |
1d037ca1 | 417 | int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) |
e60770a0 | 418 | { |
1f9975f1 | 419 | const char *test_usage[] = { |
e60770a0 ACM |
420 | "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", |
421 | NULL, | |
422 | }; | |
2ae82878 | 423 | const char *skip = NULL; |
e60770a0 | 424 | const struct option test_options[] = { |
2ae82878 | 425 | OPT_STRING('s', "skip", &skip, "tests", "tests to skip"), |
c30ab8aa | 426 | OPT_INCR('v', "verbose", &verbose, |
1c6a800c ACM |
427 | "be more verbose (show symbol address, etc)"), |
428 | OPT_END() | |
e60770a0 | 429 | }; |
1f9975f1 | 430 | const char * const test_subcommands[] = { "list", NULL }; |
2ae82878 | 431 | struct intlist *skiplist = NULL; |
a635fc51 ACM |
432 | int ret = hists__init(); |
433 | ||
434 | if (ret < 0) | |
435 | return ret; | |
1c6a800c | 436 | |
1f9975f1 | 437 | argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0); |
e60770a0 ACM |
438 | if (argc >= 1 && !strcmp(argv[0], "list")) |
439 | return perf_test__list(argc, argv); | |
1c6a800c ACM |
440 | |
441 | symbol_conf.priv_size = sizeof(int); | |
442 | symbol_conf.sort_by_name = true; | |
443 | symbol_conf.try_vmlinux_path = true; | |
444 | ||
0a7e6d1b | 445 | if (symbol__init(NULL) < 0) |
1c6a800c ACM |
446 | return -1; |
447 | ||
2ae82878 ACM |
448 | if (skip != NULL) |
449 | skiplist = intlist__new(skip); | |
450 | ||
451 | return __cmd_test(argc, argv, skiplist); | |
1c6a800c | 452 | } |