From eb2baf6f3497936ec56fe17e22af5b5add624371 Mon Sep 17 00:00:00 2001 From: Yosry Ahmed Date: Wed, 5 Jun 2024 02:58:11 +0000 Subject: [PATCH] mm: zswap: do not scale the number of zpools unnecessarily Zswap allocates several zpools per zswap pool for scalability. It currently allocates 32 zpools, an empirically determined magic number. For small machines that has less than 32 CPUs, this doesn't make much sense. Allocating more zpools than CPUs will not significantly increase scalability, but it may increase internal fragmentation due to spreading of compressed pages among different zpools. determined at boot as the smaller of 32 and the number of CPUs. Signed-off-by: Yosry Ahmed --- mm/zswap.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/mm/zswap.c b/mm/zswap.c index a50e2986cd2fa..9c4a6d309b23c 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -123,8 +123,8 @@ static unsigned int zswap_accept_thr_percent = 90; /* of max pool size */ module_param_named(accept_threshold_percent, zswap_accept_thr_percent, uint, 0644); -/* Number of zpools in zswap_pool (empirically determined for scalability) */ -#define ZSWAP_NR_ZPOOLS 32 +/* Number of zpools in zswap_pool */ +static unsigned int nr_zswap_zpools __ro_after_init; /* Enable/disable memory pressure-based shrinker. */ static bool zswap_shrinker_enabled = IS_ENABLED( @@ -156,7 +156,7 @@ struct crypto_acomp_ctx { * needs to be verified that it's still valid in the tree. */ struct zswap_pool { - struct zpool *zpools[ZSWAP_NR_ZPOOLS]; + struct zpool **zpools; struct crypto_acomp_ctx __percpu *acomp_ctx; struct percpu_ref ref; struct list_head list; @@ -268,7 +268,14 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor) if (!pool) return NULL; - for (i = 0; i < ZSWAP_NR_ZPOOLS; i++) { + pool->zpools = kcalloc(nr_zswap_zpools, sizeof(pool->zpools[0]), + GFP_KERNEL); + if (!pool->zpools) { + pr_err("zpools alloc failed\n"); + goto error; + } + + for (i = 0; i < nr_zswap_zpools; i++) { /* unique name for each pool specifically required by zsmalloc */ snprintf(name, 38, "zswap%x", atomic_inc_return(&zswap_pools_count)); @@ -312,8 +319,11 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor) error: if (pool->acomp_ctx) free_percpu(pool->acomp_ctx); - while (i--) - zpool_destroy_pool(pool->zpools[i]); + if (pool->zpools) { + while (i--) + zpool_destroy_pool(pool->zpools[i]); + kfree(pool->zpools); + } kfree(pool); return NULL; } @@ -369,8 +379,9 @@ static void zswap_pool_destroy(struct zswap_pool *pool) cpuhp_state_remove_instance(CPUHP_MM_ZSWP_POOL_PREPARE, &pool->node); free_percpu(pool->acomp_ctx); - for (i = 0; i < ZSWAP_NR_ZPOOLS; i++) + for (i = 0; i < nr_zswap_zpools; i++) zpool_destroy_pool(pool->zpools[i]); + kfree(pool->zpools); kfree(pool); } @@ -496,7 +507,7 @@ unsigned long zswap_total_pages(void) list_for_each_entry_rcu(pool, &zswap_pools, list) { int i; - for (i = 0; i < ZSWAP_NR_ZPOOLS; i++) + for (i = 0; i < nr_zswap_zpools; i++) total += zpool_get_total_pages(pool->zpools[i]); } rcu_read_unlock(); @@ -805,7 +816,7 @@ static void zswap_entry_cache_free(struct zswap_entry *entry) static struct zpool *zswap_find_zpool(struct zswap_entry *entry) { - return entry->pool->zpools[hash_ptr(entry, ilog2(ZSWAP_NR_ZPOOLS))]; + return entry->pool->zpools[hash_ptr(entry, ilog2(nr_zswap_zpools))]; } /* @@ -1767,6 +1778,12 @@ static int zswap_setup(void) static int __init zswap_init(void) { + /* + * Use multiple zpools for scalability, but avoid allocating too many. + * 32 is an empirically determined magic number. + */ + nr_zswap_zpools = min(32U, num_possible_cpus()); + if (!zswap_enabled) return 0; return zswap_setup(); -- 2.45.1.288.g0e0cd299f1-goog