File Index
Files and directories
Sign in
FILE

fp-stress.c

File preview with syntax highlighting.

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