[PATCH] erofs: add a reserved buffer pool for lz4 decompression
Gao Xiang
hsiangkao at linux.alibaba.com
Tue Apr 2 22:44:50 AEDT 2024
On 2024/4/2 16:45, Chunhai Guo wrote:
> This adds a special global buffer pool (in the end) for reserved pages.
>
> Using a reserved pool for LZ4 decompression significantly reduces the
> time spent on extra temporary page allocation for the extreme cases in
> low memory scenarios.
>
> The table below shows the reduction in time spent on page allocation for
> LZ4 decompression when using a reserved pool. The results were obtained
> from multi-app launch benchmarks on ARM64 Android devices running the
> 5.15 kernel with an 8-core CPU and 8GB of memory. In the benchmark, we
> launched 16 frequently-used apps, and the camera app was the last one in
> each round. The data in the table is the average time of camera app for
> each round.
>
> After using the reserved pool, there was an average improvement of 150ms
> in the overall launch time of our camera app, which was obtained from
> the systrace log.
>
> +--------------+---------------+--------------+---------+
> | | w/o page pool | w/ page pool | diff |
> +--------------+---------------+--------------+---------+
> | Average (ms) | 3434 | 21 | -99.38% |
> +--------------+---------------+--------------+---------+
>
> Based on the benchmark logs, 64 pages are sufficient for 95% of
> scenarios. This value can be adjusted from the module parameter.
> The default value is 0.
>
> This pool is currently only used for the LZ4 decompressor, but it can be
> applied to more decompressors if needed.
>
> Signed-off-by: Chunhai Guo <guochunhai at vivo.com>
> ---
> fs/erofs/decompressor.c | 2 +-
> fs/erofs/internal.h | 6 ++++-
> fs/erofs/zutil.c | 59 ++++++++++++++++++++++++++++++-----------
> 3 files changed, 50 insertions(+), 17 deletions(-)
>
> diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c
> index e1239d886984..d2fe8130819e 100644
> --- a/fs/erofs/decompressor.c
> +++ b/fs/erofs/decompressor.c
> @@ -111,7 +111,7 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_lz4_decompress_ctx *ctx,
> victim = availables[--top];
> get_page(victim);
> } else {
> - victim = erofs_allocpage(pagepool, rq->gfp);
> + victim = __erofs_allocpage(pagepool, rq->gfp, true);
> if (!victim)
> return -ENOMEM;
> set_page_private(victim, Z_EROFS_SHORTLIVED_PAGE);
> diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
> index 1caa5d702835..664f6f7c971f 100644
> --- a/fs/erofs/internal.h
> +++ b/fs/erofs/internal.h
> @@ -445,7 +445,11 @@ void erofs_unregister_sysfs(struct super_block *sb);
> int __init erofs_init_sysfs(void);
> void erofs_exit_sysfs(void);
>
> -struct page *erofs_allocpage(struct page **pagepool, gfp_t gfp);
> +struct page *__erofs_allocpage(struct page **pagepool, gfp_t gfp, bool tryrsv);
> +static inline struct page *erofs_allocpage(struct page **pagepool, gfp_t gfp)
> +{
> + return __erofs_allocpage(pagepool, gfp, false);
> +}
> static inline void erofs_pagepool_add(struct page **pagepool, struct page *page)
> {
> set_page_private(page, (unsigned long)*pagepool);
> diff --git a/fs/erofs/zutil.c b/fs/erofs/zutil.c
> index 14440c0bf64e..b45ca0b8b547 100644
> --- a/fs/erofs/zutil.c
> +++ b/fs/erofs/zutil.c
> @@ -12,10 +12,12 @@ struct z_erofs_gbuf {
> unsigned int nrpages;
> };
>
> -static struct z_erofs_gbuf *z_erofs_gbufpool;
> -static unsigned int z_erofs_gbuf_count, z_erofs_gbuf_nrpages;
> +static struct z_erofs_gbuf *z_erofs_gbufpool, *z_erofs_rsvbuf;
> +static unsigned int z_erofs_gbuf_count, z_erofs_gbuf_nrpages,
> + z_erofs_rsv_nrpages;
>
> module_param_named(global_buffers, z_erofs_gbuf_count, uint, 0444);
> +module_param_named(reserved_pages, z_erofs_rsv_nrpages, uint, 0444);
>
> static atomic_long_t erofs_global_shrink_cnt; /* for all mounted instances */
> /* protected by 'erofs_sb_list_lock' */
> @@ -117,19 +119,28 @@ int z_erofs_gbuf_growsize(unsigned int nrpages)
>
> int __init z_erofs_gbuf_init(void)
> {
> - unsigned int i = num_possible_cpus();
> + unsigned int i, total = num_possible_cpus();
>
> - if (!z_erofs_gbuf_count)
> - z_erofs_gbuf_count = i;
> - else
> - z_erofs_gbuf_count = min(z_erofs_gbuf_count, i);
> + if (z_erofs_gbuf_count)
> + total = min(z_erofs_gbuf_count, total);
> + z_erofs_gbuf_count = total;
>
> - z_erofs_gbufpool = kcalloc(z_erofs_gbuf_count,
> - sizeof(*z_erofs_gbufpool), GFP_KERNEL);
> + /* The last (special) global buffer is the reserved buffer */
> + total += !!z_erofs_rsv_nrpages;
> +
> + z_erofs_gbufpool = kcalloc(total, sizeof(*z_erofs_gbufpool),
> + GFP_KERNEL);
> if (!z_erofs_gbufpool)
> return -ENOMEM;
>
> - for (i = 0; i < z_erofs_gbuf_count; ++i)
> + if (z_erofs_rsv_nrpages) {
> + z_erofs_rsvbuf = &z_erofs_gbufpool[total - 1];
> + z_erofs_rsvbuf->pages = kcalloc(z_erofs_rsv_nrpages,
> + sizeof(*z_erofs_rsvbuf->pages), GFP_KERNEL);
> + if (!z_erofs_rsvbuf->pages)
> + z_erofs_rsvbuf = NULL;
It'd be better to reset z_erofs_rsv_nrpages to 0, since it can be
fetched from `/sys/module/erofs/parameters`, as:
if (!z_erofs_rsvbuf->pages) {
z_erofs_rsvbuf = NULL;
z_erofs_rsv_nrpages = 0;
}
Thanks,
Gao Xiang
More information about the Linux-erofs
mailing list