xref: /linux/tools/perf/tests/builtin-test.c (revision 3dabc8ad8ae024101dd0cfd42fd72df8817622f5)
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 <ctype.h>
8 #include <fcntl.h>
9 #include <errno.h>
10 #ifdef HAVE_BACKTRACE_SUPPORT
11 #include <execinfo.h>
12 #endif
13 #include <setjmp.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #include "util/config.h"
19 
20 #include <dirent.h>
21 #include <linux/kernel.h>
22 #include <linux/string.h>
23 #include <linux/zalloc.h>
24 #include <poll.h>
25 #include <sys/ioctl.h>
26 #include <sys/stat.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <sys/wait.h>
30 #include <unistd.h>
31 
32 #include <subcmd/exec-cmd.h>
33 #include <subcmd/parse-options.h>
34 #include <subcmd/run-command.h>
35 
36 #include <sys/mman.h>
37 
38 #include "builtin.h"
39 #include "color.h"
40 #include "config.h"
41 #include "debug.h"
42 #include "hist.h"
43 #include "intlist.h"
44 #include "string2.h"
45 #include "symbol.h"
46 #include "tests-scripts.h"
47 #include "tests.h"
48 #include "util/cap.h"
49 #include "util/event.h"
50 #include "util/mutex.h"
51 #include "util/rlimit.h"
52 #include "util/strbuf.h"
53 #include "util/term.h"
54 
55 static const char *junit_filename;
56 static struct strbuf junit_xml_buf = STRBUF_INIT;
57 
58 /*
59  * Command line option to not fork the test running in the same process and
60  * making them easier to debug.
61  */
62 static bool dont_fork;
63 /* Fork the tests in parallel and wait for their completion. */
64 static bool sequential;
65 /* List what each test needs, set by the "requisites" subcommand. */
66 static bool list_requisites;
67 /* Number of times each test is run. */
68 static unsigned int runs_per_test = 1;
69 /* Number of lines to include in failure snippet. */
70 static unsigned int failure_snippet_lines = 10;
71 /*
72  * The tests mapping ring buffers take turns using their share of
73  * kernel.perf_event_mlock_kb via this mutex, shared with the forked test
74  * processes and robust so that a test killed while holding it doesn't leave
75  * the budget locked, see mutex_init_pshared_robust().
76  */
77 struct mlock_budget {
78 	struct mutex lock;
79 };
80 
81 static struct mlock_budget *mlock_budget;
82 const char *dso_to_test;
83 const char *test_objdump_path = "objdump";
84 static const char *workload_control;
85 
86 /*
87  * List of architecture specific tests. Not a weak symbol as the array length is
88  * dependent on the initialization, as such GCC with LTO complains of
89  * conflicting definitions with a weak symbol.
90  */
91 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
92 	defined(__powerpc64__) || defined(__riscv)
93 extern struct test_suite *arch_tests[];
94 #else
95 static struct test_suite *arch_tests[] = {
96 	NULL,
97 };
98 #endif
99 
100 static struct test_suite *generic_tests[] = {
101 	&suite__vmlinux_matches_kallsyms,
102 	&suite__openat_syscall_event,
103 	&suite__openat_syscall_event_on_all_cpus,
104 	&suite__basic_mmap,
105 	&suite__mem,
106 	&suite__parse_events,
107 	&suite__uncore_event_sorting,
108 	&suite__expr,
109 	&suite__PERF_RECORD,
110 	&suite__pmu,
111 	&suite__pmu_events,
112 	&suite__hwmon_pmu,
113 	&suite__tool_pmu,
114 	&suite__dso_data,
115 	&suite__perf_evsel__roundtrip_name_test,
116 #ifdef HAVE_LIBTRACEEVENT
117 	&suite__perf_evsel__tp_sched_test,
118 	&suite__syscall_openat_tp_fields,
119 #endif
120 	&suite__hists_link,
121 	&suite__bp_signal,
122 	&suite__bp_signal_overflow,
123 	&suite__event_refresh,
124 	&suite__bp_accounting,
125 	&suite__wp,
126 	&suite__task_exit,
127 	&suite__sw_clock_freq,
128 	&suite__code_reading,
129 	&suite__sample_parsing,
130 	&suite__keep_tracking,
131 	&suite__parse_no_sample_id_all,
132 	&suite__hists_filter,
133 	&suite__mmap_thread_lookup,
134 	&suite__thread_maps_share,
135 	&suite__hists_output,
136 	&suite__hists_cumulate,
137 #ifdef HAVE_LIBTRACEEVENT
138 	&suite__switch_tracking,
139 #endif
140 	&suite__fdarray__filter,
141 	&suite__fdarray__add,
142 	&suite__kmod_path__parse,
143 	&suite__thread_map,
144 	&suite__session_topology,
145 	&suite__thread_map_synthesize,
146 	&suite__thread_map_remove,
147 	&suite__cpu_map,
148 	&suite__synthesize_stat_config,
149 	&suite__synthesize_stat,
150 	&suite__synthesize_stat_round,
151 	&suite__event_update,
152 	&suite__event_times,
153 	&suite__backward_ring_buffer,
154 	&suite__sdt_event,
155 	&suite__is_printable_array,
156 	&suite__bitmap_print,
157 	&suite__perf_hooks,
158 	&suite__unit_number__scnprint,
159 	&suite__mem2node,
160 	&suite__time_utils,
161 	&suite__jit_write_elf,
162 	&suite__pfm,
163 	&suite__api_io,
164 	&suite__maps,
165 	&suite__demangle_java,
166 	&suite__demangle_ocaml,
167 	&suite__demangle_rust,
168 	&suite__parse_metric,
169 	&suite__pe_file_parsing,
170 	&suite__expand_cgroup_events,
171 	&suite__perf_time_to_tsc,
172 	&suite__dlfilter,
173 	&suite__sigtrap,
174 	&suite__event_groups,
175 	&suite__hybrid_merge,
176 	&suite__symbols,
177 	&suite__util,
178 	&suite__subcmd_help,
179 	&suite__kallsyms_split,
180 	NULL,
181 };
182 
183 static struct test_workload *workloads[] = {
184 	&workload__noploop,
185 	&workload__thloop,
186 	&workload__named_threads,
187 	&workload__leafloop,
188 	&workload__sqrtloop,
189 	&workload__brstack,
190 	&workload__datasym,
191 	&workload__landlock,
192 	&workload__traploop,
193 	&workload__inlineloop,
194 	&workload__jitdump,
195 	&workload__context_switch_loop,
196 	&workload__deterministic,
197 	&workload__callchain,
198 	&workload__false_sharing,
199 
200 #ifdef HAVE_RUST_SUPPORT
201 	&workload__code_with_type,
202 #endif
203 };
204 
205 struct workload_control {
206 	int ctl_fd;
207 	int ack_fd;
208 };
209 
210 #define workloads__for_each(workload) \
211 	for (unsigned i = 0; i < ARRAY_SIZE(workloads) && ({ workload = workloads[i]; 1; }); i++)
212 
213 #define test_suite__for_each_test_case(suite, idx)			\
214 	for (idx = 0; (suite)->test_cases && (suite)->test_cases[idx].name != NULL; idx++)
215 
216 static void close_parent_fds(void)
217 {
218 	DIR *dir = opendir("/proc/self/fd");
219 	struct dirent *ent;
220 
221 	while ((ent = readdir(dir))) {
222 		char *end;
223 		long fd;
224 
225 		if (ent->d_type != DT_LNK)
226 			continue;
227 
228 		if (!isdigit(ent->d_name[0]))
229 			continue;
230 
231 		fd = strtol(ent->d_name, &end, 10);
232 		if (*end)
233 			continue;
234 
235 		if (fd <= 3 || fd == dirfd(dir))
236 			continue;
237 
238 		close(fd);
239 	}
240 	closedir(dir);
241 }
242 
243 static void check_leaks(void)
244 {
245 	DIR *dir = opendir("/proc/self/fd");
246 	struct dirent *ent;
247 	int leaks = 0;
248 
249 	while ((ent = readdir(dir))) {
250 		char path[PATH_MAX];
251 		char *end;
252 		long fd;
253 		ssize_t len;
254 
255 		if (ent->d_type != DT_LNK)
256 			continue;
257 
258 		if (!isdigit(ent->d_name[0]))
259 			continue;
260 
261 		fd = strtol(ent->d_name, &end, 10);
262 		if (*end)
263 			continue;
264 
265 		if (fd <= 3 || fd == dirfd(dir))
266 			continue;
267 
268 		leaks++;
269 		len = readlinkat(dirfd(dir), ent->d_name, path, sizeof(path));
270 		if (len > 0 && (size_t)len < sizeof(path))
271 			path[len] = '\0';
272 		else
273 			strncpy(path, ent->d_name, sizeof(path));
274 		pr_err("Leak of file descriptor %s that opened: '%s'\n", ent->d_name, path);
275 	}
276 	closedir(dir);
277 	if (leaks)
278 		abort();
279 }
280 
281 static int test_suite__num_test_cases(const struct test_suite *t)
282 {
283 	int num;
284 
285 	test_suite__for_each_test_case(t, num);
286 
287 	return num;
288 }
289 
290 static const char *skip_reason(const struct test_suite *t, int test_case)
291 {
292 	if (!t->test_cases)
293 		return NULL;
294 
295 	return t->test_cases[test_case >= 0 ? test_case : 0].skip_reason;
296 }
297 
298 static const char *test_description(const struct test_suite *t, int test_case)
299 {
300 	if (t->test_cases && test_case >= 0)
301 		return t->test_cases[test_case].desc;
302 
303 	return t->desc;
304 }
305 
306 static void requisites__fprintf(FILE *fp, const struct test_suite *t, int test_case)
307 {
308 	bool needs_mlock = t->needs_mlock, exclusive;
309 
310 	if (test_case < 0)
311 		test_case = test_suite__num_test_cases(t) == 1 ? 0 : -1;
312 
313 	if (test_case >= 0) {
314 		exclusive = t->test_cases[test_case].exclusive;
315 		/* The catch-all implies every other requisite. */
316 		needs_mlock = needs_mlock || exclusive;
317 	} else {
318 		exclusive = false;
319 	}
320 
321 	if (!exclusive && !needs_mlock)
322 		return;
323 
324 	fprintf(fp, " (");
325 	if (exclusive)
326 		fprintf(fp, "exclusive, ");
327 	fprintf(fp, "mlock)");
328 }
329 
330 static test_fnptr test_function(const struct test_suite *t, int test_case)
331 {
332 	if (test_case <= 0)
333 		return t->test_cases[0].run_case;
334 
335 	return t->test_cases[test_case].run_case;
336 }
337 
338 static bool test_exclusive(const struct test_suite *t, int test_case)
339 {
340 	if (test_case <= 0)
341 		return t->test_cases[0].exclusive;
342 
343 	return t->test_cases[test_case].exclusive;
344 }
345 
346 static bool perf_test__matches(const char *desc, int suite_num, int argc, const char *argv[])
347 {
348 	int i;
349 
350 	if (argc == 0)
351 		return true;
352 
353 	for (i = 0; i < argc; ++i) {
354 		char *end;
355 		long nr = strtoul(argv[i], &end, 10);
356 
357 		if (*end == '\0') {
358 			if (nr == suite_num + 1)
359 				return true;
360 			continue;
361 		}
362 
363 		if (strcasestr(desc, argv[i]))
364 			return true;
365 	}
366 
367 	return false;
368 }
369 
370 struct child_test {
371 	struct child_process process;
372 	struct test_suite *test;
373 	int suite_num;
374 	int test_case_num;
375 	struct strbuf err_output;
376 	int result;
377 	bool done;
378 	struct timespec start_time;
379 	struct timespec end_time;
380 };
381 
382 static jmp_buf run_test_jmp_buf;
383 
384 static void child_test_sig_handler(int sig)
385 {
386 #ifdef HAVE_BACKTRACE_SUPPORT
387 	void *stackdump[32];
388 	size_t stackdump_size;
389 #endif
390 
391 	fprintf(stderr, "\n---- unexpected signal (%d) ----\n", sig);
392 #ifdef HAVE_BACKTRACE_SUPPORT
393 	stackdump_size = backtrace(stackdump, ARRAY_SIZE(stackdump));
394 	__dump_stack(stderr, stackdump, stackdump_size);
395 #endif
396 	siglongjmp(run_test_jmp_buf, sig);
397 }
398 
399 static int run_test_case(struct child_test *child)
400 {
401 	return test_function(child->test, child->test_case_num)(child->test, child->test_case_num);
402 }
403 
404 /* The thread safety analysis can't express a lock held conditionally. */
405 static int run_test_case_mlocked(struct child_test *child)
406 {
407 	int err;
408 
409 	mutex_lock(&mlock_budget->lock);
410 	err = run_test_case(child);
411 	mutex_unlock(&mlock_budget->lock);
412 
413 	return err;
414 }
415 
416 static int run_test_child(struct child_process *process)
417 {
418 	const int signals[] = {
419 		SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGINT, SIGPIPE, SIGQUIT, SIGSEGV, SIGTERM,
420 	};
421 	struct child_test *child = container_of(process, struct child_test, process);
422 	bool needs_mlock = mlock_budget && child->test->needs_mlock;
423 	int err;
424 
425 	close_parent_fds();
426 
427 	err = sigsetjmp(run_test_jmp_buf, 1);
428 	if (err) {
429 		/* Received signal. */
430 		err = err > 0 ? -err : -1;
431 		goto err_out;
432 	}
433 
434 	for (size_t i = 0; i < ARRAY_SIZE(signals); i++)
435 		signal(signals[i], child_test_sig_handler);
436 
437 	pr_debug("---- start ----\n");
438 	pr_debug("test child forked, pid %d\n", getpid());
439 
440 	if (needs_mlock)
441 		err = run_test_case_mlocked(child);
442 	else
443 		err = run_test_case(child);
444 
445 	pr_debug("---- end(%d) ----\n", err);
446 
447 	check_leaks();
448 err_out:
449 	fflush(NULL);
450 	for (size_t i = 0; i < ARRAY_SIZE(signals); i++)
451 		signal(signals[i], SIG_DFL);
452 	return -err;
453 }
454 
455 #define TEST_RUNNING -3
456 
457 static struct pollfd *global_pfds;
458 static size_t *global_pfd_indices;
459 static unsigned int summary_tests_passed;
460 static unsigned int summary_subtests_passed;
461 static unsigned int summary_tests_skipped;
462 static unsigned int summary_tests_failed;
463 static struct strbuf summary_failed_tests_buf = STRBUF_INIT;
464 
465 static int strbuf_addstr_safe(struct strbuf *sb, const char *s);
466 static int __printf(2, 3) strbuf_addf_safe(struct strbuf *sb, const char *fmt, ...);
467 
468 static char *xml_escape(const char *str)
469 {
470 	struct strbuf buf = STRBUF_INIT;
471 	const char *p;
472 	char *res;
473 
474 	if (!str)
475 		return strdup("");
476 
477 	for (p = str; *p; p++) {
478 		if (*p == '&')
479 			strbuf_addstr(&buf, "&amp;");
480 		else if (*p == '<')
481 			strbuf_addstr(&buf, "&lt;");
482 		else if (*p == '>')
483 			strbuf_addstr(&buf, "&gt;");
484 		else if (*p == '"')
485 			strbuf_addstr(&buf, "&quot;");
486 		else if ((unsigned char)*p >= 32 || *p == '\n' || *p == '\t')
487 			strbuf_addch(&buf, *p);
488 	}
489 	res = strbuf_detach(&buf, NULL);
490 	return res ? res : strdup("");
491 }
492 
493 static int get_term_width(void)
494 {
495 	struct winsize ws;
496 	int cols = 80;
497 	int term_width;
498 
499 	/*
500 	 * If output is redirected to a file or piped, we don't need to wrap
501 	 * or truncate at all. Use a massive virtually infinite terminal width
502 	 * so descriptions are printed in full.
503 	 */
504 	if (!isatty(fileno(debug_file())))
505 		return 10000;
506 
507 	get_term_dimensions(&ws);
508 	if (ws.ws_col > 0)
509 		cols = ws.ws_col;
510 
511 	/*
512 	 * Limit description width to fit on a single line. We subtract 35
513 	 * columns of headroom to allocate space for:
514 	 * - The suite index prefix: e.g. " 10.100:" (8 characters) plus 1 space separator.
515 	 * - The trailing colon (1 character) and space before status (1 character).
516 	 * - The longest status results: e.g. "Skip (some metrics failed)" (26 characters)
517 	 *   or "Running (XX active)" (20 characters).
518 	 *
519 	 * A minimum description width of 10 is enforced to ensure names are
520 	 * legible even on very narrow consoles.
521 	 */
522 	term_width = cols - 35;
523 	if (term_width < 10)
524 		term_width = 10;
525 
526 	return term_width;
527 }
528 
529 static int get_max_desc_width(int width)
530 {
531 	int term_width = get_term_width();
532 
533 	return width > term_width ? term_width : width;
534 }
535 
536 static int print_test_result(struct test_suite *t, int curr_suite, int curr_test_case,
537 			     int result, int width, int running,
538 			     const char *err_output, double elapsed)
539 {
540 	int pad_width = get_max_desc_width(width);
541 	int term_width = get_term_width();
542 
543 	if (test_suite__num_test_cases(t) > 1) {
544 		char prefix[32];
545 		int len = snprintf(prefix, sizeof(prefix), "%3d.%1d:",
546 				   curr_suite + 1, curr_test_case + 1);
547 		int pad = len >= 4 ? pad_width + 4 - len : pad_width;
548 		int trunc = len >= 4 ? term_width + 4 - len : term_width;
549 
550 		pr_info("%s %-*.*s:", prefix, pad, trunc,
551 			test_description(t, curr_test_case));
552 	} else {
553 		pr_info("%3d: %-*.*s:", curr_suite + 1, pad_width, term_width,
554 			test_description(t, curr_test_case));
555 	}
556 
557 	switch (result) {
558 	case TEST_RUNNING:
559 		color_fprintf(debug_file(), PERF_COLOR_YELLOW, " Running (%d active)\n", running);
560 		break;
561 	case TEST_OK:
562 		if (test_suite__num_test_cases(t) > 1)
563 			summary_subtests_passed++;
564 		else
565 			summary_tests_passed++;
566 		pr_info(" Ok\n");
567 		break;
568 	case TEST_SKIP: {
569 		const char *reason = skip_reason(t, curr_test_case);
570 
571 		summary_tests_skipped++;
572 		if (reason)
573 			color_fprintf(debug_file(), PERF_COLOR_YELLOW, " Skip (%s)\n", reason);
574 		else
575 			color_fprintf(debug_file(), PERF_COLOR_YELLOW, " Skip\n");
576 	}
577 		break;
578 	case TEST_FAIL:
579 	default:
580 		summary_tests_failed++;
581 		if (test_suite__num_test_cases(t) > 1)
582 			strbuf_addf_safe(&summary_failed_tests_buf, "  %3d.%1d: %s\n",
583 				    curr_suite + 1, curr_test_case + 1,
584 				    test_description(t, curr_test_case));
585 		else
586 			strbuf_addf_safe(&summary_failed_tests_buf, "  %3d: %s\n",
587 				    curr_suite + 1,
588 				    test_description(t, curr_test_case));
589 		color_fprintf(debug_file(), PERF_COLOR_RED, " FAILED!\n");
590 		break;
591 	}
592 
593 	if (junit_filename && result != TEST_RUNNING) {
594 		const char *classname = t->desc;
595 		const char *testname = test_description(t, curr_test_case);
596 		char *escaped_err = xml_escape(err_output);
597 		char *escaped_class = xml_escape(classname);
598 		char *escaped_test = xml_escape(testname);
599 
600 		strbuf_addf(&junit_xml_buf,
601 			    "    <testcase classname=\"%s\" name=\"%s\" time=\"%.2f\">\n",
602 			    escaped_class, escaped_test, elapsed);
603 		if (result != TEST_OK && result != TEST_SKIP) {
604 			strbuf_addf(&junit_xml_buf,
605 				    "      <failure message=\"FAILED\">\n%s\n      </failure>\n",
606 				    escaped_err);
607 		} else if (result == TEST_SKIP) {
608 			const char *reason = skip_reason(t, curr_test_case);
609 			char *escaped_reason = xml_escape(reason ? reason : "Skip");
610 
611 			if (err_output && *err_output) {
612 				strbuf_addf(&junit_xml_buf,
613 					    "      <skipped message=\"%s\">\n%s\n      </skipped>\n",
614 					    escaped_reason, escaped_err);
615 			} else {
616 				strbuf_addf(&junit_xml_buf, "      <skipped message=\"%s\"/>\n",
617 					    escaped_reason);
618 			}
619 			free(escaped_reason);
620 		}
621 		strbuf_addstr(&junit_xml_buf, "    </testcase>\n");
622 		free(escaped_err);
623 		free(escaped_class);
624 		free(escaped_test);
625 	}
626 
627 	return 0;
628 }
629 
630 static const char * const fail_keywords[] = {
631 	"error", "fail", "segv", "abort",
632 	"signal", "fatal", "panic", "corrupt", NULL
633 };
634 
635 static const char *find_next_keyword(const char *str, size_t max_len, size_t *kw_len)
636 {
637 	const char *best = NULL;
638 	size_t best_len = 0;
639 	int k;
640 
641 	for (k = 0; fail_keywords[k]; k++) {
642 		const char *s = str;
643 		size_t len = strlen(fail_keywords[k]);
644 
645 		while ((size_t)(s - str) + len <= max_len) {
646 			size_t i;
647 
648 			if (best && s >= best)
649 				break;
650 
651 			for (i = 0; i < len; i++) {
652 				if (tolower(s[i]) != fail_keywords[k][i])
653 					break;
654 			}
655 			if (i == len) {
656 				if (!best || s < best) {
657 					best = s;
658 					best_len = len;
659 				}
660 				break;
661 			}
662 			s++;
663 		}
664 	}
665 	if (best) {
666 		*kw_len = best_len;
667 		return best;
668 	}
669 	return NULL;
670 }
671 
672 static void print_line_highlighted(FILE *fp, const char *line, size_t len)
673 {
674 	const char *s = line;
675 
676 	while (len > 0) {
677 		size_t kw_len = 0;
678 		const char *match = find_next_keyword(s, len, &kw_len);
679 
680 		if (!match) {
681 			fwrite(s, 1, len, fp);
682 			break;
683 		}
684 		if (match > s)
685 			fwrite(s, 1, match - s, fp);
686 		if (perf_use_color_default)
687 			fprintf(fp, "%s", PERF_COLOR_RED);
688 		fwrite(match, 1, kw_len, fp);
689 		if (perf_use_color_default)
690 			fprintf(fp, "%s", PERF_COLOR_RESET);
691 
692 		len -= (match + kw_len) - s;
693 		s = match + kw_len;
694 	}
695 }
696 
697 
698 static bool is_blank_line(const char *line, size_t len)
699 {
700 	for (size_t i = 0; i < len; i++) {
701 		if (!isspace((unsigned char)line[i]))
702 			return false;
703 	}
704 	return true;
705 }
706 
707 static bool is_stack_line(const char *line, size_t len)
708 {
709 	size_t i = 0;
710 
711 	while (i < len && isspace((unsigned char)line[i]))
712 		i++;
713 	return i + 1 < len && line[i] == '#' && isdigit((unsigned char)line[i + 1]);
714 }
715 
716 static bool is_ignorable_snippet_line(const char *line, size_t len)
717 {
718 	return is_blank_line(line, len) || is_stack_line(line, len);
719 }
720 
721 static bool has_non_blank_between(const char **lines, const size_t *line_lens,
722 				  size_t start, size_t end)
723 {
724 	for (size_t j = start + 1; j < end; j++) {
725 		if (!is_blank_line(lines[j], line_lens[j]))
726 			return true;
727 	}
728 	return false;
729 }
730 
731 static void pick_snippet_line(bool *pick, size_t idx, unsigned int *picked_count)
732 {
733 	if (!pick[idx] && *picked_count < failure_snippet_lines) {
734 		pick[idx] = true;
735 		(*picked_count)++;
736 	}
737 }
738 
739 static void print_test_failure_snippet(FILE *fp, const char *buf)
740 {
741 	size_t num_lines = 0;
742 	size_t max_lines = 128;
743 	const char **lines = calloc(max_lines, sizeof(const char *));
744 	size_t *line_lens = calloc(max_lines, sizeof(size_t));
745 	const char *s = buf;
746 	size_t i;
747 	unsigned int picked_count = 0;
748 	bool *pick;
749 	int last_printed = -1;
750 
751 	if (!lines || !line_lens) {
752 		free(lines); free(line_lens);
753 		fprintf(fp, "%s", buf);
754 		return;
755 	}
756 
757 	while (*s) {
758 		const char *eol = strchr(s, '\n');
759 		size_t len;
760 
761 		if (eol)
762 			len = eol - s + 1;
763 		else
764 			len = strlen(s);
765 
766 		if (num_lines == max_lines) {
767 			const char **new_lines;
768 			size_t *new_lens;
769 
770 			max_lines *= 2;
771 			new_lines = realloc(lines, max_lines * sizeof(const char *));
772 			if (!new_lines) {
773 				free(lines); free(line_lens);
774 				fprintf(fp, "%s", buf);
775 				return;
776 			}
777 			lines = new_lines;
778 
779 			new_lens = realloc(line_lens, max_lines * sizeof(size_t));
780 			if (!new_lens) {
781 				free(lines); free(line_lens);
782 				fprintf(fp, "%s", buf);
783 				return;
784 			}
785 			line_lens = new_lens;
786 		}
787 		lines[num_lines] = s;
788 		line_lens[num_lines] = len;
789 		num_lines++;
790 		s += len;
791 	}
792 
793 	if (num_lines <= failure_snippet_lines) {
794 		for (i = 0; i < num_lines; i++)
795 			print_line_highlighted(fp, lines[i], line_lens[i]);
796 		free(lines); free(line_lens);
797 		return;
798 	}
799 
800 	pick = calloc(num_lines, sizeof(bool));
801 	if (!pick) {
802 		for (i = 0; i < num_lines; i++)
803 			print_line_highlighted(fp, lines[i], line_lens[i]);
804 		free(lines); free(line_lens);
805 		return;
806 	}
807 
808 	/* Pass 0: Always pick the very first line */
809 	if (num_lines > 0)
810 		pick_snippet_line(pick, 0, &picked_count);
811 
812 	/* Pass 1: Pick lines with failure keywords from start (Highest Priority) */
813 	for (i = 0; i < num_lines && picked_count < failure_snippet_lines; i++) {
814 		size_t dummy;
815 
816 		if (is_ignorable_snippet_line(lines[i], line_lens[i]))
817 			continue;
818 		if (!find_next_keyword(lines[i], line_lens[i], &dummy))
819 			continue;
820 
821 		pick_snippet_line(pick, i, &picked_count);
822 		/*
823 		 * For unexpected signals, prioritize the preceding non-blank
824 		 * line showing where the test had run to before the signal.
825 		 */
826 		if (!strncmp(lines[i], "---- unexpected signal", 22)) {
827 			size_t j = i;
828 
829 			while (j > 0) {
830 				j--;
831 				if (!is_ignorable_snippet_line(lines[j], line_lens[j])) {
832 					pick_snippet_line(pick, j, &picked_count);
833 					break;
834 				}
835 			}
836 		}
837 		/* Prioritize getting the immediate next line for context */
838 		if (i + 1 < num_lines &&
839 		    !is_ignorable_snippet_line(lines[i + 1], line_lens[i + 1]))
840 			pick_snippet_line(pick, i + 1, &picked_count);
841 	}
842 
843 	/*
844 	 * Pass 2: Fill remaining quota from the end backwards, skipping blank
845 	 * and stack trace lines so trailing test progress is shown instead of
846 	 * outermost stack frames like main/_start.
847 	 */
848 	i = num_lines;
849 	while (i > 0 && picked_count < failure_snippet_lines) {
850 		i--;
851 		if (!is_ignorable_snippet_line(lines[i], line_lens[i]))
852 			pick_snippet_line(pick, i, &picked_count);
853 	}
854 
855 	/* Pass 3: Fallback to top stack frames if quota remains */
856 	for (i = 0; i < num_lines && picked_count < failure_snippet_lines; i++) {
857 		if (!is_blank_line(lines[i], line_lens[i]))
858 			pick_snippet_line(pick, i, &picked_count);
859 	}
860 
861 	for (i = 0; i < num_lines; i++) {
862 		if (!pick[i])
863 			continue;
864 		if (last_printed != -1 &&
865 		    has_non_blank_between(lines, line_lens, last_printed, i)) {
866 			if (perf_use_color_default)
867 				fprintf(fp, "%s...%s\n", PERF_COLOR_BLUE, PERF_COLOR_RESET);
868 			else
869 				fprintf(fp, "...\n");
870 		}
871 		print_line_highlighted(fp, lines[i], line_lens[i]);
872 		last_printed = i;
873 	}
874 
875 	free(pick);
876 	free(lines);
877 	free(line_lens);
878 }
879 
880 static void finish_test(struct child_test **child_tests, int running_test, int child_test_num,
881 		int width)
882 {
883 	struct child_test *child_test = child_tests[running_test];
884 	struct test_suite *t;
885 	int curr_suite, curr_test_case, err;
886 	bool err_done = false;
887 	struct strbuf err_output = STRBUF_INIT;
888 	int last_running = -1;
889 	int ret;
890 	struct timespec end_time;
891 	double elapsed;
892 	width = get_max_desc_width(width);
893 
894 	if (child_test == NULL) {
895 		/* Test wasn't started. */
896 		return;
897 	}
898 	t = child_test->test;
899 	curr_suite = child_test->suite_num;
900 	curr_test_case = child_test->test_case_num;
901 	err = child_test->process.err;
902 	/*
903 	 * For test suites with subtests, display the suite name ahead of the
904 	 * sub test names.
905 	 */
906 	if (test_suite__num_test_cases(t) > 1 && curr_test_case == 0)
907 		pr_info("%3d: %-*.*s:\n", curr_suite + 1, width, width,
908 			test_description(t, -1));
909 
910 	/*
911 	 * Busy loop reading from the child's stdout/stderr that are set to be
912 	 * non-blocking until EOF.
913 	 */
914 	if (err >= 0)
915 		fcntl(err, F_SETFL, O_NONBLOCK);
916 	if (verbose > 1) {
917 		if (test_suite__num_test_cases(t) > 1)
918 			pr_info("%3d.%1d: %s:\n", curr_suite + 1, curr_test_case + 1,
919 				test_description(t, curr_test_case));
920 		else
921 			pr_info("%3d: %s:\n", curr_suite + 1, test_description(t, -1));
922 	}
923 	while (!err_done) {
924 		struct pollfd pfds[1] = {
925 			{ .fd = err,
926 			  .events = POLLIN | POLLERR | POLLHUP | POLLNVAL,
927 			},
928 		};
929 		if (perf_use_color_default) {
930 			int running = 0;
931 
932 			for (int y = running_test; y < child_test_num; y++) {
933 				if (child_tests[y] == NULL)
934 					continue;
935 				if (check_if_command_finished(&child_tests[y]->process) == 0)
936 					running++;
937 			}
938 			if (running != last_running) {
939 				if (last_running != -1) {
940 					/*
941 					 * Erase "Running (.. active)" line
942 					 * printed before poll/sleep.
943 					 */
944 					fprintf(debug_file(), PERF_COLOR_DELETE_LINE);
945 				}
946 				print_test_result(t, curr_suite, curr_test_case, TEST_RUNNING,
947 						  width, running, NULL, 0.0);
948 				last_running = running;
949 			}
950 		}
951 
952 		err_done = true;
953 		if (err <= 0) {
954 			/* No child stderr to poll, sleep for 10ms for child to complete. */
955 			usleep(10 * 1000);
956 		} else {
957 			/* Poll to avoid excessive spinning, timeout set for 100ms. */
958 			poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100);
959 			if (pfds[0].revents) {
960 				char buf[512];
961 				ssize_t len;
962 
963 				len = read(err, buf, sizeof(buf) - 1);
964 
965 				if (len > 0) {
966 					err_done = false;
967 					buf[len] = '\0';
968 					strbuf_addstr_safe(&err_output, buf);
969 				}
970 			}
971 		}
972 		if (err_done)
973 			err_done = check_if_command_finished(&child_test->process);
974 	}
975 	/* Drain any remaining data from the pipe. */
976 	if (err >= 0) {
977 		char buf[512];
978 		ssize_t len;
979 
980 		while ((len = read(err, buf, sizeof(buf) - 1)) > 0) {
981 			buf[len] = '\0';
982 			strbuf_addstr_safe(&err_output, buf);
983 		}
984 	}
985 	if (perf_use_color_default && last_running != -1) {
986 		/* Erase "Running (.. active)" line printed before poll/sleep. */
987 		fprintf(debug_file(), PERF_COLOR_DELETE_LINE);
988 	}
989 	/* Clean up child process. */
990 	ret = finish_command(&child_test->process);
991 	child_test->process.pid = 0;
992 	if (child_test->err_output.len > 0) {
993 		struct strbuf merged = STRBUF_INIT;
994 
995 		if (child_test->err_output.buf)
996 			strbuf_addstr_safe(&merged, child_test->err_output.buf);
997 		if (err_output.buf)
998 			strbuf_addstr_safe(&merged, err_output.buf);
999 		strbuf_release(&err_output);
1000 		err_output = merged;
1001 	}
1002 	if (verbose > 1)
1003 		fprintf(stderr, "%s", err_output.buf);
1004 	else if (verbose == 1 && ret == TEST_FAIL)
1005 		print_test_failure_snippet(stderr, err_output.buf);
1006 
1007 	clock_gettime(CLOCK_MONOTONIC, &end_time);
1008 	elapsed = (end_time.tv_sec - child_test->start_time.tv_sec) +
1009 		  (end_time.tv_nsec - child_test->start_time.tv_nsec) / 1000000000.0;
1010 
1011 	print_test_result(t, curr_suite, curr_test_case, ret, width, /*running=*/0,
1012 			  err_output.buf, elapsed);
1013 	strbuf_release(&err_output);
1014 	strbuf_release(&child_test->err_output);
1015 	if (err > 0)
1016 		close(err);
1017 	zfree(&child_tests[running_test]);
1018 }
1019 
1020 static int strbuf_addstr_safe(struct strbuf *sb, const char *s)
1021 {
1022 	sigset_t set, oldset;
1023 	int ret;
1024 
1025 	sigemptyset(&set);
1026 	sigaddset(&set, SIGINT);
1027 	sigaddset(&set, SIGTERM);
1028 	pthread_sigmask(SIG_BLOCK, &set, &oldset);
1029 	ret = strbuf_addstr(sb, s);
1030 	pthread_sigmask(SIG_SETMASK, &oldset, NULL);
1031 	return ret;
1032 }
1033 
1034 static int __printf(2, 3) strbuf_addf_safe(struct strbuf *sb, const char *fmt, ...)
1035 {
1036 	char buf[1024];
1037 	va_list ap;
1038 	int len;
1039 	sigset_t set, oldset;
1040 	int ret;
1041 
1042 	sigemptyset(&set);
1043 	sigaddset(&set, SIGINT);
1044 	sigaddset(&set, SIGTERM);
1045 	sigprocmask(SIG_BLOCK, &set, &oldset);
1046 
1047 	va_start(ap, fmt);
1048 	len = vsnprintf(buf, sizeof(buf), fmt, ap);
1049 	va_end(ap);
1050 
1051 	if (len < 0) {
1052 		sigprocmask(SIG_SETMASK, &oldset, NULL);
1053 		return len;
1054 	}
1055 	if ((size_t)len >= sizeof(buf)) {
1056 		char *dynamic_buf = malloc(len + 1);
1057 
1058 		if (!dynamic_buf) {
1059 			sigprocmask(SIG_SETMASK, &oldset, NULL);
1060 			return -ENOMEM;
1061 		}
1062 		va_start(ap, fmt);
1063 		vsnprintf(dynamic_buf, len + 1, fmt, ap);
1064 		va_end(ap);
1065 		ret = strbuf_addstr(sb, dynamic_buf);
1066 		free(dynamic_buf);
1067 	} else {
1068 		ret = strbuf_addstr(sb, buf);
1069 	}
1070 
1071 	sigprocmask(SIG_SETMASK, &oldset, NULL);
1072 	return ret;
1073 }
1074 
1075 static void drain_child_process_err(struct child_test *child)
1076 {
1077 	char buf[512];
1078 	ssize_t len;
1079 
1080 	while ((len = read(child->process.err, buf, sizeof(buf) - 1)) > 0) {
1081 		buf[len] = '\0';
1082 		strbuf_addstr_safe(&child->err_output, buf);
1083 	}
1084 }
1085 
1086 static void handle_child_pipe_activity(struct child_test *child, short revents)
1087 {
1088 	if (!revents)
1089 		return;
1090 
1091 	drain_child_process_err(child);
1092 	/*
1093 	 * If the child closed its end of the pipe (EOF) or encountered
1094 	 * an error, close the file descriptor immediately and set it
1095 	 * to -1. This removes it from the pfds array for subsequent
1096 	 * iterations, preventing a tight CPU busy-loop while waiting
1097 	 * for the process itself to exit.
1098 	 */
1099 	if (revents & (POLLHUP | POLLERR | POLLNVAL)) {
1100 		close(child->process.err);
1101 		child->process.err = -1;
1102 	}
1103 }
1104 
1105 static int finish_tests_parallel(struct child_test **child_tests, size_t num_tests, int width)
1106 {
1107 	size_t next_to_print = 0;
1108 	struct pollfd *pfds;
1109 	size_t *pfd_indices;
1110 	size_t num_pfds = 0;
1111 	int last_running = -1;
1112 	size_t i;
1113 	int last_suite_printed = -1;
1114 	sigset_t set, oldset;
1115 
1116 	width = get_max_desc_width(width);
1117 
1118 	sigemptyset(&set);
1119 	sigaddset(&set, SIGINT);
1120 	sigaddset(&set, SIGTERM);
1121 
1122 	pthread_sigmask(SIG_BLOCK, &set, &oldset);
1123 	global_pfds = calloc(num_tests, sizeof(*pfds));
1124 	global_pfd_indices = calloc(num_tests, sizeof(*pfd_indices));
1125 	pfds = global_pfds;
1126 	pfd_indices = global_pfd_indices;
1127 	if (!pfds || !pfd_indices) {
1128 		free(pfds);
1129 		free(pfd_indices);
1130 		global_pfds = NULL;
1131 		global_pfd_indices = NULL;
1132 		pthread_sigmask(SIG_SETMASK, &oldset, NULL);
1133 		return -ENOMEM;
1134 	}
1135 	pthread_sigmask(SIG_SETMASK, &oldset, NULL);
1136 
1137 	for (i = 0; i < num_tests; i++) {
1138 		struct child_test *child = child_tests[i];
1139 
1140 		if (!child)
1141 			continue;
1142 		strbuf_init(&child->err_output, 0);
1143 		if (child->process.err >= 0)
1144 			fcntl(child->process.err, F_SETFL, O_NONBLOCK);
1145 	}
1146 
1147 	while (next_to_print < num_tests) {
1148 		size_t running_count = 0;
1149 		size_t p;
1150 
1151 		while (next_to_print < num_tests &&
1152 		       (!child_tests[next_to_print] || child_tests[next_to_print]->done))
1153 			next_to_print++;
1154 
1155 		if (next_to_print >= num_tests)
1156 			break;
1157 
1158 		num_pfds = 0;
1159 
1160 		for (i = next_to_print; i < num_tests; i++) {
1161 			struct child_test *child = child_tests[i];
1162 
1163 			if (!child || child->done)
1164 				continue;
1165 
1166 			if (!check_if_command_finished(&child->process))
1167 				running_count++;
1168 
1169 			if (child->process.err >= 0) {
1170 				pfds[num_pfds].fd = child->process.err;
1171 				pfds[num_pfds].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
1172 				pfd_indices[num_pfds] = i;
1173 				num_pfds++;
1174 			}
1175 		}
1176 
1177 		if (perf_use_color_default && running_count != (size_t)last_running) {
1178 			struct child_test *next_child = child_tests[next_to_print];
1179 
1180 			if (last_running != -1)
1181 				fprintf(debug_file(), PERF_COLOR_DELETE_LINE);
1182 
1183 			if (next_child) {
1184 				if (test_suite__num_test_cases(next_child->test) > 1 &&
1185 				    last_suite_printed != next_child->suite_num) {
1186 					pr_info("%3d: %-*.*s:\n",
1187 						next_child->suite_num + 1,
1188 						width, width,
1189 						test_description(
1190 							next_child->test, -1));
1191 					last_suite_printed = next_child->suite_num;
1192 				}
1193 				print_test_result(next_child->test, next_child->suite_num,
1194 						  next_child->test_case_num, TEST_RUNNING, width,
1195 						  running_count, NULL, 0.0);
1196 			}
1197 			last_running = running_count;
1198 		}
1199 
1200 		if (num_pfds == 0) {
1201 			if (running_count > 0)
1202 				usleep(10 * 1000);
1203 		} else {
1204 			int pret = poll(pfds, num_pfds, 100);
1205 
1206 			if (pret > 0) {
1207 				for (p = 0; p < num_pfds; p++) {
1208 					size_t idx = pfd_indices[p];
1209 
1210 					handle_child_pipe_activity(child_tests[idx],
1211 								   pfds[p].revents);
1212 				}
1213 			}
1214 		}
1215 
1216 		for (i = next_to_print; i < num_tests; i++) {
1217 			struct child_test *child = child_tests[i];
1218 
1219 			if (!child || child->done)
1220 				continue;
1221 
1222 			if (check_if_command_finished(&child->process)) {
1223 				if (child->process.err >= 0) {
1224 					drain_child_process_err(child);
1225 					close(child->process.err);
1226 					child->process.err = -1;
1227 				}
1228 				child->result = finish_command(&child->process);
1229 				child->process.pid = 0;
1230 				clock_gettime(CLOCK_MONOTONIC, &child->end_time);
1231 				child->done = true;
1232 			}
1233 		}
1234 
1235 		while (next_to_print < num_tests) {
1236 			struct child_test *child = child_tests[next_to_print];
1237 			double elapsed;
1238 
1239 			if (!child) {
1240 				next_to_print++;
1241 				continue;
1242 			}
1243 			if (!child->done)
1244 				break;
1245 
1246 			if (perf_use_color_default && last_running != -1) {
1247 				fprintf(debug_file(), PERF_COLOR_DELETE_LINE);
1248 				last_running = -1;
1249 			}
1250 
1251 			if (test_suite__num_test_cases(child->test) > 1 &&
1252 			    last_suite_printed != child->suite_num) {
1253 				pr_info("%3d: %-*.*s:\n", child->suite_num + 1,
1254 					width, width,
1255 					test_description(child->test, -1));
1256 				last_suite_printed = child->suite_num;
1257 			}
1258 
1259 			if (verbose > 1) {
1260 				if (test_suite__num_test_cases(child->test) > 1) {
1261 					pr_info("%3d.%1d: %s:\n", child->suite_num + 1,
1262 						child->test_case_num + 1,
1263 						test_description(child->test,
1264 								 child->test_case_num));
1265 				} else {
1266 					pr_info("%3d: %s:\n", child->suite_num + 1,
1267 						test_description(child->test, -1));
1268 				}
1269 			}
1270 
1271 			if (verbose > 1)
1272 				fprintf(stderr, "%s", child->err_output.buf);
1273 			else if (verbose == 1 && child->result == TEST_FAIL)
1274 				print_test_failure_snippet(stderr, child->err_output.buf);
1275 
1276 			elapsed = (child->end_time.tv_sec - child->start_time.tv_sec) +
1277 				  (child->end_time.tv_nsec -
1278 				   child->start_time.tv_nsec) / 1000000000.0;
1279 
1280 			print_test_result(child->test, child->suite_num, child->test_case_num,
1281 					  child->result, width, 0, child->err_output.buf, elapsed);
1282 			pthread_sigmask(SIG_BLOCK, &set, &oldset);
1283 			strbuf_release(&child->err_output);
1284 			child_tests[next_to_print] = NULL;
1285 			zfree(&child);
1286 			pthread_sigmask(SIG_SETMASK, &oldset, NULL);
1287 			next_to_print++;
1288 		}
1289 	}
1290 
1291 	pthread_sigmask(SIG_BLOCK, &set, &oldset);
1292 	free(global_pfds);
1293 	free(global_pfd_indices);
1294 	global_pfds = NULL;
1295 	global_pfd_indices = NULL;
1296 	pthread_sigmask(SIG_SETMASK, &oldset, NULL);
1297 	return 0;
1298 }
1299 
1300 static int start_test(struct test_suite *test, int curr_suite, int curr_test_case,
1301 		struct child_test **child, int width, int pass)
1302 {
1303 	int err;
1304 
1305 	*child = NULL;
1306 	if (dont_fork) {
1307 		if (pass == 1) {
1308 			struct timespec start_time, end_time;
1309 			double elapsed;
1310 
1311 			clock_gettime(CLOCK_MONOTONIC, &start_time);
1312 			pr_debug("--- start ---\n");
1313 			err = test_function(test, curr_test_case)(test, curr_test_case);
1314 			pr_debug("---- end ----\n");
1315 			clock_gettime(CLOCK_MONOTONIC, &end_time);
1316 			elapsed = (end_time.tv_sec - start_time.tv_sec) +
1317 				  (end_time.tv_nsec - start_time.tv_nsec) / 1000000000.0;
1318 			print_test_result(test, curr_suite, curr_test_case, err, width,
1319 					  /*running=*/0, NULL, elapsed);
1320 		}
1321 		return 0;
1322 	}
1323 	if (pass == 1 && !sequential && test_exclusive(test, curr_test_case)) {
1324 		/* When parallel, skip exclusive tests on the first pass. */
1325 		return 0;
1326 	}
1327 	if (pass != 1 && (sequential || !test_exclusive(test, curr_test_case))) {
1328 		/* Sequential and non-exclusive tests were run on the first pass. */
1329 		return 0;
1330 	}
1331 	*child = zalloc(sizeof(**child));
1332 	if (!*child)
1333 		return -ENOMEM;
1334 
1335 	(*child)->test = test;
1336 	(*child)->suite_num = curr_suite;
1337 	(*child)->test_case_num = curr_test_case;
1338 	(*child)->process.pid = -1;
1339 	(*child)->process.no_stdin = 1;
1340 	(*child)->process.in = -1;
1341 	(*child)->process.out = -1;
1342 	(*child)->process.err = -1;
1343 	if (verbose <= 0) {
1344 		(*child)->process.no_stdout = 1;
1345 		(*child)->process.no_stderr = 1;
1346 	} else {
1347 		(*child)->process.stdout_to_stderr = 1;
1348 	}
1349 	(*child)->process.no_exec_cmd = run_test_child;
1350 	if (sequential || pass == 2) {
1351 		err = start_command(&(*child)->process);
1352 		if (err)
1353 			return err;
1354 		finish_test(child, /*running_test=*/0, /*child_test_num=*/1, width);
1355 		return 0;
1356 	}
1357 	return start_command(&(*child)->process);
1358 }
1359 
1360 /* State outside of __cmd_test for the sake of the signal handler. */
1361 
1362 static size_t num_tests;
1363 static struct child_test **child_tests;
1364 static jmp_buf cmd_test_jmp_buf;
1365 
1366 static void cmd_test_sig_handler(int sig)
1367 {
1368 	siglongjmp(cmd_test_jmp_buf, sig);
1369 }
1370 
1371 static void print_tests_summary(void)
1372 {
1373 	pr_info("\n=== Test Summary ===\n");
1374 	pr_info("Passed main tests : %u\n", summary_tests_passed);
1375 	pr_info("Passed subtests   : %u\n", summary_subtests_passed);
1376 	pr_info("Skipped tests     : %u\n", summary_tests_skipped);
1377 	if (summary_tests_failed > 0) {
1378 		color_fprintf(debug_file(), PERF_COLOR_RED, "Failed tests      : %u\n",
1379 			      summary_tests_failed);
1380 		pr_info("List of failed tests:\n");
1381 		pr_info("%s", summary_failed_tests_buf.buf);
1382 	} else {
1383 		color_fprintf(debug_file(), PERF_COLOR_GREEN, "Failed tests      : 0\n");
1384 	}
1385 
1386 	if (junit_filename) {
1387 		int fd;
1388 		FILE *fp;
1389 
1390 		fd = open(junit_filename, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0644);
1391 		if (fd >= 0) {
1392 			fp = fdopen(fd, "w");
1393 			if (fp) {
1394 				unsigned int total = summary_tests_passed +
1395 						     summary_subtests_passed +
1396 						     summary_tests_skipped +
1397 						     summary_tests_failed;
1398 				fprintf(fp, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1399 				fprintf(fp, "<testsuites>\n");
1400 				fprintf(fp,
1401 					"  <testsuite name=\"perf-tests\" tests=\"%u\" failures=\"%u\" skipped=\"%u\">\n",
1402 					total, summary_tests_failed,
1403 					summary_tests_skipped);
1404 				fprintf(fp, "%s", junit_xml_buf.buf);
1405 				fprintf(fp, "  </testsuite>\n");
1406 				fprintf(fp, "</testsuites>\n");
1407 				fclose(fp);
1408 				pr_info("Wrote junit XML output to %s\n", junit_filename);
1409 			} else {
1410 				close(fd);
1411 				pr_err("Failed to associate stream with fd for %s: %s\n",
1412 				       junit_filename, strerror(errno));
1413 			}
1414 		} else {
1415 			pr_err("Failed to open %s for writing junit XML output: %s\n",
1416 			       junit_filename, strerror(errno));
1417 		}
1418 	}
1419 	strbuf_release(&junit_xml_buf);
1420 	strbuf_release(&summary_failed_tests_buf);
1421 }
1422 
1423 static int __cmd_test(struct test_suite **suites, int argc, const char *argv[],
1424 		      struct intlist *skiplist)
1425 {
1426 	static int width = 0;
1427 	int err = 0;
1428 
1429 	for (struct test_suite **t = suites; *t; t++) {
1430 		int i, len = strlen(test_description(*t, -1));
1431 
1432 		if (width < len)
1433 			width = len;
1434 
1435 		test_suite__for_each_test_case(*t, i) {
1436 			len = strlen(test_description(*t, i));
1437 			if (width < len)
1438 				width = len;
1439 			num_tests += runs_per_test;
1440 		}
1441 	}
1442 	child_tests = calloc(num_tests, sizeof(*child_tests));
1443 	if (!child_tests)
1444 		return -ENOMEM;
1445 
1446 	err = sigsetjmp(cmd_test_jmp_buf, 1);
1447 	if (err) {
1448 		pr_err("\nSignal (%d) while running tests.\nTerminating tests with the same signal\n",
1449 		       err);
1450 		for (size_t x = 0; x < num_tests; x++) {
1451 			struct child_test *child_test = child_tests[x];
1452 
1453 			if (!child_test || child_test->process.pid <= 0)
1454 				continue;
1455 
1456 			pr_debug3("Killing %d pid %d\n",
1457 				  child_test->suite_num + 1,
1458 				  child_test->process.pid);
1459 			kill(child_test->process.pid, err);
1460 		}
1461 		goto err_out;
1462 	}
1463 	signal(SIGINT, cmd_test_sig_handler);
1464 	signal(SIGTERM, cmd_test_sig_handler);
1465 
1466 	/*
1467 	 * In parallel mode pass 1 runs non-exclusive tests in parallel, pass 2
1468 	 * runs the exclusive tests sequentially. In other modes all tests are
1469 	 * run in pass 1.
1470 	 */
1471 	for (int pass = 1; pass <= 2; pass++) {
1472 		int child_test_num = 0;
1473 		int curr_suite = 0;
1474 
1475 		for (struct test_suite **t = suites; *t; t++, curr_suite++) {
1476 			int curr_test_case;
1477 			bool suite_matched = false;
1478 
1479 			if (!perf_test__matches(test_description(*t, -1), curr_suite, argc, argv)) {
1480 				/*
1481 				 * Test suite shouldn't be run based on
1482 				 * description. See if any test case should.
1483 				 */
1484 				bool skip = true;
1485 
1486 				test_suite__for_each_test_case(*t, curr_test_case) {
1487 					if (perf_test__matches(test_description(*t, curr_test_case),
1488 							       curr_suite, argc, argv)) {
1489 						skip = false;
1490 						break;
1491 					}
1492 				}
1493 				if (skip)
1494 					continue;
1495 			} else {
1496 				suite_matched = true;
1497 			}
1498 
1499 			if (intlist__find(skiplist, curr_suite + 1)) {
1500 				if (pass == 1) {
1501 					int pad_width = get_max_desc_width(width);
1502 					int term_width = get_term_width();
1503 
1504 					pr_info("%3d: %-*.*s:", curr_suite + 1,
1505 						pad_width, term_width,
1506 						test_description(*t, -1));
1507 					color_fprintf(debug_file(), PERF_COLOR_YELLOW,
1508 						      " Skip (user override)\n");
1509 					summary_tests_skipped++;
1510 					if (junit_filename) {
1511 						char *escaped_class =
1512 							xml_escape((const char *)
1513 								   test_description(*t, -1));
1514 						char *escaped_test = xml_escape("override");
1515 						char *escaped_reason =
1516 							xml_escape("user override");
1517 
1518 						strbuf_addf(&junit_xml_buf,
1519 							"    <testcase classname=\"%s\" name=\"%s\" time=\"0.000\">\n",
1520 							escaped_class, escaped_test);
1521 						strbuf_addf(&junit_xml_buf,
1522 							"      <skipped message=\"%s\"/>\n",
1523 							escaped_reason);
1524 						strbuf_addstr(&junit_xml_buf, "    </testcase>\n");
1525 						free(escaped_reason);
1526 						free(escaped_test);
1527 						free(escaped_class);
1528 					}
1529 				}
1530 				continue;
1531 			}
1532 
1533 			for (unsigned int run = 0; run < runs_per_test; run++) {
1534 				test_suite__for_each_test_case(*t, curr_test_case) {
1535 					if (!suite_matched &&
1536 					    !perf_test__matches(test_description(*t, curr_test_case),
1537 								curr_suite, argc, argv))
1538 						continue;
1539 					err = start_test(*t, curr_suite, curr_test_case,
1540 							 &child_tests[child_test_num++],
1541 							 width, pass);
1542 					if (err)
1543 						goto err_out;
1544 				}
1545 			}
1546 		}
1547 		if (!sequential) {
1548 			/* Parallel mode starts tests but doesn't finish them. Do that now. */
1549 			err = finish_tests_parallel(child_tests, num_tests, width);
1550 			if (err)
1551 				goto err_out;
1552 		}
1553 	}
1554 err_out:
1555 	signal(SIGINT, SIG_DFL);
1556 	signal(SIGTERM, SIG_DFL);
1557 	if (err) {
1558 		pr_err("Internal test harness failure. Completing any started tests:\n:");
1559 		for (size_t x = 0; x < num_tests; x++)
1560 			finish_test(child_tests, x, num_tests, width);
1561 	}
1562 	print_tests_summary();
1563 	free(global_pfds);
1564 	free(global_pfd_indices);
1565 	global_pfds = NULL;
1566 	global_pfd_indices = NULL;
1567 	free(child_tests);
1568 	return err;
1569 }
1570 
1571 static int perf_test__list(FILE *fp, struct test_suite **suites, int argc, const char **argv)
1572 {
1573 	int curr_suite = 0;
1574 
1575 	for (struct test_suite **t = suites; *t; t++, curr_suite++) {
1576 		int curr_test_case;
1577 
1578 		if (!perf_test__matches(test_description(*t, -1), curr_suite, argc, argv))
1579 			continue;
1580 
1581 		fprintf(fp, "%3d: %s", curr_suite + 1, test_description(*t, -1));
1582 		if (list_requisites)
1583 			requisites__fprintf(fp, *t, /*test_case=*/-1);
1584 		fprintf(fp, "\n");
1585 
1586 		if (test_suite__num_test_cases(*t) <= 1)
1587 			continue;
1588 
1589 		test_suite__for_each_test_case(*t, curr_test_case) {
1590 			fprintf(fp, "%3d.%1d: %s", curr_suite + 1, curr_test_case + 1,
1591 				test_description(*t, curr_test_case));
1592 			if (list_requisites)
1593 				requisites__fprintf(fp, *t, curr_test_case);
1594 			fprintf(fp, "\n");
1595 		}
1596 	}
1597 	return 0;
1598 }
1599 
1600 static int workloads__fprintf_list(FILE *fp)
1601 {
1602 	struct test_workload *twl;
1603 	int printed = 0;
1604 
1605 	workloads__for_each(twl)
1606 		printed += fprintf(fp, "%s\n", twl->name);
1607 
1608 	return printed;
1609 }
1610 
1611 static int perf_control_open_fifo(struct workload_control *ctl, const char *str)
1612 {
1613 	char *s, *p;
1614 	int ret;
1615 
1616 	if (strncmp(str, "fifo:", 5))
1617 		return -EINVAL;
1618 
1619 	str += 5;
1620 	if (!*str || *str == ',')
1621 		return -EINVAL;
1622 
1623 	s = strdup(str);
1624 	if (!s)
1625 		return -ENOMEM;
1626 
1627 	p = strchr(s, ',');
1628 	if (p)
1629 		*p = '\0';
1630 
1631 	ctl->ctl_fd = open(s, O_WRONLY | O_CLOEXEC);
1632 	if (ctl->ctl_fd < 0) {
1633 		ret = -errno;
1634 		pr_err("Failed to open workload control FIFO '%s': %m\n", s);
1635 		free(s);
1636 		return ret;
1637 	}
1638 
1639 	if (p && *++p) {
1640 		ctl->ack_fd = open(p, O_RDONLY | O_CLOEXEC);
1641 		if (ctl->ack_fd < 0) {
1642 			ret = -errno;
1643 			pr_err("Failed to open workload control ack FIFO '%s': %m\n", p);
1644 			close(ctl->ctl_fd);
1645 			ctl->ctl_fd = -1;
1646 			free(s);
1647 			return ret;
1648 		}
1649 	}
1650 
1651 	free(s);
1652 	return 0;
1653 }
1654 
1655 static int perf_control_open(struct workload_control *ctl)
1656 {
1657 	int ret;
1658 
1659 	if (!workload_control)
1660 		return 0;
1661 
1662 	ret = perf_control_open_fifo(ctl, workload_control);
1663 
1664 	if (ret == -EINVAL) {
1665 		pr_err("Unsupported workload control spec '%s', expected fifo:ctl-fifo[,ack-fifo]\n",
1666 			workload_control);
1667 	}
1668 
1669 	return ret;
1670 }
1671 
1672 static void perf_control_close(struct workload_control *ctl)
1673 {
1674 	if (ctl->ctl_fd >= 0) {
1675 		close(ctl->ctl_fd);
1676 		ctl->ctl_fd = -1;
1677 	}
1678 	if (ctl->ack_fd >= 0) {
1679 		close(ctl->ack_fd);
1680 		ctl->ack_fd = -1;
1681 	}
1682 }
1683 
1684 static int perf_control_write_cmd(int fd, const char *cmd)
1685 {
1686 	size_t len = strlen(cmd);
1687 	ssize_t ret;
1688 
1689 	while (len) {
1690 		ret = write(fd, cmd, len);
1691 		if (ret < 0) {
1692 			if (errno == EINTR)
1693 				continue;
1694 			pr_err("Failed to write perf control command: %m\n");
1695 			return -1;
1696 		}
1697 
1698 		if (!ret) {
1699 			pr_err("Failed to write perf control command: short write\n");
1700 			return -1;
1701 		}
1702 
1703 		cmd += ret;
1704 		len -= ret;
1705 	}
1706 
1707 	return 0;
1708 }
1709 
1710 static int perf_control_read_ack(int fd)
1711 {
1712 	char buf[16];
1713 	ssize_t ret;
1714 
1715 	do {
1716 		ret = read(fd, buf, sizeof(buf) - 1);
1717 	} while (ret < 0 && errno == EINTR);
1718 
1719 	if (ret < 0) {
1720 		pr_err("Failed to read perf control ack: %m\n");
1721 		return -1;
1722 	}
1723 
1724 	if (!ret) {
1725 		pr_err("Unexpected EOF while reading perf control ack\n");
1726 		return -1;
1727 	}
1728 
1729 	buf[ret] = '\0';
1730 	for (ssize_t i = 0; i < ret; i++) {
1731 		if (buf[i] == '\n' || buf[i] == '\0') {
1732 			buf[i] = '\0';
1733 			break;
1734 		}
1735 	}
1736 
1737 	if (strcmp(buf, "ack")) {
1738 		pr_err("Unexpected perf control ack: %s\n", buf);
1739 		return -1;
1740 	}
1741 
1742 	return 0;
1743 }
1744 
1745 static int perf_control_send(struct workload_control *ctl, const char *cmd)
1746 {
1747 	if (ctl->ctl_fd < 0)
1748 		return 0;
1749 
1750 	if (perf_control_write_cmd(ctl->ctl_fd, cmd))
1751 		return -1;
1752 
1753 	if (ctl->ack_fd >= 0 && perf_control_read_ack(ctl->ack_fd))
1754 		return -1;
1755 
1756 	return 0;
1757 }
1758 
1759 static int run_workload(const char *work, int argc, const char **argv)
1760 {
1761 	struct test_workload *twl;
1762 
1763 	workloads__for_each(twl) {
1764 		struct workload_control ctl = {
1765 			.ctl_fd = -1,
1766 			.ack_fd = -1,
1767 		};
1768 		int control_ret, ret;
1769 
1770 		if (strcmp(twl->name, work))
1771 			continue;
1772 
1773 		ret = perf_control_open(&ctl);
1774 		if (ret)
1775 			return ret;
1776 
1777 		if (perf_control_send(&ctl, "enable\n")) {
1778 			perf_control_close(&ctl);
1779 			return -1;
1780 		}
1781 
1782 		ret = twl->func(argc, argv);
1783 
1784 		control_ret = perf_control_send(&ctl, "disable\n");
1785 		perf_control_close(&ctl);
1786 		if (control_ret)
1787 			return -1;
1788 
1789 		return ret;
1790 	}
1791 
1792 	pr_info("No workload found: %s\n", work);
1793 	return -1;
1794 }
1795 
1796 /*
1797  * Owns the string test_objdump_path points at when it came from the config. It
1798  * is reachable for the lifetime of the process so leak checking won't report
1799  * it.
1800  */
1801 static char *test_objdump_config_path;
1802 
1803 static int perf_test__config(const char *var, const char *value,
1804 			     void *data __maybe_unused)
1805 {
1806 	if (!strcmp(var, "annotate.objdump")) {
1807 		/*
1808 		 * The config, and so value, is freed by perf_config__exit()
1809 		 * below, take a copy that lives as long as the tests.
1810 		 */
1811 		char *dup = strdup(value);
1812 
1813 		if (!dup)
1814 			return -ENOMEM;
1815 
1816 		free(test_objdump_config_path);
1817 		test_objdump_config_path = dup;
1818 		test_objdump_path = dup;
1819 	}
1820 
1821 	return 0;
1822 }
1823 
1824 static struct test_suite **build_suites(void)
1825 {
1826 	/*
1827 	 * TODO: suites is static to avoid needing to clean up the scripts tests
1828 	 * for leak sanitizer.
1829 	 */
1830 	static struct test_suite **suites[] = {
1831 		generic_tests,
1832 		arch_tests,
1833 		NULL,
1834 	};
1835 	struct test_suite **result;
1836 	struct test_suite *t;
1837 	size_t n = 0, num_suites = 0;
1838 
1839 	if (suites[2] == NULL)
1840 		suites[2] = create_script_test_suites();
1841 
1842 #define for_each_suite(suite)						\
1843 	for (size_t i = 0, j = 0; i < ARRAY_SIZE(suites); i++, j = 0)	\
1844 		while ((suite = suites[i][j++]) != NULL)
1845 
1846 	for_each_suite(t) {
1847 		if (t->setup) {
1848 			int ret = t->setup(t);
1849 
1850 			if (ret < 0) {
1851 				errno = -ret;
1852 				return NULL;
1853 			}
1854 		}
1855 		num_suites++;
1856 	}
1857 
1858 	result = calloc(num_suites + 1, sizeof(struct test_suite *));
1859 	if (!result)
1860 		return NULL;
1861 
1862 	for (int pass = 1; pass <= 2; pass++) {
1863 		for_each_suite(t) {
1864 			bool exclusive = false;
1865 			int curr_test_case;
1866 
1867 			test_suite__for_each_test_case(t, curr_test_case) {
1868 				if (test_exclusive(t, curr_test_case)) {
1869 					exclusive = true;
1870 					break;
1871 				}
1872 			}
1873 			if ((!exclusive && pass == 1) || (exclusive && pass == 2))
1874 				result[n++] = t;
1875 		}
1876 	}
1877 	return result;
1878 #undef for_each_suite
1879 }
1880 
1881 static bool perf_test__shares_mlock_budget(struct test_suite **suites, int argc,
1882 					   const char *argv[], struct intlist *skiplist)
1883 {
1884 	int sharing = 0;
1885 
1886 	/* The selection rules mirrored here are __cmd_test()'s: when they change, change both. */
1887 	for (int curr_suite = 0; suites[curr_suite]; curr_suite++) {
1888 		struct test_suite *t = suites[curr_suite];
1889 		int curr_test_case;
1890 		bool suite_matched;
1891 
1892 		if (!t->needs_mlock || intlist__find(skiplist, curr_suite + 1))
1893 			continue;
1894 
1895 		suite_matched = perf_test__matches(test_description(t, /*test_case=*/-1),
1896 						   curr_suite, argc, argv);
1897 		test_suite__for_each_test_case(t, curr_test_case) {
1898 			if (test_exclusive(t, curr_test_case))
1899 				continue;
1900 
1901 			if (suite_matched ||
1902 			    perf_test__matches(test_description(t, curr_test_case),
1903 					       curr_suite, argc, argv))
1904 				sharing += runs_per_test;
1905 		}
1906 		if (sharing > 1)
1907 			return true;
1908 	}
1909 	return false;
1910 }
1911 
1912 /*
1913  * Once the per user budget set in kernel.perf_event_mlock_kb is spent, what
1914  * maps on top of it is charged against RLIMIT_MEMLOCK and the mapping is
1915  * refused with EPERM when that runs out too, but only for the processes the
1916  * kernel is paranoid about and that have no CAP_IPC_LOCK to lift the check,
1917  * see perf_mmap_calc_limits() in the kernel: used by
1918  * perf_test__setup_mlock_budget() below, that has nothing to take turns on
1919  * when neither applies.
1920  */
1921 static bool perf_test__mlock_budget_exhaustible(void)
1922 {
1923 	if (perf_cap__capable(CAP_IPC_LOCK))
1924 		return false;
1925 
1926 	return perf_event_paranoid() > -1;
1927 }
1928 
1929 static void perf_test__setup_mlock_budget(struct test_suite **suites, int argc,
1930 					  const char *argv[], struct intlist *skiplist)
1931 {
1932 	/* Nothing can be denied the budget, nothing to take turns for. */
1933 	if (!perf_test__mlock_budget_exhaustible()) {
1934 		pr_debug("Not taking turns using the perf mlock budget: nothing can exhaust it\n");
1935 		return;
1936 	}
1937 
1938 	/* Nothing runs at the same time, nothing to share the budget with. */
1939 	if (sequential || !perf_test__shares_mlock_budget(suites, argc, argv, skiplist))
1940 		return;
1941 
1942 	mlock_budget = mmap(NULL, sizeof(*mlock_budget), PROT_READ | PROT_WRITE,
1943 			    MAP_SHARED | MAP_ANONYMOUS, /*fd=*/-1, /*offset=*/0);
1944 	if (mlock_budget == MAP_FAILED) {
1945 		mlock_budget = NULL;
1946 		pr_err("Failed to map the shared area used to take turns using the perf mlock budget\n");
1947 		return;
1948 	}
1949 
1950 	if (!mutex_init_pshared_robust(&mlock_budget->lock)) {
1951 		munmap(mlock_budget, sizeof(*mlock_budget));
1952 		mlock_budget = NULL;
1953 		pr_debug("Not taking turns using the perf mlock budget\n");
1954 	}
1955 }
1956 
1957 static void perf_test__teardown_mlock_budget(void)
1958 {
1959 	if (!mlock_budget)
1960 		return;
1961 
1962 	mutex_destroy(&mlock_budget->lock);
1963 	munmap(mlock_budget, sizeof(*mlock_budget));
1964 	mlock_budget = NULL;
1965 }
1966 
1967 int cmd_test(int argc, const char **argv)
1968 {
1969 	const char *test_usage[] = {
1970 	"perf test [<options>] [{list|requisites} [<test-name-fragment>]|"
1971 	"[<test-name-fragments>|<test-numbers>]]",
1972 	NULL,
1973 	};
1974 	const char *skip = NULL;
1975 	const char *workload = NULL;
1976 	bool list_workloads = false;
1977 	const struct option test_options[] = {
1978 	OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
1979 	OPT_INCR('v', "verbose", &verbose,
1980 		    "be more verbose (show symbol address, etc)"),
1981 	OPT_BOOLEAN('F', "dont-fork", &dont_fork,
1982 		    "Do not fork for testcase"),
1983 	OPT_BOOLEAN('S', "sequential", &sequential,
1984 		    "Run the tests one after another rather than in parallel"),
1985 	OPT_UINTEGER('r', "runs-per-test", &runs_per_test,
1986 		     "Run each test the given number of times, default 1"),
1987 	OPT_STRING('w', "workload", &workload, "work", "workload to run for testing, use '--list-workloads' to list the available ones."),
1988 	OPT_STRING(0, "record-ctl", &workload_control, "fifo:ctl-fifo[,ack-fifo]",
1989 		   "Write enable to the fifo just before running the workload and disable after, with optional ack from ack-fifo"),
1990 	OPT_BOOLEAN(0, "list-workloads", &list_workloads, "List the available builtin workloads to use with -w/--workload"),
1991 	OPT_STRING(0, "dso", &dso_to_test, "dso", "dso to test"),
1992 	OPT_STRING(0, "objdump", &test_objdump_path, "path",
1993 		   "objdump binary to use for disassembly and annotations"),
1994 	OPT_UINTEGER(0, "failure-snippet-lines", &failure_snippet_lines,
1995 		     "Number of lines to include in failure snippet, default 10"),
1996 	OPT_STRING_OPTARG('j', "junit", &junit_filename, "file",
1997 			  "Generate junit XML output, default test.xml", "test.xml"),
1998 	OPT_END()
1999 	};
2000 	const char * const test_subcommands[] = { "list", "requisites", NULL };
2001 	struct intlist *skiplist = NULL;
2002 	struct test_suite **suites;
2003 	int ret;
2004 
2005 	ret = hists__init();
2006 	if (ret < 0)
2007                 return ret;
2008 
2009 	/* Read test related config, like annotate.objdump, before isolating. */
2010 	ret = perf_config(perf_test__config, NULL);
2011 	if (ret < 0)
2012 		return ret;
2013 
2014 	/*
2015 	 * Isolate the test suite from the user's ~/.perfconfig to ensure
2016 	 * behavior isn't impacted by custom variables (e.g. core.hybrid-merge).
2017 	 * Setting PERF_CONFIG isolates the perf commands run by the shell
2018 	 * tests, config_exclusive_filename does the same for this process.
2019 	 * Config values already read by main's perf_config are reset here, so
2020 	 * far only the hybrid-merge value is known to alter test output.
2021 	 */
2022 	if (setenv("PERF_CONFIG", "/dev/null", 1) < 0)
2023 		return -1;
2024 	config_exclusive_filename = "/dev/null";
2025 	perf_config__exit();
2026 	symbol_conf.hybrid_merge = false;
2027 
2028 	/* Unbuffered output */
2029 	setvbuf(stdout, NULL, _IONBF, 0);
2030 
2031 	argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0);
2032 	if (argc >= 1 && (!strcmp(argv[0], "list") || !strcmp(argv[0], "requisites"))) {
2033 		suites = build_suites();
2034 		if (!suites)
2035 			return errno ? -errno : -ENOMEM;
2036 		list_requisites = !strcmp(argv[0], "requisites");
2037 		ret = perf_test__list(stdout, suites, argc - 1, argv + 1);
2038 		free(suites);
2039 		return ret;
2040 	}
2041 
2042 	if (workload)
2043 		return run_workload(workload, argc, argv);
2044 
2045 	if (list_workloads) {
2046 		workloads__fprintf_list(stdout);
2047 		return 0;
2048 	}
2049 
2050 	if (dont_fork)
2051 		sequential = true;
2052 
2053 	symbol_conf.priv_size = sizeof(int);
2054 	symbol_conf.try_vmlinux_path = true;
2055 
2056 
2057 	if (symbol__init(NULL) < 0)
2058 		return -1;
2059 
2060 	if (skip != NULL)
2061 		skiplist = intlist__new(skip);
2062 	/*
2063 	 * Tests that create BPF maps, for instance, need more than the 64K
2064 	 * default:
2065 	 */
2066 	rlimit__bump_memlock();
2067 
2068 	suites = build_suites();
2069 	if (!suites) {
2070 		int err = errno;
2071 
2072 		intlist__delete(skiplist);
2073 		return err ? -err : -ENOMEM;
2074 	}
2075 	perf_test__setup_mlock_budget(suites, argc, argv, skiplist);
2076 	ret = __cmd_test(suites, argc, argv, skiplist);
2077 	perf_test__teardown_mlock_budget();
2078 	free(suites);
2079 	intlist__delete(skiplist);
2080 	return ret;
2081 }
2082