aboutsummaryrefslogtreecommitdiffstats
path: root/lib/helper.c
diff options
context:
space:
mode:
authorBernd Schubert <bschubert@ddn.com>2022-03-24 12:19:57 +0100
committerNikolaus Rath <Nikolaus@rath.org>2022-09-04 13:07:15 +0100
commitaf5710e7a3ad42e1b64ee8882fd72b22ffe271ac (patch)
tree9fffcd971131d4061069c382dc79b3bd8b92a501 /lib/helper.c
parent30a126c5f9009e8ff8e369c563eb941679bec252 (diff)
downloadlibfuse-af5710e7a3ad42e1b64ee8882fd72b22ffe271ac.tar.gz
fuse-loop/fuse_do_work: Avoid lots of thread creations/destructions
On benchmarking metadata operations with a single threaded bonnie++ and "max_idle_threads" limited to 1, 'top' was showing suspicious 160% cpu usage. Profiling the system with flame graphs showed that an astonishing amount of CPU time was spent in thread creation and destruction. After verifying the code it turned out that fuse_do_work() was creating a new thread every time all existing idle threads were already busy. And then just a few lines later after processing the current request it noticed that it had created too many threads and destructed the current thread. I.e. there was a thread creation/destruction ping-pong. Code is changed to only create new threads if the max number of threads is not reached. Furthermore, thread destruction is disabled, as creation/destruction is expensive in general. With this change cpu usage of passthrough_hp went from ~160% to ~80% (with different values of max_idle_threads). And bonnie values got approximately faster by 90%. This is a with single threaded bonnie++ bonnie++ -x 4 -q -s0 -d <path> -n 30:1:1:10 -r 0 Without this patch, using the default max_idle_threads=10 and just a single bonnie++ the thread creation/destruction code path is not triggered. Just one libfuse and one application thread is just a corner case - the requirement for the issue was just n-application-threads >= max_idle_threads. Signed-off-by: Bernd Schubert <bschubert@ddn.com>
Diffstat (limited to 'lib/helper.c')
-rw-r--r--lib/helper.c47
1 files changed, 44 insertions, 3 deletions
diff --git a/lib/helper.c b/lib/helper.c
index fc6a6ee..ea5f87d 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -50,6 +50,7 @@ static const struct fuse_opt fuse_helper_opts[] = {
#endif
FUSE_HELPER_OPT("clone_fd", clone_fd),
FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
+ FUSE_HELPER_OPT("max_threads=%u", max_threads),
FUSE_OPT_END
};
@@ -136,6 +137,8 @@ void fuse_cmdline_help(void)
" -o clone_fd use separate fuse device fd for each thread\n"
" (may improve performance)\n"
" -o max_idle_threads the maximum number of idle worker threads\n"
+ " allowed (default: -1)\n"
+ " -o max_threads the maximum number of worker threads\n"
" allowed (default: 10)\n");
}
@@ -199,12 +202,16 @@ static int add_default_subtype(const char *progname, struct fuse_args *args)
return res;
}
-int fuse_parse_cmdline(struct fuse_args *args,
- struct fuse_cmdline_opts *opts)
+int fuse_parse_cmdline_312(struct fuse_args *args,
+ struct fuse_cmdline_opts *opts);
+FUSE_SYMVER("fuse_parse_cmdline_312", "fuse_parse_cmdline@@FUSE_3.12")
+int fuse_parse_cmdline_312(struct fuse_args *args,
+ struct fuse_cmdline_opts *opts)
{
memset(opts, 0, sizeof(struct fuse_cmdline_opts));
- opts->max_idle_threads = 10;
+ opts->max_idle_threads = -1; /* new default in fuse version 3.12 */
+ opts->max_threads = 10;
if (fuse_opt_parse(args, opts, fuse_helper_opts,
fuse_helper_opt_proc) == -1)
@@ -221,6 +228,40 @@ int fuse_parse_cmdline(struct fuse_args *args,
return 0;
}
+/**
+ * struct fuse_cmdline_opts got extended in libfuse-3.12
+ */
+int fuse_parse_cmdline_30(struct fuse_args *args,
+ struct fuse_cmdline_opts *opts);
+FUSE_SYMVER("fuse_parse_cmdline_37", "fuse_parse_cmdline@FUSE_3.0")
+int fuse_parse_cmdline_30(struct fuse_args *args,
+ struct fuse_cmdline_opts *out_opts)
+{
+ struct fuse_cmdline_opts opts;
+
+
+ int rc = fuse_parse_cmdline_312(args, &opts);
+ if (rc == 0) {
+ /* copy up to the size of the old pre 3.12 struct */
+ memcpy(out_opts, &opts,
+ offsetof(struct fuse_cmdline_opts, max_idle_threads) +
+ sizeof(opts.max_idle_threads));
+ }
+
+ return rc;
+}
+
+/**
+ * Compatibility ABI symbol for systems that do not support version symboling
+ */
+#if (defined(__UCLIBC__) || defined(__APPLE__))
+int fuse_parse_cmdline(struct fuse_args *args,
+ struct fuse_cmdline_opts *opts)
+{
+ return fuse_parse_cmdline_30(args, out_opts);
+}
+#endif
+
int fuse_daemonize(int foreground)
{