diff options
author | Bernd Schubert <bschubert@ddn.com> | 2022-03-24 12:19:57 +0100 |
---|---|---|
committer | Nikolaus Rath <Nikolaus@rath.org> | 2022-09-04 13:07:15 +0100 |
commit | af5710e7a3ad42e1b64ee8882fd72b22ffe271ac (patch) | |
tree | 9fffcd971131d4061069c382dc79b3bd8b92a501 /include | |
parent | 30a126c5f9009e8ff8e369c563eb941679bec252 (diff) | |
download | libfuse-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 'include')
-rw-r--r-- | include/fuse_common.h | 10 | ||||
-rw-r--r-- | include/fuse_lowlevel.h | 23 |
2 files changed, 30 insertions, 3 deletions
diff --git a/include/fuse_common.h b/include/fuse_common.h index b40814f..e9d8745 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -857,13 +857,19 @@ struct fuse_loop_config *fuse_loop_cfg_create(void); void fuse_loop_cfg_destroy(struct fuse_loop_config *config); /** - * fuse_loop_config2 setter to set the number of max idle threads. + * fuse_loop_config setter to set the number of max idle threads. */ void fuse_loop_cfg_set_idle_threads(struct fuse_loop_config *config, unsigned int value); /** - * fuse_loop_config2 setter to enable the clone_fd feature + * fuse_loop_config setter to set the number of max threads. + */ +void fuse_loop_cfg_set_max_threads(struct fuse_loop_config *config, + unsigned int value); + +/** + * fuse_loop_config setter to enable the clone_fd feature */ void fuse_loop_cfg_set_clone_fd(struct fuse_loop_config *config, unsigned int value); diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index 378742d..53f0fcf 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -1868,6 +1868,11 @@ void fuse_cmdline_help(void); * Filesystem setup & teardown * * ----------------------------------------------------------- */ +/** + * Note: Any addition to this struct needs to create a compatibility symbol + * for fuse_parse_cmdline(). For ABI compatibility reasons it is also + * not possible to remove struct members. + */ struct fuse_cmdline_opts { int singlethread; int foreground; @@ -1877,7 +1882,11 @@ struct fuse_cmdline_opts { int show_version; int show_help; int clone_fd; - unsigned int max_idle_threads; + unsigned int max_idle_threads; /* discouraged, due to thread + * destruct overhead */ + + /* Added in libfuse-3.12 */ + unsigned int max_threads; }; /** @@ -1898,8 +1907,20 @@ struct fuse_cmdline_opts { * @param opts output argument for parsed options * @return 0 on success, -1 on failure */ +#if (!defined(__UCLIBC__) && !defined(__APPLE__)) int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts); +#else +#if FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12) +int fuse_parse_cmdline_30(struct fuse_args *args, + struct fuse_cmdline_opts *opts); +#define fuse_parse_cmdline(args, opts) fuse_parse_cmdline_30(args, opts) +#else +int fuse_parse_cmdline_312(struct fuse_args *args, + struct fuse_cmdline_opts *opts); +#define fuse_parse_cmdline(args, opts) fuse_parse_cmdline_312(args, opts) +#endif +#endif /** * Create a low level session. |