Skip to content

Commit b8cf32d

Browse files
yosrym93akpm00
authored andcommitted
mm: zswap: multiple zpools support
Support using multiple zpools of the same type in zswap, for concurrency purposes. A fixed number of 32 zpools is suggested by this commit, which was determined empirically. It can be later changed or made into a config option if needed. On a setup with zswap and zsmalloc, comparing a single zpool to 32 zpools shows improvements in the zsmalloc lock contention, especially on the swap out path. The following shows the perf analysis of the swapout path when 10 workloads are simultaneously reclaiming and refaulting tmpfs pages. There are some improvements on the swap in path as well, but less significant. 1 zpool: |--28.99%--zswap_frontswap_store | <snip> | |--8.98%--zpool_map_handle | | | --8.98%--zs_zpool_map | | | --8.95%--zs_map_object | | | --8.38%--_raw_spin_lock | | | --7.39%--queued_spin_lock_slowpath | |--8.82%--zpool_malloc | | | --8.82%--zs_zpool_malloc | | | --8.80%--zs_malloc | | | |--7.21%--_raw_spin_lock | | | | | --6.81%--queued_spin_lock_slowpath <snip> 32 zpools: |--16.73%--zswap_frontswap_store | <snip> | |--1.81%--zpool_malloc | | | --1.81%--zs_zpool_malloc | | | --1.79%--zs_malloc | | | --0.73%--obj_malloc | |--1.06%--zswap_update_total_size | |--0.59%--zpool_map_handle | | | --0.59%--zs_zpool_map | | | --0.57%--zs_map_object | | | --0.51%--_raw_spin_lock <snip> Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Yosry Ahmed <[email protected]> Suggested-by: Yu Zhao <[email protected]> Acked-by: Chris Li (Google) <[email protected]> Reviewed-by: Nhat Pham <[email protected]> Tested-by: Nhat Pham <[email protected]> Cc: Dan Streetman <[email protected]> Cc: Domenico Cerasuolo <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Konrad Rzeszutek Wilk <[email protected]> Cc: Seth Jennings <[email protected]> Cc: Vitaly Wool <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 6be3601 commit b8cf32d

File tree

1 file changed

+54
-27
lines changed

1 file changed

+54
-27
lines changed

mm/zswap.c

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ static bool zswap_exclusive_loads_enabled = IS_ENABLED(
142142
CONFIG_ZSWAP_EXCLUSIVE_LOADS_DEFAULT_ON);
143143
module_param_named(exclusive_loads, zswap_exclusive_loads_enabled, bool, 0644);
144144

