summaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2023-05-23 14:34:07 -0400
committerTavian Barnes <tavianator@tavianator.com>2023-06-13 11:06:47 -0400
commit9dca9f2bcd06f921312762e0b07254f5f8f51fc2 (patch)
tree4b0348678c887e323ad74f3298a2ab49b5c5c204 /src/eval.c
parentc023cceb3f50d92ed565ea3f085883f86de0f3f0 (diff)
downloadbfs-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.
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c18
1 files changed, 18 insertions, 0 deletions
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;