Re: [PATCH v1 2/2] mm/memory: add anonymous mTHP folios to deferred split list
Johannes Weiner <[email protected]> Mon, 3 Aug 2026 10:45:10 -0400
| Newsgroups | org.kvack.linux-mm |
|---|---|
| Message-ID | <[email protected]> |
On Sat, Aug 01, 2026 at 03:33:42PM +0800, Barry Song wrote: > On Fri, Jul 31, 2026 at 11:04 PM Johannes Weiner <[email protected]> wrote: > > This is kind of tangential, but I'm curious if you would have > > experimented with larger folios AND the THP shrinker? > > > > Haven't tried it yet. > > A key difference between Android and server workloads is that Android > typically has many applications running with frequent > foreground/background transitions. When an app moves to the > background, much of its memory may be compressed. When it returns to > the foreground, it often allocates a large amount of new memory, > creating significant memory pressure. > > If we need around 200 ms to cold/warm start an app, allocating 2 MB > folios and later splitting them into smaller ones via the THP shrinker > could cause us to hit this shrinker path directly during the app launch > process. For example, we may spend the first 100 ms allocating 2 MB > folios and then the next 100 ms shrinking them back under memory > pressure. This would be quite ironic for Android :-) > > Since Android app launches can demand a large amount of memory on > devices with limited RAM, keeping burst allocations small is also > important. Makes sense, thanks for the insight. It works for many DC services because it's just a bit of extra startup cost, while then getting predictable THP coverage for exactly those areas where it makes sense, and the TLB benefits pay off over long service runtimes. > > In Meta, 2M thp=always without the shrinker would also not have been > > tolerable. It OOMed immediately on a large number of services. The > > shrinker *is* what allowed us to use such large folios to begin with, > > without the internal memory waste problem. > > My understanding is that Meta's use case is a service that is already > running with 2 MB pages, and later additional services start and > require more memory. In that case, shrinking THPs from the existing > service to free memory for the new services makes sense to me. It's simpler than that. We had existing services, scaled to machine capacity, running with basepages. When we enabled 2M pages, they started thrashing and OOMing from areas with poor virtual packing. The shrinker makes it possible to run with THPs enabled, period. This is why I'm concerned about making the search for waste less efficient. It would likely regress things in production immediately. > > Here is an idea: the THP shrinker will not consider anything unused > > that has <= max_ptes_none zero pages. See thp_underused(). Joanne was > > proposing to scale this knob down relative to the folio size for mTHP > > shrinking. What if instead we kept the meaning absolute? > > > > The knob is an expression of how much waste the user is willing to > > tolerate per folio. If the folio order in question couldn't possibly > > have that much waste in the first place, we don't have to queue it? > > > > Something like this: > > > > diff --git a/mm/huge_memory.c b/mm/huge_memory.c > > index 2bccb0a53a0a..1670e9869bd3 100644 > > --- a/mm/huge_memory.c > > +++ b/mm/huge_memory.c > > @@ -4364,6 +4364,9 @@ void deferred_split_folio(struct folio *folio, bool partially_mapped) > > if (!partially_mapped && !split_underused_thp) > > return; > > > > + if (!partially_mapped && folio_nr_pages(folio) <= khugepaged_max_ptes_none) > > + return; > > + > > /* > > * Exclude swapcache: originally to avoid a corrupt deferred split > > * queue. Nowadays that is fully prevented by __memcg1_swapout(); > > > > The setting defaults to the PMD-1, so out of the box we wouldn't queue > > any new orders. It would allow that 2MB on 64k ARM usecase, without > > jeopardizing smaller mTHP usecases like Barry's. > > > > Thoughts? > > My understanding is that adding smaller folios to the deferred split > list is not the right approach. We could end up with a very large list > where we cannot distinguish partially unmapped folios from fully mapped > ones. For example, the deferred split list could contain 100 fully mapped > folios but only a single partially mapped folio. > Moreover, for smaller large folios, the number of zero subpages > is likely to be small and short-lived. > > However, this is probably fine for larger large folios, since it is > unlikely to significantly increase the size of the deferred split > list. In other words, the deferred split list should remain manageable. > For the same reason, larger large folios may not benefit much from the > LRU cache either. > > So if we have some mechanism to prevent users from doing things that > are not beneficial, such as adding smaller large folios to the list, it > seems reasonable to me. Just to clarify, we're on the same page, right? I was proposing a mechanism to do just that. > As a side note (I'm not quite sure whether this is relevant to this > discussion), one thing we tried previously as an out-of-tree proof of > concept was: > > for (pfn = start_phys_pfn; pfn < end_phys_pfn;) { > folio = get_folio_from_pfn(); > if (folio_is_zero_fill(folio)) > swap_out(folio); > pfn += folio_nr_pages(); > } > > Then I was using my previous patch to remap it to zero-pfn if someone > reads it: > https://lore.kernel.org/linux-mm/[email protected]/ > > This does not depend on any list-related logic. We can scan all PFNs > within a short time. Hm there are 268 million PFNs on a 1TB host. I don't think that can scale? Compaction used to be linear scans, but needed to grow the freelist search and a whole bunch of position hinting to stay ahead of scaling bottlenecks.