145+
/* Number of zpools in zswap_pool (empirically determined for scalability) */
146+
#define ZSWAP_NR_ZPOOLS 32
147+
145148
/*********************************
146149
* data structures
147150
**********************************/
@@ -161,7 +164,7 @@ struct crypto_acomp_ctx {
161164
* needs to be verified that it's still valid in the tree.
162165
*/
163166
struct zswap_pool {
164-
struct zpool *zpool;
167+
struct zpool *zpools[ZSWAP_NR_ZPOOLS];
165168
struct crypto_acomp_ctx __percpu *acomp_ctx;
166169
struct kref kref;
167170
struct list_head list;
@@ -248,7 +251,7 @@ static bool zswap_has_pool;
248251

249252
#define zswap_pool_debug(msg, p) \
250253
pr_debug("%s pool %s/%s\n", msg, (p)->tfm_name, \
251-
zpool_get_type((p)->zpool))
254+
zpool_get_type((p)->zpools[0]))
252255

253256
static int zswap_writeback_entry(struct zswap_entry *entry,
254257
struct zswap_tree *tree);
@@ -272,11 +275,13 @@ static void zswap_update_total_size(void)
272275
{
273276
struct zswap_pool *pool;
274277
u64 total = 0;
278+
int i;
275279

276280
rcu_read_lock();
277281

278282
list_for_each_entry_rcu(pool, &zswap_pools, list)
279-
total += zpool_get_total_size(pool->zpool);
283+
for (i = 0; i < ZSWAP_NR_ZPOOLS; i++)
284+
total += zpool_get_total_size(pool->zpools[i]);
280285

281286
rcu_read_unlock();
282287

@@ -365,6 +370,16 @@ static bool zswap_rb_erase(struct rb_root *root, struct zswap_entry *entry)
365370
return false;
366371
}
367372

373+
static struct zpool *zswap_find_zpool(struct zswap_entry *entry)
374+
{
375+
int i = 0;
376+
377+
if (ZSWAP_NR_ZPOOLS > 1)
378+
i = hash_ptr(entry, ilog2(ZSWAP_NR_ZPOOLS));
379+
380+
return entry->pool->zpools[i];
381+
}
382+
368383
/*
369384
* Carries out the common pattern of freeing and entry's zpool allocation,
370385
* freeing the entry itself, and decrementing the number of stored pages.
@@ -381,7 +396,7 @@ static void zswap_free_entry(struct zswap_entry *entry)
381396
spin_lock(&entry->pool->lru_lock);
382397
list_del(&entry->lru);
383398
spin_unlock(&entry->pool->lru_lock);
384-
zpool_free(entry->pool->zpool, entry->handle);
399+
zpool_free(zswap_find_zpool(entry), entry->handle);
385400
zswap_pool_put(entry->pool);
386401
}
387402
zswap_entry_cache_free(entry);
@@ -590,7 +605,8 @@ static struct zswap_pool *zswap_pool_find_get(char *type, char *compressor)
590605
list_for_each_entry_rcu(pool, &zswap_pools, list) {
591606
if (strcmp(pool->tfm_name, compressor))
592607
continue;
593-
if (strcmp(zpool_get_type(pool->zpool), type))
608+
/* all zpools share the same type */
609+
if (strcmp(zpool_get_type(pool->zpools[0]), type))
594610
continue;
595611
/* if we can't get it, it's about to be destroyed */
596612
if (!zswap_pool_get(pool))
@@ -695,6 +711,7 @@ static void shrink_worker(struct work_struct *w)
695711

696712
static struct zswap_pool *zswap_pool_create(char *type, char *compressor)
697713
{
714+
int i;
698715
struct zswap_pool *pool;
699716
char name[38]; /* 'zswap' + 32 char (max) num + \0 */
700717
gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN | __GFP_KSWAPD_RECLAIM;
@@ -715,15 +732,18 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor)
715732
if (!pool)
716733
return NULL;
717734

718-
/* unique name for each pool specifically required by zsmalloc */
719-
snprintf(name, 38, "zswap%x", atomic_inc_return(&zswap_pools_count));
735+
for (i = 0; i < ZSWAP_NR_ZPOOLS; i++) {
736+
/* unique name for each pool specifically required by zsmalloc */
737+
snprintf(name, 38, "zswap%x",
738+
atomic_inc_return(&zswap_pools_count));
720739

721-
pool->zpool = zpool_create_pool(type, name, gfp);
722-
if (!pool->zpool) {
723-
pr_err("%s zpool not available\n", type);
724-
goto error;
740+
pool->zpools[i] = zpool_create_pool(type, name, gfp);
741+
if (!pool->zpools[i]) {
742+
pr_err("%s zpool not available\n", type);
743+
goto error;
744+
}
725745
}
726-
pr_debug("using %s zpool\n", zpool_get_type(pool->zpool));
746+
pr_debug("using %s zpool\n", zpool_get_type(pool->zpools[0]));
727747

728748
strscpy(pool->tfm_name, compressor, sizeof(pool->tfm_name));
729749

@@ -755,8 +775,8 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor)
755775
error:
756776
if (pool->acomp_ctx)
757777
free_percpu(pool->acomp_ctx);
758-
if (pool->zpool)
759-
zpool_destroy_pool(pool->zpool);
778+
while (i--)
779+
zpool_destroy_pool(pool->zpools[i]);
760780
kfree(pool);
761781
return NULL;
762782
}
@@ -805,11 +825,14 @@ static struct zswap_pool *__zswap_pool_create_fallback(void)
805825

806826
static void zswap_pool_destroy(struct zswap_pool *pool)
807827
{
828+
int i;
829+
808830
zswap_pool_debug("destroying", pool);
809831

810832
cpuhp_state_remove_instance(CPUHP_MM_ZSWP_POOL_PREPARE, &pool->node);
811833
free_percpu(pool->acomp_ctx);
812-
zpool_destroy_pool(pool->zpool);
834+
for (i = 0; i < ZSWAP_NR_ZPOOLS; i++)
835+
zpool_destroy_pool(pool->zpools[i]);
813836
kfree(pool);
814837
}
815838

