From: Ryan Roberts <ryan.roberts@arm.com>
To: "Huang, Ying" <ying.huang@intel.com>,
David Hildenbrand <david@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
Matthew Wilcox <willy@infradead.org>,
Gao Xiang <xiang@kernel.org>, Yu Zhao <yuzhao@google.com>,
Yang Shi <shy828301@gmail.com>, Michal Hocko <mhocko@suse.com>,
Kefeng Wang <wangkefeng.wang@huawei.com>,
Barry Song <21cnbao@gmail.com>, Chris Li <chrisl@kernel.org>,
Lance Yang <ioworker0@gmail.com>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v6 4/6] mm: swap: Allow storage of all mTHP orders
Date: Mon, 8 Apr 2024 10:24:48 +0100 [thread overview]
Message-ID: <ba63464e-afc3-4bbb-b13f-704eaf9ed4af@arm.com> (raw)
In-Reply-To: <87edbhaexj.fsf@yhuang6-desk2.ccr.corp.intel.com>
On 07/04/2024 07:02, Huang, Ying wrote:
> David Hildenbrand <david@redhat.com> writes:
>
>> On 03.04.24 13:40, Ryan Roberts wrote:
>>> Multi-size THP enables performance improvements by allocating large,
>>> pte-mapped folios for anonymous memory. However I've observed that on an
>>> arm64 system running a parallel workload (e.g. kernel compilation)
>>> across many cores, under high memory pressure, the speed regresses. This
>>> is due to bottlenecking on the increased number of TLBIs added due to
>>> all the extra folio splitting when the large folios are swapped out.
>>> Therefore, solve this regression by adding support for swapping out
>>> mTHP
>>> without needing to split the folio, just like is already done for
>>> PMD-sized THP. This change only applies when CONFIG_THP_SWAP is enabled,
>>> and when the swap backing store is a non-rotating block device. These
>>> are the same constraints as for the existing PMD-sized THP swap-out
>>> support.
>>> Note that no attempt is made to swap-in (m)THP here - this is still
>>> done
>>> page-by-page, like for PMD-sized THP. But swapping-out mTHP is a
>>> prerequisite for swapping-in mTHP.
>>> The main change here is to improve the swap entry allocator so that
>>> it
>>> can allocate any power-of-2 number of contiguous entries between [1, (1
>>> << PMD_ORDER)]. This is done by allocating a cluster for each distinct
>>> order and allocating sequentially from it until the cluster is full.
>>> This ensures that we don't need to search the map and we get no
>>> fragmentation due to alignment padding for different orders in the
>>> cluster. If there is no current cluster for a given order, we attempt to
>>> allocate a free cluster from the list. If there are no free clusters, we
>>> fail the allocation and the caller can fall back to splitting the folio
>>> and allocates individual entries (as per existing PMD-sized THP
>>> fallback).
>>> The per-order current clusters are maintained per-cpu using the
>>> existing
>>> infrastructure. This is done to avoid interleving pages from different
>>> tasks, which would prevent IO being batched. This is already done for
>>> the order-0 allocations so we follow the same pattern.
>>> As is done for order-0 per-cpu clusters, the scanner now can steal
>>> order-0 entries from any per-cpu-per-order reserved cluster. This
>>> ensures that when the swap file is getting full, space doesn't get tied
>>> up in the per-cpu reserves.
>>> This change only modifies swap to be able to accept any order
>>> mTHP. It
>>> doesn't change the callers to elide doing the actual split. That will be
>>> done in separate changes.
>>> Reviewed-by: "Huang, Ying" <ying.huang@intel.com>
>>> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
>>> ---
>>> include/linux/swap.h | 10 ++-
>>> mm/swap_slots.c | 6 +-
>>> mm/swapfile.c | 175 ++++++++++++++++++++++++-------------------
>>> 3 files changed, 109 insertions(+), 82 deletions(-)
>>> diff --git a/include/linux/swap.h b/include/linux/swap.h
>>> index 5e1e4f5bf0cb..11c53692f65f 100644
>>> --- a/include/linux/swap.h
>>> +++ b/include/linux/swap.h
>>> @@ -268,13 +268,19 @@ struct swap_cluster_info {
>>> */
>>> #define SWAP_NEXT_INVALID 0
>>> +#ifdef CONFIG_THP_SWAP
>>> +#define SWAP_NR_ORDERS (PMD_ORDER + 1)
>>> +#else
>>> +#define SWAP_NR_ORDERS 1
>>> +#endif
>>> +
>>> /*
>>> * We assign a cluster to each CPU, so each CPU can allocate swap entry from
>>> * its own cluster and swapout sequentially. The purpose is to optimize swapout
>>> * throughput.
>>> */
>>> struct percpu_cluster {
>>> - unsigned int next; /* Likely next allocation offset */
>>> + unsigned int next[SWAP_NR_ORDERS]; /* Likely next allocation offset */
>>> };
>>> struct swap_cluster_list {
>>> @@ -471,7 +477,7 @@ swp_entry_t folio_alloc_swap(struct folio *folio);
>>> bool folio_free_swap(struct folio *folio);
>>> void put_swap_folio(struct folio *folio, swp_entry_t entry);
>>> extern swp_entry_t get_swap_page_of_type(int);
>>> -extern int get_swap_pages(int n, swp_entry_t swp_entries[], int entry_size);
>>> +extern int get_swap_pages(int n, swp_entry_t swp_entries[], int order);
>>> extern int add_swap_count_continuation(swp_entry_t, gfp_t);
>>> extern void swap_shmem_alloc(swp_entry_t);
>>> extern int swap_duplicate(swp_entry_t);
>>> diff --git a/mm/swap_slots.c b/mm/swap_slots.c
>>> index 53abeaf1371d..13ab3b771409 100644
>>> --- a/mm/swap_slots.c
>>> +++ b/mm/swap_slots.c
>>> @@ -264,7 +264,7 @@ static int refill_swap_slots_cache(struct swap_slots_cache *cache)
>>> cache->cur = 0;
>>> if (swap_slot_cache_active)
>>> cache->nr = get_swap_pages(SWAP_SLOTS_CACHE_SIZE,
>>> - cache->slots, 1);
>>> + cache->slots, 0);
>>> return cache->nr;
>>> }
>>> @@ -311,7 +311,7 @@ swp_entry_t folio_alloc_swap(struct folio *folio)
>>> if (folio_test_large(folio)) {
>>> if (IS_ENABLED(CONFIG_THP_SWAP))
>>> - get_swap_pages(1, &entry, folio_nr_pages(folio));
>>> + get_swap_pages(1, &entry, folio_order(folio));
>>
>> The only comment I have is that this nr_pages -> order conversion adds
>> a bit of noise to this patch.
>>
>> AFAIKS, it's primarily only required for "cluster->next[order]",
>> everything else doesn't really require the order.
>>
>> I'd just have split that out into a separate patch, or simply
>> converted nr_pages -> order where required.
>>
>> Nothing jumped at me, but I'm not an expert on that code, so I'm
>> mostly trusting the others ;)
>
> The nr_pages -> order conversion replaces ilog2(nr_pages) with
> (1<<order). IIUC, "<<" is a little faster than "ilog2()". And, we
> don't need to worry about whether nr_pages is a power of 2. Do you
> think that this makes sense?
I think that David's point was that I should just split out that change to its
own patch to aid readability? I'm happy to do that if no one objects.
>
> --
> Best Regards,
> Huang, Ying
next prev parent reply other threads:[~2024-04-08 9:24 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-03 11:40 [PATCH v6 0/6] Swap-out mTHP without splitting Ryan Roberts
2024-04-03 11:40 ` [PATCH v6 1/6] mm: swap: Remove CLUSTER_FLAG_HUGE from swap_cluster_info:flags Ryan Roberts
2024-04-03 22:12 ` Chris Li
2024-04-04 7:06 ` Ryan Roberts
2024-04-04 13:43 ` Chris Li
2024-04-08 11:56 ` Ryan Roberts
2024-04-05 9:25 ` David Hildenbrand
2024-04-03 11:40 ` [PATCH v6 2/6] mm: swap: free_swap_and_cache_nr() as batched free_swap_and_cache() Ryan Roberts
2024-04-05 10:13 ` David Hildenbrand
2024-04-08 9:22 ` Ryan Roberts
2024-04-08 9:43 ` David Hildenbrand
2024-04-08 10:07 ` Ryan Roberts
2024-04-08 10:24 ` David Hildenbrand
2024-04-08 10:39 ` Ryan Roberts
2024-04-08 12:07 ` Ryan Roberts
2024-04-08 12:47 ` Ryan Roberts
2024-04-08 13:27 ` Ryan Roberts
2024-04-08 15:13 ` David Hildenbrand
2024-04-03 11:40 ` [PATCH v6 3/6] mm: swap: Simplify struct percpu_cluster Ryan Roberts
2024-04-03 11:40 ` [PATCH v6 4/6] mm: swap: Allow storage of all mTHP orders Ryan Roberts
2024-04-05 10:38 ` David Hildenbrand
2024-04-07 6:02 ` Huang, Ying
2024-04-08 9:24 ` Ryan Roberts [this message]
2024-04-08 9:33 ` David Hildenbrand
2024-04-08 9:35 ` Ryan Roberts
2024-04-07 7:38 ` Barry Song
2024-04-08 9:28 ` Ryan Roberts
2024-04-03 11:40 ` [PATCH v6 5/6] mm: vmscan: Avoid split during shrink_folio_list() Ryan Roberts
2024-04-05 10:42 ` David Hildenbrand
2024-04-08 9:31 ` Ryan Roberts
2024-04-03 11:40 ` [PATCH v6 6/6] mm: madvise: Avoid split during MADV_PAGEOUT and MADV_COLD Ryan Roberts
2024-04-03 17:17 ` Ryan Roberts
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=ba63464e-afc3-4bbb-b13f-704eaf9ed4af@arm.com \
--to=ryan.roberts@arm.com \
--cc=21cnbao@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=chrisl@kernel.org \
--cc=david@redhat.com \
--cc=ioworker0@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mhocko@suse.com \
--cc=shy828301@gmail.com \
--cc=wangkefeng.wang@huawei.com \
--cc=willy@infradead.org \
--cc=xiang@kernel.org \
--cc=ying.huang@intel.com \
--cc=yuzhao@google.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.