xref: /openbmc/linux/tools/testing/selftests/arm64/fp/fp-stress.c (revision 8ef9ea1503d0a129cc6f5cf48fb63633efa5d766)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2022 ARM Limited.
4  */
5 
6 #define _GNU_SOURCE
7 #define _POSIX_C_SOURCE 199309L
8 
9 #include <errno.h>
10 #include <getopt.h>
11 #include <poll.h>
12 #include <signal.h>
13 #include <stdbool.h>
14 #include <stddef.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <sys/auxv.h>
20 #include <sys/epoll.h>
21 #include <sys/prctl.h>
22 #include <sys/types.h>
23 #include <sys/uio.h>
24 #include <sys/wait.h>
25 #include <asm/hwcap.h>
26 
27 #include "../../kselftest.h"
28 
29 #define MAX_VLS 16
30 
31 struct child_data {
32 	char *name, *output;
33 	pid_t pid;
34 	int stdout;
35 	bool output_seen;
36 	bool exited;
37 	int exit_status;
38 };
39 
40 static int epoll_fd;
41 static struct child_data *children;
42 static struct epoll_event *evs;
43 static int tests;
44 static int num_children;
45 static bool terminate;
46 
47 static int startup_pipe[2];
48 
49 static int num_processors(void)
50 {
51 	long nproc = sysconf(_SC_NPROCESSORS_CONF);
52 	if (nproc < 0) {
53 		perror("Unable to read number of processors\n");
54 		exit(EXIT_FAILURE);
55 	}
56 
57 	return nproc;
58 }
59 
60 static void child_start(struct child_data *child, const char *program)
61 {
62 	int ret, pipefd[2], i;
63 	struct epoll_event ev;
64 
65 	ret = pipe(pipefd);
66 	if (ret != 0)
67 		ksft_exit_fail_msg("Failed to create stdout pipe: %s (%d)\n",
68 				   strerror(errno), errno);
69 
70 	child->pid = fork();
71 	if (child->pid == -1)
72 		ksft_exit_fail_msg("fork() failed: %s (%d)\n",
73 				   strerror(errno), errno);
74 
75 	if (!child->pid) {
76 		/*
77 		 * In child, replace stdout with the pipe, errors to
78 		 * stderr from here as kselftest prints to stdout.
79 		 */
80 		ret = dup2(pipefd[1], 1);
81 		if (ret == -1) {
82 			printf("dup2() %d\n", errno);
83 			exit(EXIT_FAILURE);
84 		}
85 
86 		/*
87 		 * Duplicate the read side of the startup pipe to
88 		 * FD 3 so we can close everything else.
89 		 */
90 		ret = dup2(startup_pipe[0], 3);
91 		if (ret == -1) {
92 			printf("dup2() %d\n", errno);
93 			exit(EXIT_FAILURE);
94 		}
95 
96 		/*
97 		 * Very dumb mechanism to clean open FDs other than
98 		 * stdio. We don't want O_CLOEXEC for the pipes...
99 		 */
100 		for (i = 4; i < 8192; i++)
101 			close(i);
102 
103 		/*
104 		 * Read from the startup pipe, there should be no data
105 		 * and we should block until it is closed.  We just
106 		 * carry on on error since this isn't super critical.
107 		 */
108 		ret = read(3, &i, sizeof(i));
109 		if (ret < 0)
110 			printf("read(startp pipe) failed: %s (%d)\n",
111 			       strerror(errno), errno);
112 		if (ret > 0)
113 			printf("%d bytes of data on startup pipe\n", ret);
114 		close(3);
115 
116 		ret = execl(program, program, NULL);
117 		printf("execl(%s) failed: %d (%s)\n",
118 		       program, errno, strerror(errno));
119 
120 		exit(EXIT_FAILURE);
121 	} else {
122 		/*
123 		 * In parent, remember the child and close our copy of the
124 		 * write side of stdout.
125 		 */
126 		close(pipefd[1]);
127 		child->stdout = pipefd[0];
128 		child->output = NULL;
129 		child->exited = false;
130 		child->output_seen = false;
131 
132 		ev.events = EPOLLIN | EPOLLHUP;
133 		ev.data.ptr = child;
134 
135 		ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, child->stdout, &ev);
136 		if (ret < 0) {
137 			ksft_exit_fail_msg("%s EPOLL_CTL_ADD failed: %s (%d)\n",
138 					   child->name, strerror(errno), errno);
139 		}
140 	}
141 }
142 
143 static bool child_output_read(struct child_data *child)
144 {
145 	char read_data[1024];
146 	char work[1024];
147 	int ret, len, cur_work, cur_read;
148 
149 	ret = read(child->stdout, read_data, sizeof(read_data));
150 	if (ret < 0) {
151 		if (errno == EINTR)
152 			return true;
153 
154 		ksft_print_msg("%s: read() failed: %s (%d)\n",
155 			       child->name, strerror(errno),
156 			       errno);
157 		return false;
158 	}
159 	len = ret;
160 
161 	child->output_seen = true;
162 
163 	/* Pick up any partial read */
164 	if (child->output) {
165 		strncpy(work, child->output, sizeof(work) - 1);
166 		cur_work = strnlen(work, sizeof(work));
167 		free(child->output);
168 		child->output = NULL;
169 	} else {
170 		cur_work = 0;
171 	}
172 
173 	cur_read = 0;
174 	while (cur_read < len) {
175 		work[cur_work] = read_data[cur_read++];
176 
177 		if (work[cur_work] == '\n') {
178 			work[cur_work] = '\0';
179 			ksft_print_msg("%s: %s\n", child->name, work);
180 			cur_work = 0;
181 		} else {
182 			cur_work++;
183 		}
184 	}
185 
186 	if (cur_work) {
187 		work[cur_work] = '\0';
188 		ret = asprintf(&child->output, "%s", work);
189 		if (ret == -1)
190 			ksft_exit_fail_msg("Out of memory\n");
191 	}
192 
193 	return false;
194 }
195 
196 static void child_output(struct child_data *child, uint32_t events,
197 			 bool flush)
198 {
199 	bool read_more;
200 
201 	if (events & EPOLLIN) {
202 		do {
203 			read_more = child_output_read(child);
204 		} while (read_more);
205 	}
206 
207 	if (events & EPOLLHUP) {
208 		close(child->stdout);
209 		child->stdout = -1;
210 		flush = true;
211 	}
212 
213 	if (flush && child->output) {
214 		ksft_print_msg("%s: %s<EOF>\n", child->name, child->output);
215 		free(child->output);
216 		child->output = NULL;
217 	}
218 }
219 
220 static void child_tickle(struct child_data *child)
221 {
222 	if (child->output_seen && !child->exited)
223 		kill(child->pid, SIGUSR2);
224 }
225 
226 static void child_stop(struct child_data *child)
227 {
228 	if (!child->exited)
229 		kill(child->pid, SIGTERM);
230 }
231 
232 static void child_cleanup(struct child_data *child)
233 {
234 	pid_t ret;
235 	int status;
236 	bool fail = false;
237 
238 	if (!child->exited) {
239 		do {
240 			ret = waitpid(child->pid, &status, 0);
241 			if (ret == -1 && errno == EINTR)
242 				continue;
243 
244 			if (ret == -1) {
245 				ksft_print_msg("waitpid(%d) failed: %s (%d)\n",
246 					       child->pid, strerror(errno),
247 					       errno);
248 				fail = true;
249 				break;
250 			}
251 		} while (!WIFEXITED(status));
252 		child->exit_status = WEXITSTATUS(status);
253 	}
254 
255 	if (!child->output_seen) {
256 		ksft_print_msg("%s no output seen\n", child->name);
257 		fail = true;
258 	}
259 
260 	if (child->exit_status != 0) {
261 		ksft_print_msg("%s exited with error code %d\n",
262 			       child->name, child->exit_status);
263 		fail = true;
264 	}
265 
266 	ksft_test_result(!fail, "%s\n", child->name);
267 }
268 
269 static void handle_child_signal(int sig, siginfo_t *info, void *context)
270 {
271 	int i;
272 	bool found = false;
273 
274 	for (i = 0; i < num_children; i++) {
275 		if (children[i].pid == info->si_pid) {
276 			children[i].exited = true;
277 			children[i].exit_status = info->si_status;
278 			found = true;
279 			break;
280 		}
281 	}
282 
283 	if (!found)
284 		ksft_print_msg("SIGCHLD for unknown PID %d with status %d\n",
285 			       info->si_pid, info->si_status);
286 }
287 
288 static void handle_exit_signal(int sig, siginfo_t *info, void *context)
289 {
290 	int i;
291 
292 	/* If we're already exiting then don't signal again */
293 	if (terminate)
294 		return;
295 
296 	ksft_print_msg("Got signal, exiting...\n");
297 
298 	terminate = true;
299 
300 	/*
301 	 * This should be redundant, the main loop should clean up
302 	 * after us, but for safety stop everything we can here.
303 	 */
304 	for (i = 0; i < num_children; i++)
305 		child_stop(&children[i]);
306 }
307 
308 static void start_fpsimd(struct child_data *child, int cpu, int copy)
309 {
310 	int ret;
311 
312 	ret = asprintf(&child->name, "FPSIMD-%d-%d", cpu, copy);
313 	if (ret == -1)
314 		ksft_exit_fail_msg("asprintf() failed\n");
315 
316 	child_start(child, "./fpsimd-test");
317 
318 	ksft_print_msg("Started %s\n", child->name);
319 }
320 
321 static void start_sve(struct child_data *child, int vl, int cpu)
322 {
323 	int ret;
324 
325 	ret = prctl(PR_SVE_SET_VL, vl | PR_SVE_VL_INHERIT);
326 	if (ret < 0)
327 		ksft_exit_fail_msg("Failed to set SVE VL %d\n", vl);
328 
329 	ret = asprintf(&child->name, "SVE-VL-%d-%d", vl, cpu);
330 	if (ret == -1)
331 		ksft_exit_fail_msg("asprintf() failed\n");
332 
333 	child_start(child, "./sve-test");
334 
335 	ksft_print_msg("Started %s\n", child->name);
336 }
337 
338 static void start_ssve(struct child_data *child, int vl, int cpu)
339 {
340 	int ret;
341 
342 	ret = asprintf(&child->name, "SSVE-VL-%d-%d", vl, cpu);
343 	if (ret == -1)
344 		ksft_exit_fail_msg("asprintf() failed\n");
345 
346 	ret = prctl(PR_SME_SET_VL, vl | PR_SME_VL_INHERIT);
347 	if (ret < 0)
348 		ksft_exit_fail_msg("Failed to set SME VL %d\n", ret);
349 
350 	child_start(child, "./ssve-test");
351 
352 	ksft_print_msg("Started %s\n", child->name);
353 }
354 
355 static void start_za(struct child_data *child, int vl, int cpu)
356 {
357 	int ret;
358 
359 	ret = prctl(PR_SME_SET_VL, vl | PR_SVE_VL_INHERIT);
360 	if (ret < 0)
361 		ksft_exit_fail_msg("Failed to set SME VL %d\n", ret);
362 
363 	ret = asprintf(&child->name, "ZA-VL-%d-%d", vl, cpu);
364 	if (ret == -1)
365 		ksft_exit_fail_msg("asprintf() failed\n");
366 
367 	child_start(child, "./za-test");
368 
369 	ksft_print_msg("Started %s\n", child->name);
370 }
371 
372 static void start_zt(struct child_data *child, int cpu)
373 {
374 	int ret;
375 
376 	ret = asprintf(&child->name, "ZT-%d", cpu);
377 	if (ret == -1)
378 		ksft_exit_fail_msg("asprintf() failed\n");
379 
380 	child_start(child, "./zt-test");
381 
382 	ksft_print_msg("Started %s\n", child->name);
383 }
384 
385 static void probe_vls(int vls[], int *vl_count, int set_vl)
386 {
387 	unsigned int vq;
388 	int vl;
389 
390 	*vl_count = 0;
391 
392 	for (vq = SVE_VQ_MAX; vq > 0; vq /= 2) {
393 		vl = prctl(set_vl, vq * 16);
394 		if (vl == -1)
395 			ksft_exit_fail_msg("SET_VL failed: %s (%d)\n",
396 					   strerror(errno), errno);
397 
398 		vl &= PR_SVE_VL_LEN_MASK;
399 
400 		if (*vl_count && (vl == vls[*vl_count - 1]))
401 			break;
402 
403 		vq = sve_vq_from_vl(vl);
404 
405 		vls[*vl_count] = vl;
406 		*vl_count += 1;
407 	}
408 }
409 
410 /* Handle any pending output without blocking */
411 static void drain_output(bool flush)
412 {
413 	int ret = 1;
414 	int i;
415 
416 	while (ret > 0) {
417 		ret = epoll_wait(epoll_fd, evs, tests, 0);
418 		if (ret < 0) {
419 			if (errno == EINTR)
420 				continue;
421 			ksft_print_msg("epoll_wait() failed: %s (%d)\n",
422 				       strerror(errno), errno);
423 		}
424 
425 		for (i = 0; i < ret; i++)
426 			child_output(evs[i].data.ptr, evs[i].events, flush);
427 	}
428 }
429 
430 static const struct option options[] = {
431 	{ "timeout",	required_argument, NULL, 't' },
432 	{ }
433 };
434 
435 int main(int argc, char **argv)
436 {
437 	int ret;
438 	int timeout = 10;
439 	int cpus, i, j, c;
440 	int sve_vl_count, sme_vl_count, fpsimd_per_cpu;
441 	bool all_children_started = false;
442 	int seen_children;
443 	int sve_vls[MAX_VLS], sme_vls[MAX_VLS];
444 	bool have_sme2;
445 	struct sigaction sa;
446 
447 	while ((c = getopt_long(argc, argv, "t:", options, NULL)) != -1) {
448 		switch (c) {
449 		case 't':
450 			ret = sscanf(optarg, "%d", &timeout);
451 			if (ret != 1)
452 				ksft_exit_fail_msg("Failed to parse timeout %s\n",
453 						   optarg);
454 			break;
455 		default:
456 			ksft_exit_fail_msg("Unknown argument\n");
457 		}
458 	}
459 
460 	cpus = num_processors();
461 	tests = 0;
462 
463 	if (getauxval(AT_HWCAP) & HWCAP_SVE) {
464 		probe_vls(sve_vls, &sve_vl_count, PR_SVE_SET_VL);
465 		tests += sve_vl_count * cpus;
466 	} else {
467 		sve_vl_count = 0;
468 	}
469 
470 	if (getauxval(AT_HWCAP2) & HWCAP2_SME) {
471 		probe_vls(sme_vls, &sme_vl_count, PR_SME_SET_VL);
472 		tests += sme_vl_count * cpus * 2;
473 	} else {
474 		sme_vl_count = 0;
475 	}
476 
477 	if (getauxval(AT_HWCAP2) & HWCAP2_SME2) {
478 		tests += cpus;
479 		have_sme2 = true;
480 	} else {
481 		have_sme2 = false;
482 	}
483 
484 	/* Force context switching if we only have FPSIMD */
485 	if (!sve_vl_count && !sme_vl_count)
486 		fpsimd_per_cpu = 2;
487 	else
488 		fpsimd_per_cpu = 1;
489 	tests += cpus * fpsimd_per_cpu;
490 
491 	ksft_print_header();
492 	ksft_set_plan(tests);
493 
494 	ksft_print_msg("%d CPUs, %d SVE VLs, %d SME VLs, SME2 %s\n",
495 		       cpus, sve_vl_count, sme_vl_count,
496 		       have_sme2 ? "present" : "absent");
497 
498 	if (timeout > 0)
499 		ksft_print_msg("Will run for %ds\n", timeout);
500 	else
501 		ksft_print_msg("Will run until terminated\n");
502 
503 	children = calloc(sizeof(*children), tests);
504 	if (!children)
505 		ksft_exit_fail_msg("Unable to allocate child data\n");
506 
507 	ret = epoll_create1(EPOLL_CLOEXEC);
508 	if (ret < 0)
509 		ksft_exit_fail_msg("epoll_create1() failed: %s (%d)\n",
510 				   strerror(errno), ret);
511 	epoll_fd = ret;
512 
513 	/* Create a pipe which children will block on before execing */
514 	ret = pipe(startup_pipe);
515 	if (ret != 0)
516 		ksft_exit_fail_msg("Failed to create startup pipe: %s (%d)\n",
517 				   strerror(errno), errno);
518 
519 	/* Get signal handers ready before we start any children */
520 	memset(&sa, 0, sizeof(sa));
521 	sa.sa_sigaction = handle_exit_signal;
522 	sa.sa_flags = SA_RESTART | SA_SIGINFO;
523 	sigemptyset(&sa.sa_mask);
524 	ret = sigaction(SIGINT, &sa, NULL);
525 	if (ret < 0)
526 		ksft_print_msg("Failed to install SIGINT handler: %s (%d)\n",
527 			       strerror(errno), errno);
528 	ret = sigaction(SIGTERM, &sa, NULL);
529 	if (ret < 0)
530 		ksft_print_msg("Failed to install SIGTERM handler: %s (%d)\n",
531 			       strerror(errno), errno);
532 	sa.sa_sigaction = handle_child_signal;
533 	ret = sigaction(SIGCHLD, &sa, NULL);
534 	if (ret < 0)
535 		ksft_print_msg("Failed to install SIGCHLD handler: %s (%d)\n",
536 			       strerror(errno), errno);
537 
538 	evs = calloc(tests, sizeof(*evs));
539 	if (!evs)
540 		ksft_exit_fail_msg("Failed to allocated %d epoll events\n",
541 				   tests);
542 
543 	for (i = 0; i < cpus; i++) {
544 		for (j = 0; j < fpsimd_per_cpu; j++)
545 			start_fpsimd(&children[num_children++], i, j);
546 
547 		for (j = 0; j < sve_vl_count; j++)
548 			start_sve(&children[num_children++], sve_vls[j], i);
549 
550 		for (j = 0; j < sme_vl_count; j++) {
551 			start_ssve(&children[num_children++], sme_vls[j], i);
552 			start_za(&children[num_children++], sme_vls[j], i);
553 		}
554 
555 		if (have_sme2)
556 			start_zt(&children[num_children++], i);
557 	}
558 
559 	/*
560 	 * All children started, close the startup pipe and let them
561 	 * run.
562 	 */
563 	close(startup_pipe[0]);
564 	close(startup_pipe[1]);
565 
566 	for (;;) {
567 		/* Did we get a signal asking us to exit? */
568 		if (terminate)
569 			break;
570 
571 		/*
572 		 * Timeout is counted in seconds with no output, the
573 		 * tests print during startup then are silent when
574 		 * running so this should ensure they all ran enough
575 		 * to install the signal handler, this is especially
576 		 * useful in emulation where we will both be slow and
577 		 * likely to have a large set of VLs.
578 		 */
579 		ret = epoll_wait(epoll_fd, evs, tests, 1000);
580 		if (ret < 0) {
581 			if (errno == EINTR)
582 				continue;
583 			ksft_exit_fail_msg("epoll_wait() failed: %s (%d)\n",
584 					   strerror(errno), errno);
585 		}
586 
587 		/* Output? */
588 		if (ret > 0) {
589 			for (i = 0; i < ret; i++) {
590 				child_output(evs[i].data.ptr, evs[i].events,
591 					     false);
592 			}
593 			continue;
594 		}
595 
596 		/* Otherwise epoll_wait() timed out */
597 
598 		/*
599 		 * If the child processes have not produced output they
600 		 * aren't actually running the tests yet .
601 		 */
602 		if (!all_children_started) {
603 			seen_children = 0;
604 
605 			for (i = 0; i < num_children; i++)
606 				if (children[i].output_seen ||
607 				    children[i].exited)
608 					seen_children++;
609 
610 			if (seen_children != num_children) {
611 				ksft_print_msg("Waiting for %d children\n",
612 					       num_children - seen_children);
613 				continue;
614 			}
615 
616 			all_children_started = true;
617 		}
618 
619 		ksft_print_msg("Sending signals, timeout remaining: %d\n",
620 			       timeout);
621 
622 		for (i = 0; i < num_children; i++)
623 			child_tickle(&children[i]);
624 
625 		/* Negative timeout means run indefinitely */
626 		if (timeout < 0)
627 			continue;
628 		if (--timeout == 0)
629 			break;
630 	}
631 
632 	ksft_print_msg("Finishing up...\n");
633 	terminate = true;
634 
635 	for (i = 0; i < tests; i++)
636 		child_stop(&children[i]);
637 
638 	drain_output(false);
639 
640 	for (i = 0; i < tests; i++)
641 		child_cleanup(&children[i]);
642 
643 	drain_output(true);
644 
645 	ksft_print_cnts();
646 
647 	return 0;
648 }
649