Skip to content

Commit 98102a2

Browse files
brooniewilldeacon
authored andcommitted
kselftest/arm64: Hold fp-stress children until they're all spawned
At present fp-stress has a bit of a thundering herd problem since the children it spawns start running immediately, meaning that they can start starving the parent process of CPU before it has even started all the children. This is much more severe on virtual platforms since they tend to support far more SVE and SME vector lengths, be slower in general and for some have issues with performance when simulating multiple CPUs. We can mitigate this problem by having all the child processes block before starting the test program, meaning that we at least have all the child processes started before we start heavily using CPU. We still have the same load issues while waiting for the actual stress test programs to start up and produce output but they're at least all ready to go before that kicks in, resulting in substantial reductions in overall runtime on some of the severely affected systems. One test was showing about 20% improvement. Signed-off-by: Mark Brown <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 6429789 commit 98102a2

File tree

1 file changed

+40
-1
lines changed

1 file changed

+40
-1
lines changed

tools/testing/selftests/arm64/fp/fp-stress.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ static bool terminate;
4444

4545
static void drain_output(bool flush);
4646

47+
static int startup_pipe[2];
48+
4749
static int num_processors(void)
4850
{
4951
long nproc = sysconf(_SC_NPROCESSORS_CONF);
@@ -81,13 +83,37 @@ static void child_start(struct child_data *child, const char *program)
8183
exit(EXIT_FAILURE);
8284
}
8385

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+
fprintf(stderr, "dup2() %d\n", errno);
93+
exit(EXIT_FAILURE);
94+
}
95+
8496
/*
8597
* Very dumb mechanism to clean open FDs other than
8698
* stdio. We don't want O_CLOEXEC for the pipes...
8799
*/
88-
for (i = 3; i < 8192; i++)
100+
for (i = 4; i < 8192; i++)
89101
close(i);
90102

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+
fprintf(stderr, "read(startp pipe) failed: %s (%d)\n",
111+
strerror(errno), errno);
112+
if (ret > 0)
113+
fprintf(stderr, "%d bytes of data on startup pipe\n",
114+
ret);
115+
close(3);
116+
91117
ret = execl(program, program, NULL);
92118
fprintf(stderr, "execl(%s) failed: %d (%s)\n",
93119
program, errno, strerror(errno));
@@ -467,6 +493,12 @@ int main(int argc, char **argv)
467493
strerror(errno), ret);
468494
epoll_fd = ret;
469495

496+
/* Create a pipe which children will block on before execing */
497+
ret = pipe(startup_pipe);
498+
if (ret != 0)
499+
ksft_exit_fail_msg("Failed to create startup pipe: %s (%d)\n",
500+
strerror(errno), errno);
501+
470502
/* Get signal handers ready before we start any children */
471503
memset(&sa, 0, sizeof(sa));
472504
sa.sa_sigaction = handle_exit_signal;
@@ -499,6 +531,13 @@ int main(int argc, char **argv)
499531
}
500532
}
501533

534+
/*
535+
* All children started, close the startup pipe and let them
536+
* run.
537+
*/
538+
close(startup_pipe[0]);
539+
close(startup_pipe[1]);
540+
502541
for (;;) {
503542
/* Did we get a signal asking us to exit? */
504543
if (terminate)

0 commit comments

Comments
 (0)