Re: [PATCH v1 2/2] mm/memory: add anonymous mTHP folios to deferred split list
Barry Song <[email protected]> Tue, 4 Aug 2026 05:20:00 +0800
| Newsgroups | org.kvack.linux-mm |
|---|---|
| Message-ID | <CAGsJ_4x86EYsMz_n2NKDwTqeiv2pi4AcZb1RuZoBeUBR1iFqOA@mail.gmail.com> |
On Mon, Aug 3, 2026 at 10:45=E2=80=AFPM Johannes Weiner <[email protected]= > wrote: > > On Sat, Aug 01, 2026 at 03:33:42PM +0800, Barry Song wrote: > > On Fri, Jul 31, 2026 at 11:04=E2=80=AFPM Johannes Weiner <hannes@cmpxch= g.org> 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=3Dalways without the shrinker would also not have bee= n > > > 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 <=3D max_ptes_none zero pages. See thp_underused(). Joanne w= as > > > 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) <=3D khugepage= d_max_ptes_none) > > > + return; > > > + > > > /* > > > * Exclude swapcache: originally to avoid a corrupt deferred = split > > > * queue. Nowadays that is fully prevented by __memcg1_swapou= t(); > > > > > > The setting defaults to the PMD-1, so out of the box we wouldn't queu= e > > > 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 mapp= ed > > 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. For example, with smaller folios, the distribution might look something like this: Smaller large folios +------------------------------------------------------------+ | F | F | F | F | F | F | F | F | F | F | F | F | F | P | Z | +------------------------------------------------------------+ F: Fully mapped (dominant) P: Partially mapped (rare) Z: Zero subpages mapped (rare) So it doesn't make much sense to add them to the list, because we would rarely find P, and even the few Z entries we do find would soon be filled with non-zero data anyway. For larger folios, the list becomes much shorter. As folio size increases, they are more likely to contain zero-filled subpages: Larger large folios: +------------------------------------------------------------+ | F | P | Z | F | P | Z | P | F | Z | F | P | Z | F | P | Z | +------------------------------------------------------------+ F, P and Z become much more evenly distributed. So if the folio is large enough, this seems acceptable. I know a sysctl knob may not be well received, as it adds to the user's configuration burden. Perhaps we could just hard-code a sufficiently large value instead? for example, #define LARGE_FOLIO_ZERO_SCAN_MIN_SIZE SZ_2M if (folio_size(folio) >=3D LARGE_FOLIO_ZERO_SCAN_MIN_SIZE) deferred_split_folio(folio, false); If, someday, people find that 1 MiB also helps, they can provide data to support it. > > > 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 =3D start_phys_pfn; pfn < end_phys_pfn;) { > > folio =3D get_folio_from_pfn(); > > if (folio_is_zero_fill(folio)) > > swap_out(folio); > > pfn +=3D 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]= om/ > > > > 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? > Yes, this is a problem. We tried this on a GB-scale system, and the scanning itself was very fast. However, it provided little benefit, as the zero-filled subpages were quickly overwritten with non-zero data. > 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. Right. If we want a physical-address-based scan, we'll need some lightweight mechanism to hint where scanning should start. Thanks Barry