diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2023-05-23 14:34:07 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2023-06-13 11:06:47 -0400 |
commit | 9dca9f2bcd06f921312762e0b07254f5f8f51fc2 (patch) | |
tree | 4b0348678c887e323ad74f3298a2ab49b5c5c204 | |
parent | c023cceb3f50d92ed565ea3f085883f86de0f3f0 (diff) | |
download | bfs-9dca9f2bcd06f921312762e0b07254f5f8f51fc2.tar.xz |
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.
-rw-r--r-- | src/eval.c | 18 |
1 files changed, 18 insertions, 0 deletions
@@ -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; |