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