From: Jesper Dangaard Brouer <hawk@kernel.org>
To: Yosry Ahmed <yosry@kernel.org>, Johannes Weiner <hannes@cmpxchg.org>
Cc: Yunzhao Li <yunzhao@cloudflare.com>,
linux-mm@kvack.org, nphamcs@gmail.com, yosryahmed@google.com,
shakeel.butt@linux.dev, akpm@linux-foundation.org,
zhouchengming@bytedance.com,
James Houghton <jthoughton@google.com>,
kernel-team <kernel-team@cloudflare.com>
Subject: Re: [PATCH] mm/zswap: use ratelimited stats flush in zswap_shrinker_count()
Date: Wed, 8 Jul 2026 11:10:56 +0200 [thread overview]
Message-ID: <6ecf5579-0b3b-4e8c-a625-bbf0a4a48f94@kernel.org> (raw)
In-Reply-To: <CAO9r8zOiwgG80EjqdZFgWQvODUe1RzecLemxcB7xXNm_f3XfbA@mail.gmail.com>
On 06/07/2026 21.46, Yosry Ahmed wrote:
> On Thu, Jul 2, 2026 at 6:01 PM Johannes Weiner <hannes@cmpxchg.org> wrote:
>>
>> On Thu, Jul 02, 2026 at 11:07:35AM -0700, Yunzhao Li wrote:
>>> zswap_shrinker_count() calls mem_cgroup_flush_stats(), which takes the
>>> global cgroup rstat lock synchronously. On machines with many CPUs and
>>> NUMA nodes, this creates severe lock contention in the kswapd reclaim
>>> path:
>>>
>>> - Multiple kswapd threads (one per NUMA node) run concurrently.
>>> - do_shrink_slab() invokes zswap_shrinker_count() for each
>>> memcg-aware shrinker pass.
>>> - Each call flushes the full cgroup rstat hierarchy under the global
>>> lock.
>>>
>>> On AMD EPYC 9684X machines (96 cores, 192 threads, 12 NUMA nodes)
>>> running production workloads with zswap enabled, perf shows 2.88% of
>>> kernel cycles in osq_lock contention from this path:
>>>
>>> 2.88% [k] osq_lock
>>> --__mutex_lock.constprop.0
>>> --__cgroup_rstat_lock
>>> --cgroup_rstat_flush_locked
>>> --cgroup_rstat_flush
>>> --zswap_shrinker_count
>>> do_shrink_slab
>>> shrink_slab
>>> shrink_node
>>> balance_pgdat
>>> kswapd
>>>
>>> 84% of kswapd kernel cycles are spent in
>>> shrink_slab -> zswap_shrinker_count -> cgroup_rstat_flush, not in actual
>>> page reclaim (shrink_lruvec).
>>>
>>> Controlled A/B on identical hardware and workload:
>>>
>>> shrinker=Y: 2.88% osq_lock, memory PSI 1.58%
>>> shrinker=N: 0.00% osq_lock, memory PSI 0.57%
>>>
>>> eBPF-based rstat lock wait measurement across 8 production metals
>>> confirms the contention splits cleanly along shrinker enablement:
>>>
>>> shrinker=Y: 50-250x more contended lock acquisitions (248/s vs 1.1/s)
>>> shrinker=N: baseline lock wait (0.0017 s/s vs 1.04 s/s)
>>>
>>> zswap_shrinker_count() only produces a heuristic estimate, scaled by
>>> compression ratio via mult_frac(). The actual writeback happens in
>>> zswap_shrinker_scan(). Slightly stale stats are acceptable here.
>>>
>>> Switch to mem_cgroup_flush_stats_ratelimited(), which only flushes if
>>> the periodic 2-second flusher is one full cycle late. This matches the
>>> approach already used in prepare_scan_control() (mm/vmscan.c) for the
>>> same reclaim path.
>>>
>>> After applying this patch, rstat flush latency and lock wait time on
>>> shrinker=Y machines dropped to the same level as shrinker=N controls,
>>> while the zswap shrinker continues to function (pool size remains
>>> bounded under the max_pool_percent cap).
>>>
>>> Previously discussed:
>>> - Chengming Zhou (Dec 2023): rstat contention from
>>> zswap_shrinker_count [1]
>>> - Shakeel Butt (Aug 2024): zswap_shrinker_count still uses sync
>>> flush [2]
>>> - Yosry Ahmed (Aug 2024): suggested eliminating in-kernel
>>> flushers [3]
>>> - Jesper Dangaard Brouer (Sep 2024): cgroup/rstat V11 patch [4]
>>>
>>> [1] https://lore.kernel.org/linux-mm/20231206103935.3440502-1-zhouchengming@bytedance.com/
>>> [2] https://lore.kernel.org/linux-mm/CALvZod7LFxLCxVpOFH8b2Ppm8T40HPGMKQwX_=NPCWB_mFW+oQ@mail.gmail.com/
>>> [3] https://lore.kernel.org/linux-mm/CAJD7tkYvFyOSX+rP_FKGBhxvZiCDxtpsNp-c5CGOA-4Bq9oXSg@mail.gmail.com/
>>> [4] https://lore.kernel.org/linux-mm/172616070094.2055617.17676042522679701515.stgit@firesoul/
>>>
>>> Suggested-by: Jesper Dangaard Brouer <hawk@kernel.org>
>>> Signed-off-by: Jesper Dangaard Brouer <hawk@kernel.org>
>>> Signed-off-by: Yunzhao Li <yunzhao@cloudflare.com>
>>> Tested-by: Yunzhao Li <yunzhao@cloudflare.com>
>>
>> Acked-by: Johannes Weiner <hannes@cmpxchg.org>
>>
>> A lot can happen in 2s, but I agree doing this every time is
>> silly. vmscan has been good with 2s for a while, so this should be
>> fine as well. We can re-evaluate if we run into weird behavior.
>
> Hmm actually we are starting to exercise kernels with the 2s change in
> the vmscan path, and we are observing some seemingly premature OOM
> kills for VMs under memory pressure. We are still looking into it, but
> I would honestly hold off on adding another ratelimited flush here. It
> may not be as big of a deal for the zswap path, but I'd rather fix
> this properly instead of just plugging it. We should probably move
> away from using rstat for zswapped/zswap_b stats and use page counters
> as we discussed previously (i.e. eliminating the flushes to begin
> with).
>
> (Adding James here as he's looking into the premature OOM kills internally)
IMHO it doesn't make any sense to hold off on this patch.
This only relates to zswap path with shrinker enabled. Today we are
forced to run with shrinker disabled.
If you find some better approach to ratelimited flush, then that is
great. You can change this code again for your use-case. No reason to
stall this patch IMHO.
--Jesper
next prev parent reply other threads:[~2026-07-08 9:11 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-02 18:07 [PATCH] mm/zswap: use ratelimited stats flush in zswap_shrinker_count() Yunzhao Li
2026-07-02 20:16 ` Johannes Weiner
2026-07-02 20:51 ` Jesper Dangaard Brouer
2026-07-06 19:46 ` Yosry Ahmed
2026-07-08 9:10 ` Jesper Dangaard Brouer [this message]
2026-07-08 19:32 ` Yosry Ahmed
2026-07-08 22:16 ` Yunzhao Li
2026-07-09 0:08 ` Yosry Ahmed
2026-07-09 16:34 ` Yunzhao Li
2026-07-09 19:32 ` Yosry Ahmed
2026-07-10 16:35 ` Yunzhao Li
2026-07-10 18:27 ` Yosry Ahmed
2026-07-10 21:25 ` Yunzhao Li
2026-07-10 17:16 ` Nhat Pham
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=6ecf5579-0b3b-4e8c-a625-bbf0a4a48f94@kernel.org \
--to=hawk@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=hannes@cmpxchg.org \
--cc=jthoughton@google.com \
--cc=kernel-team@cloudflare.com \
--cc=linux-mm@kvack.org \
--cc=nphamcs@gmail.com \
--cc=shakeel.butt@linux.dev \
--cc=yosry@kernel.org \
--cc=yosryahmed@google.com \
--cc=yunzhao@cloudflare.com \
--cc=zhouchengming@bytedance.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox