Re: [PATCH 2/2] mm/zswap: Support batch writeback in shrink_memcg()
From: Hao Jia
Date: Wed Jul 15 2026 - 07:28:30 EST
On 2026/7/15 00:52, Yosry Ahmed wrote:
On Tue, Jul 14, 2026 at 1:15 AM Hao Jia <jiahao.kernel@xxxxxxxxx> wrote:
From: Hao Jia <jiahao1@xxxxxxxxxxx>
Currently, shrink_memcg() writes back at most one entry per-node during
its traversal. This makes shrink_worker() inefficient, as it must
repeatedly re-enter shrink_memcg() to make any substantial progress.
Please also mention the case about writeback being slow to keep up
with refaults in some cases, leading to zswap store failures and pages
skipping zswap and going directly to disk, which is an LRU inversion.
Will be done in the next version.
To address this, extend shrink_memcg() and rewrite its LRU iteration logic
to support batch writeback. Introduce the nr_to_scan parameter to bound how
many pages are scanned per call. This enables batch writeback in the
shrink_worker() path, while maintaining a low scan budget in the
zswap_store() path.
Additionally, to prepare for future proactive writeback, update the return
value semantics of shrink_memcg(): a positive value now represents the
actual number of compressed bytes written back, 0 indicates that candidates
existed but no writeback succeeded, and a negative value represents an
error code.
This part should be dropped for now, and added with the proactive
writeback, as it's currently unused AFAICT. Removing
zswap_shrink_walk_arg will simplify the patch and make it focused on
the batching part.
Will be done in the next version.
Test Setup:
Total memory: 32 GB.
zswap settings: max_pool_percent=1, accept_threshold_percent=50,
shrinker_enabled=N.
Allocate 512MB of anonymous pages and fill them with random data (to avoid
compression), then use cgroup memory.reclaim to force a large amount of
anonymous pages into zswap. At an interval of 2ms, allocate a 4K anonymous
page where the first 4 bytes are random numbers and the rest are zeros, and
then trigger a reclamation of this 4K anonymous page through cgroup
memory.reclaim. When the pool threshold is reached, shrink_memcg() will
be triggered.
The test data after running for 120s is as follows:
Baseline Patched
shrink_worker wakeups 5363 85
shrink_memcg calls 11,345,012 188,264
written_back 40214 40275
Conclusion:
Under the same workload and run duration, the patched kernel shows a
significant reduction in both shrink_worker wakeups and shrink_memcg calls.
Please also include data from the case where zswap store failures are
observed and pages go to disk, and compare before and after this
patch. I think that part is also really important.
I retested and added some collected information. Perhaps `pool_limit_hit` and `pswpout` can explain that batch shrinking of zswap can reduce the number of pages that fail to be stored due to the pool limit, allowing zswap to skip zswap and go directly to disk.
Baseline Patched
shrink_worker wakeups 5,363 85
shrink_memcg calls 11,373,201 180,928
written_back pages 40,212 40,236
zswap_store calls 161,190 168,741
store succeeded (ret=1) 102,743 127,644
store rejected (ret=0) 58,447 41,097
store reject rate ~36% ~24%
pool_limit_hit delta 55,826 14,062
pswpout 98,659 81,333
pswpin 2 1
Thanks,
Hao