From: "Vlastimil Babka (SUSE)" <vbabka@kernel.org>
To: JP Kobryn <jp.kobryn@linux.dev>,
akpm@linux-foundation.org, surenb@google.com, mhocko@suse.com,
jackmanb@google.com, hannes@cmpxchg.org, ziy@nvidia.com,
linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org, kernel-team@meta.com
Subject: Re: [PATCH] mm/compaction: cap compact_gap() at COMPACT_CLUSTER_MAX
Date: Wed, 3 Jun 2026 10:19:27 +0200 [thread overview]
Message-ID: <a0a19e2e-04b4-4224-95f6-3195006ee780@kernel.org> (raw)
In-Reply-To: <89e01c8e-1b08-45a6-a702-b23e45b70a29@linux.dev>
On 6/3/26 09:15, JP Kobryn wrote:
> On 6/2/26 1:40 AM, Vlastimil Babka (SUSE) wrote:
>> On 6/2/26 03:48, JP Kobryn wrote:
>>> On 5/28/26 1:51 AM, Vlastimil Babka (SUSE) wrote:
>>>> On 5/27/26 02:10, JP Kobryn wrote:
>>>>> On 5/25/26 3:02 AM, Vlastimil Babka (SUSE) wrote:
>>>>>> On 5/19/26 22:08, JP Kobryn (Meta) wrote:
>>>>>>> compact_gap() returns 2 << order, which is used as watermark headroom in
>>>>>>> __compaction_suitable() and as a reclaim target in kswapd. The computed
>>>>>>> value scales exponentially by order. For order-9 THP allocations this
>>>>>>> evaluates to 1024 pages, but the compaction free scanner's working set is
>>>>>>> bounded by COMPACT_CLUSTER_MAX (32 pages). The scanner stops
>>>>>>> isolating free
>>>>>>> pages once it matches the migration batch. The current gap
>>>>>>> over-reserves by
>>>>>>> 32x.
>>>>>>>
>>>>>>> On fragmented production hosts, kswapd will try and reclaim up to the
>>>>>>> gap,
>>>>>>> but it only reaches that threshold 18% of the time, causing reclaim to
>>>>>>> continue a majority of the time.
>>>>>> But doesn't that mean there's genuine memory pressure? We're effectively
>>>>>> raising the high watermark by 4 MB, but if processes are continuously
>>>>>> allocating, we'd be reclaiming without the gap as well? Unless the
>>>>>> workload
>>>>>> is sized to fit without the gap.
>>>>> It wasn't actual pressure, but the repetitive order-9 THP failures that were
>>>>> waking up kswapd. I should make this more clear in the changelog. After
>>>>> looking into why so much reclaim was occurring though, the compact gap stood
>>>>> out since it dictates the target amount to reclaim.
>>>> But the "amount to reclaim" is still defined as "reach high watermark +
>>>> compact_gap()" and not "reclaim at least compact_gap() pages" right? Or did
>>>> I miss something non-obvious.
>>> Within kswapd_shrink_node(), sc->nr_to_reclaim is the sum of max(zone high
>>> watermark or SWAP_CLUSTER_MAX) for each zone combined. The gap is not
>>> added to
>>> that reclaim target though. It's used afterward as the threshold for
>>> abandoning
>>> high order reclaim:
>>>
>>> if (sc->order && sc->nr_reclaimed >= compact_gap(sc->order))
>>> sc->order = 0;
>>>
>>> balance_pgdat() then returns sc->order and that becomes the kswapd
>>> reclaim_order
>>> value, allowing this branch to be taken:
>>>
>>> if (reclaim_order < alloc_order)
>>> goto kswapd_try_sleep;
>>>
>>> Then in prepare_kswapd_sleep(), if pgdat_balanced() succeeds (at order-0),
>>> kcompactd is woken up for the original alloc_order (order-9).
>>
>> Oh I see, thanks for explaining. I think it makes sense to target this
>> particular part (checking sc->nr_reclaimed) than change compact_gap()
>> globally then? It seems we have some mismatch in the various heuristics? IIUC:
>
> I gave this a try and got some interesting results. Based on mm-new as
> of earlier today, I ran three variations: original compact_gap (2 <<
> order), capped compact_gap (this patch), and capped downgrade gate which
> has the original compact_gap (2 << order) but caps within
> kswapd_shrink_node():
>
> - if (sc->order && sc->nr_reclaimed >= compact_gap(sc->order)) {
> + if (sc->order && sc->nr_reclaimed >=
> + min(compact_gap(sc->order), SWAP_CLUSTER_MAX)) {
> sc->order = 0;
> }
>
> The new approach showed improvements in THP allocations.
>
> thp_fault_fallback
> original gap: 1217
> capped gap (global): 738
> capped gap at downgrade gate: 898
>
> More details are below.
>
>>
>> - in shrink_node() we have a should_continue_reclaim() call, which will
>> return false as soon as compaction is suitable, but before that, we are
>> likely to not accumulate enough sc->nr_reclaimed, because sc->nr_to_reclaim
>> would be capped by SWAP_CLUSTER_MAX's
>>
>> - thus we won't pass the sc->nr_reclaimed >= compact_gap check in
>> kswapd_shrink_node()
>>
>> - balance_pgdat() will keep looping because we're not raising priority
>> (kswapd_shrink_node() returned a high order) and pgdat_balanced() is false
>> (it checks for high-order page availability)
>
> I added some temporary tracepoints to verify paths taken. The average
> hits across three 60s runs are shown below.
>
> kswapd_shrink_node downgrade to order-0
> original gap: 0
> capped gap (global, this patch): 28
> capped gap at downgrade gate: 80
>
> So the downgrades are more frequent, but the suggested approach
> regressed harder in terms of reclaim.
>
> pgscan_kswapd
> original gap: 6328
> capped gap (global, this patch): 3773
> capped gap at downgrade gate: 7988
>
> pgsteal_kswapd
> original gap: 5657
> capped gap (global, this patch): 3243
> capped gap at downgrade gate: 7101
>
> This is because the suitability checks are still using the inflated gap
> causing the split below.
> kswapd_shrink_node() gap: 32
> __compaction_suitable() gap: 1024
>
> So it seems that capping globally (this patch) is the better option to
> avoid the split above which causes unnecessary reclaim.
OK that's convincing and thanks a lot for doing that. Could you summarize
this in the changelog as well? Thanks!
next prev parent reply other threads:[~2026-06-03 8:19 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-19 20:08 JP Kobryn (Meta)
2026-05-25 10:02 ` Vlastimil Babka (SUSE)
2026-05-27 0:10 ` JP Kobryn
2026-05-28 8:51 ` Vlastimil Babka (SUSE)
2026-06-02 1:48 ` JP Kobryn
2026-06-02 8:40 ` Vlastimil Babka (SUSE)
2026-06-03 7:15 ` JP Kobryn
2026-06-03 8:19 ` Vlastimil Babka (SUSE) [this message]
2026-06-03 8:20 ` Vlastimil Babka (SUSE)
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=a0a19e2e-04b4-4224-95f6-3195006ee780@kernel.org \
--to=vbabka@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=hannes@cmpxchg.org \
--cc=jackmanb@google.com \
--cc=jp.kobryn@linux.dev \
--cc=kernel-team@meta.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mhocko@suse.com \
--cc=surenb@google.com \
--cc=ziy@nvidia.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
Powered by JetHome