From 9dca9f2bcd06f921312762e0b07254f5f8f51fc2 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 23 May 2023 14:34:07 -0400 Subject: eval: Pre-allocate the highest fd This avoids the need to grow the fd table during the search, significantly reducing kernel contention when opening directories in parallel. --- src/eval.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/eval.c') diff --git a/src/eval.c b/src/eval.c index b9bce6c..f16821e 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1471,6 +1471,23 @@ static int raise_fdlimit(const struct bfs_ctx *ctx) { return ret; } +/** Preallocate the fd table in the kernel. */ +static void reserve_fds(int limit) { + // Kernels typically implement the fd table as a dynamic array. + // Growing the array can be expensive, especially if files are being + // opened in parallel. We can work around this by allocating the + // highest possible fd, forcing the kernel to grow the table upfront. + +#ifdef F_DUPFD_CLOEXEC + int fd = fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC, limit - 1); +#else + int fd = fcntl(STDIN_FILENO, F_DUPFD, limit - 1); +#endif + if (fd >= 0) { + xclose(fd); + } +} + /** Infer the number of file descriptors available to bftw(). */ static int infer_fdlimit(const struct bfs_ctx *ctx, int limit) { // 3 for std{in,out,err} @@ -1604,6 +1621,7 @@ int bfs_eval(const struct bfs_ctx *ctx) { } int fdlimit = raise_fdlimit(ctx); + reserve_fds(fdlimit); fdlimit = infer_fdlimit(ctx, fdlimit); int nthreads; -- cgit v1.2.3