staticint num_processors(void)
{ long nproc = sysconf(_SC_NPROCESSORS_CONF); if (nproc < 0) {
perror("Unable to read number of processors\n"); exit(EXIT_FAILURE);
}
if (!child->pid) { /* * In child, replace stdout with the pipe, errors to * stderr from here as kselftest prints to stdout.
*/
ret = dup2(pipefd[1], 1); if (ret == -1) {
printf("dup2() %d\n", errno); exit(EXIT_FAILURE);
}
/* * Duplicate the read side of the startup pipe to * FD 3 so we can close everything else.
*/
ret = dup2(startup_pipe[0], 3); if (ret == -1) {
printf("dup2() %d\n", errno); exit(EXIT_FAILURE);
}
/* * Very dumb mechanism to clean open FDs other than * stdio. We don't want O_CLOEXEC for the pipes...
*/ for (i = 4; i < 8192; i++)
close(i);
/* * Read from the startup pipe, there should be no data * and we should block until it is closed. We just * carry on on error since this isn't super critical.
*/
ret = read(3, &i, sizeof(i)); if (ret < 0)
printf("read(startp pipe) failed: %s (%d)\n",
strerror(errno), errno); if (ret > 0)
printf("%d bytes of data on startup pipe\n", ret);
close(3);
exit(EXIT_FAILURE);
} else { /* * In parent, remember the child and close our copy of the * write side of stdout.
*/
close(pipefd[1]);
child->stdout = pipefd[0];
child->output = NULL;
child->exited = false;
child->output_seen = false;
if (!child->output_seen) {
ksft_print_msg("%s no output seen\n", child->name);
fail = true;
}
if (child->exit_status != 0) {
ksft_print_msg("%s exited with error code %d\n",
child->name, child->exit_status);
fail = true;
}
ksft_test_result(!fail, "%s\n", child->name);
}
staticvoid handle_child_signal(int sig, siginfo_t *info, void *context)
{ int i; bool found = false;
for (i = 0; i < num_children; i++) { if (children[i].pid == info->si_pid) {
children[i].exited = true;
children[i].exit_status = info->si_status;
found = true; break;
}
}
if (!found)
ksft_print_msg("SIGCHLD for unknown PID %d with status %d\n",
info->si_pid, info->si_status);
}
staticvoid handle_exit_signal(int sig, siginfo_t *info, void *context)
{ int i;
/* If we're already exiting then don't signal again */ if (terminate) return;
ksft_print_msg("Got signal, exiting...\n");
terminate = true;
/* * This should be redundant, the main loop should clean up * after us, but for safety stop everything we can here.
*/ for (i = 0; i < num_children; i++)
child_stop(&children[i]);
}
staticvoid start_fpsimd(struct child_data *child, int cpu, int copy)
{ int ret;
ret = asprintf(&child->name, "FPSIMD-%d-%d", cpu, copy); if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n");
child_start(child, "./fpsimd-test");
ksft_print_msg("Started %s\n", child->name);
}
staticvoid start_kernel(struct child_data *child, int cpu, int copy)
{ int ret;
ret = asprintf(&child->name, "KERNEL-%d-%d", cpu, copy); if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n");
child_start(child, "./kernel-test");
ksft_print_msg("Started %s\n", child->name);
}
staticvoid start_sve(struct child_data *child, int vl, int cpu)
{ int ret;
ret = prctl(PR_SVE_SET_VL, vl | PR_SVE_VL_INHERIT); if (ret < 0)
ksft_exit_fail_msg("Failed to set SVE VL %d\n", vl);
ret = asprintf(&child->name, "SVE-VL-%d-%d", vl, cpu); if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n");
child_start(child, "./sve-test");
ksft_print_msg("Started %s\n", child->name);
}
staticvoid start_ssve(struct child_data *child, int vl, int cpu)
{ int ret;
ret = asprintf(&child->name, "SSVE-VL-%d-%d", vl, cpu); if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n");
ret = prctl(PR_SME_SET_VL, vl | PR_SME_VL_INHERIT); if (ret < 0)
ksft_exit_fail_msg("Failed to set SME VL %d\n", ret);
child_start(child, "./ssve-test");
ksft_print_msg("Started %s\n", child->name);
}
staticvoid start_za(struct child_data *child, int vl, int cpu)
{ int ret;
ret = prctl(PR_SME_SET_VL, vl | PR_SVE_VL_INHERIT); if (ret < 0)
ksft_exit_fail_msg("Failed to set SME VL %d\n", ret);
ret = asprintf(&child->name, "ZA-VL-%d-%d", vl, cpu); if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n");
child_start(child, "./za-test");
ksft_print_msg("Started %s\n", child->name);
}
staticvoid start_zt(struct child_data *child, int cpu)
{ int ret;
ret = asprintf(&child->name, "ZT-%d", cpu); if (ret == -1)
ksft_exit_fail_msg("asprintf() failed\n");
child_start(child, "./zt-test");
ksft_print_msg("Started %s\n", child->name);
}
staticvoid probe_vls(int vls[], int *vl_count, int set_vl)
{ unsignedint vq; int vl;
int main(int argc, char **argv)
{ int ret; int timeout = 10 * (1000 / SIGNAL_INTERVAL_MS); int poll_interval = 5000; int cpus, i, j, c; int sve_vl_count, sme_vl_count; bool all_children_started = false; int seen_children; int sve_vls[MAX_VLS], sme_vls[MAX_VLS]; bool have_sme2; struct sigaction sa;
while ((c = getopt_long(argc, argv, "t:", options, NULL)) != -1) { switch (c) { case't':
ret = sscanf(optarg, "%d", &timeout); if (ret != 1)
ksft_exit_fail_msg("Failed to parse timeout %s\n",
optarg); break; default:
ksft_exit_fail_msg("Unknown argument\n");
}
}
ksft_print_msg("%d CPUs, %d SVE VLs, %d SME VLs, SME2 %s\n",
cpus, sve_vl_count, sme_vl_count,
have_sme2 ? "present" : "absent");
if (timeout > 0)
ksft_print_msg("Will run for %d\n", timeout); else
ksft_print_msg("Will run until terminated\n");
children = calloc(sizeof(*children), tests); if (!children)
ksft_exit_fail_msg("Unable to allocate child data\n");
ret = epoll_create1(EPOLL_CLOEXEC); if (ret < 0)
ksft_exit_fail_msg("epoll_create1() failed: %s (%d)\n",
strerror(errno), ret);
epoll_fd = ret;
/* Create a pipe which children will block on before execing */
ret = pipe(startup_pipe); if (ret != 0)
ksft_exit_fail_msg("Failed to create startup pipe: %s (%d)\n",
strerror(errno), errno);
/* Get signal handers ready before we start any children */
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = handle_exit_signal;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&sa.sa_mask);
ret = sigaction(SIGINT, &sa, NULL); if (ret < 0)
ksft_print_msg("Failed to install SIGINT handler: %s (%d)\n",
strerror(errno), errno);
ret = sigaction(SIGTERM, &sa, NULL); if (ret < 0)
ksft_print_msg("Failed to install SIGTERM handler: %s (%d)\n",
strerror(errno), errno);
sa.sa_sigaction = handle_child_signal;
ret = sigaction(SIGCHLD, &sa, NULL); if (ret < 0)
ksft_print_msg("Failed to install SIGCHLD handler: %s (%d)\n",
strerror(errno), errno);
evs = calloc(tests, sizeof(*evs)); if (!evs)
ksft_exit_fail_msg("Failed to allocated %d epoll events\n",
tests);
for (i = 0; i < cpus; i++) {
start_fpsimd(&children[num_children++], i, 0);
start_kernel(&children[num_children++], i, 0);
if (have_sme2)
start_zt(&children[num_children++], i);
}
/* * All children started, close the startup pipe and let them * run.
*/
close(startup_pipe[0]);
close(startup_pipe[1]);
for (;;) { /* Did we get a signal asking us to exit? */ if (terminate) break;
/* * Timeout is counted in poll intervals with no * output, the tests print during startup then are * silent when running so this should ensure they all * ran enough to install the signal handler, this is * especially useful in emulation where we will both * be slow and likely to have a large set of VLs.
*/
ret = epoll_wait(epoll_fd, evs, tests, poll_interval); if (ret < 0) { if (errno == EINTR) continue;
ksft_exit_fail_msg("epoll_wait() failed: %s (%d)\n",
strerror(errno), errno);
}
/* Output? */ if (ret > 0) { for (i = 0; i < ret; i++) {
child_output(evs[i].data.ptr, evs[i].events, false);
} continue;
}
/* Otherwise epoll_wait() timed out */
/* * If the child processes have not produced output they * aren't actually running the tests yet .
*/ if (!all_children_started) {
seen_children = 0;
for (i = 0; i < num_children; i++) if (children[i].output_seen ||
children[i].exited)
seen_children++;
if (seen_children != num_children) {
ksft_print_msg("Waiting for %d children\n",
num_children - seen_children); continue;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.