@@ -1073,7 +1096,7 @@ static int zswap_writeback_entry(struct zswap_entry *entry,
10731096
struct page *page;
10741097
struct scatterlist input, output;
10751098
struct crypto_acomp_ctx *acomp_ctx;
1076-
struct zpool *pool = entry->pool->zpool;
1099+
struct zpool *pool = zswap_find_zpool(entry);
10771100

10781101
u8 *src, *tmp = NULL;
10791102
unsigned int dlen;
@@ -1214,6 +1237,7 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
12141237
struct crypto_acomp_ctx *acomp_ctx;
12151238
struct obj_cgroup *objcg = NULL;
12161239
struct zswap_pool *pool;
1240+
struct zpool *zpool;
12171241
int ret;
12181242
unsigned int dlen = PAGE_SIZE;
12191243
unsigned long handle, value;
@@ -1324,10 +1348,11 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
13241348
}
13251349

13261350
/* store */
1351+
zpool = zswap_find_zpool(entry);
13271352
gfp = __GFP_NORETRY | __GFP_NOWARN | __GFP_KSWAPD_RECLAIM;
1328-
if (zpool_malloc_support_movable(entry->pool->zpool))
1353+
if (zpool_malloc_support_movable(zpool))
13291354
gfp |= __GFP_HIGHMEM | __GFP_MOVABLE;
1330-
ret = zpool_malloc(entry->pool->zpool, dlen, gfp, &handle);
1355+
ret = zpool_malloc(zpool, dlen, gfp, &handle);
13311356
if (ret == -ENOSPC) {
13321357
zswap_reject_compress_poor++;
13331358
goto put_dstmem;
@@ -1336,9 +1361,9 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
13361361
zswap_reject_alloc_fail++;
13371362
goto put_dstmem;
13381363
}
1339-
buf = zpool_map_handle(entry->pool->zpool, handle, ZPOOL_MM_WO);
1364+
buf = zpool_map_handle(zpool, handle, ZPOOL_MM_WO);
13401365
memcpy(buf, dst, dlen);
1341-
zpool_unmap_handle(entry->pool->zpool, handle);
1366+
zpool_unmap_handle(zpool, handle);
13421367
mutex_unlock(acomp_ctx->mutex);
13431368

13441369
/* populate entry */
@@ -1409,6 +1434,7 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset,
14091434
struct scatterlist input, output;
14101435
struct crypto_acomp_ctx *acomp_ctx;
14111436
u8 *src, *dst, *tmp;
1437+
struct zpool *zpool;
14121438
unsigned int dlen;
14131439
int ret;
14141440

@@ -1430,7 +1456,8 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset,
14301456
goto stats;
14311457
}
14321458

1433-
if (!zpool_can_sleep_mapped(entry->pool->zpool)) {
1459+
zpool = zswap_find_zpool(entry);
1460+
if (!zpool_can_sleep_mapped(zpool)) {
14341461
tmp = kmalloc(entry->length, GFP_KERNEL);
14351462
if (!tmp) {
14361463
ret = -ENOMEM;
@@ -1440,12 +1467,12 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset,
14401467

14411468
/* decompress */
14421469
dlen = PAGE_SIZE;
1443-
src = zpool_map_handle(entry->pool->zpool, entry->handle, ZPOOL_MM_RO);
1470+
src = zpool_map_handle(zpool, entry->handle, ZPOOL_MM_RO);
14441471

1445-
if (!zpool_can_sleep_mapped(entry->pool->zpool)) {
1472+
if (!zpool_can_sleep_mapped(zpool)) {
14461473
memcpy(tmp, src, entry->length);
14471474
src = tmp;
1448-
zpool_unmap_handle(entry->pool->zpool, entry->handle);
1475+
zpool_unmap_handle(zpool, entry->handle);
14491476
}
14501477

14511478
acomp_ctx = raw_cpu_ptr(entry->pool->acomp_ctx);
@@ -1457,8 +1484,8 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset,
14571484
ret = crypto_wait_req(crypto_acomp_decompress(acomp_ctx->req), &acomp_ctx->wait);
14581485
mutex_unlock(acomp_ctx->mutex);
14591486

1460-
if (zpool_can_sleep_mapped(entry->pool->zpool))
1461-
zpool_unmap_handle(entry->pool->zpool, entry->handle);
1487+
if (zpool_can_sleep_mapped(zpool))
1488+
zpool_unmap_handle(zpool, entry->handle);
14621489
else
14631490
kfree(tmp);
14641491

@@ -1619,7 +1646,7 @@ static int zswap_setup(void)
16191646
pool = __zswap_pool_create_fallback();
16201647
if (pool) {
16211648
pr_info("loaded using pool %s/%s\n", pool->tfm_name,
1622-
zpool_get_type(pool->zpool));
1649+
zpool_get_type(pool->zpools[0]));
16231650
list_add(&pool->list, &zswap_pools);
16241651
zswap_has_pool = true;
16251652
} else {

0 commit comments

Comments
 (0)