mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "David Hildenbrand (Arm)" <david@kernel.org>
To: "Garg, Shivank" <shivankg@amd.com>,
	Andrew Morton <akpm@linux-foundation.org>,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org, x86@kernel.org
Cc: Lorenzo Stoakes <ljs@kernel.org>,
	"Liam R . Howlett" <Liam.Howlett@oracle.com>,
	Vlastimil Babka <vbabka@kernel.org>,
	Mike Rapoport <rppt@kernel.org>,
	Suren Baghdasaryan <surenb@google.com>,
	Michal Hocko <mhocko@suse.com>, Thomas Gleixner <tglx@kernel.org>,
	Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	"H . Peter Anvin" <hpa@zytor.com>,
	Ankur Arora <ankur.a.arora@oracle.com>,
	Bharata B Rao <bharata@amd.com>,
	Hrushikesh Salunke <hsalunke@amd.com>,
	David Rientjes <rientjes@google.com>,
	sandipan.das@amd.com
Subject: Re: [RFC PATCH 1/1] mm: batch page copies in folio_copy() and folio_mc_copy()
Date: Mon, 18 May 2026 10:43:22 +0200	[thread overview]
Message-ID: <60fb497d-a35a-42b9-8bf1-7f9ccbde8ade@kernel.org> (raw)
In-Reply-To: <6a5e794a-a608-4126-9abe-0d512a57dd67@amd.com>

On 5/14/26 07:17, Garg, Shivank wrote:
> 
> 
> On 5/12/2026 3:01 PM, David Hildenbrand (Arm) wrote:
>> On 4/27/26 16:20, Shivank Garg wrote:
>>> Rewrite folio_copy() and folio_mc_copy() as thin wrappers around new
>>> batched helpers copy_highpages() and copy_mc_highpages().
>>>
>>> The current implementations iterate copy_highpage() (or its #MC-aware
>>> variant) per 4 KB page. For a single 2 MB folio that loop runs 512
>>> times and pays, per page:
>>>
>>>   - kmap_local_page() / kunmap_local()
>>>   - cond_resched()
>>>   - one invocation of the architecture copy_page()/memcpy() primitive
>>>
>>> The new helpers issue a single copy_mc_to_kernel()/memcpy() over
>>> the whole contiguous range when CONFIG_HIGHMEM is off and no
>>> architecture overrides (__HAVE_ARCH_COPY_HIGHPAGE) copy_highpage().
>>> HIGHMEM and arch overrides keep the existing per-page path.
>>>
>>> Tested on dual-socket AMD EPYC 9655 (Zen 5) with a CXL.mem node.
>>> In-kernel folio_mc_copy() microbenchmark on 2 MB folios, source
>>> evicted from cache before each iteration and measured throughput:
>>>
>>>   direction         baseline GB/s   optimized GB/s   speedup
>>>   DRAM0 -> DRAM1     18.65 ± 1.37    38.03 ± 3.21     2.04x
>>>   DRAM0 -> CXL       25.46 ± 2.89    39.29 ± 1.17     1.54x
>>>   CXL   -> DRAM0     20.61 ± 3.95    35.07 ± 0.62     1.70x
>>>
>>> End-to-end move_pages(2) throughput on anonymous 2 MB mTHP folios,
>>> 1 GB migrated per run:
>>>
>>>   direction         baseline GB/s   optimized GB/s   speedup
>>>   DRAM0 -> DRAM1      7.20 ± 0.03     8.01 ± 0.02     1.11x
>>>   DRAM0 -> CXL       11.12 ± 0.15    13.07 ± 0.03     1.18x
>>>   DRAM1 -> DRAM0      7.21 ± 0.02     7.95 ± 0.02     1.10x
>>>   CXL   -> DRAM0      9.10 ± 0.05     9.49 ± 0.01     1.04x
>>>
>>> On AMD EPYC 7713 (Zen 3 / Milan, REP_GOOD without FSRM/ERMS) the
>>> folio_copy() bulk path regresses because memcpy() falls through to
>>> memcpy_orig (an unrolled movq loop), which is slower than the
>>> per-page copy_page() (microcoded rep movsq) it replaces. 
>>
>> Do you know what the reason for that fallback is? Could it be fixed (e.g., when
>> we detect page alignment or sth like that?)
>>
> 
> The fallback is gated on X86_FEATURE_FSRM in arch/x86/lib/memcpy_64.S:
> 
> SYM_TYPED_FUNC_START(__memcpy)
> 	ALTERNATIVE "jmp memcpy_orig", "", X86_FEATURE_FSRM
> 	movq %rdi, %rax
> 	movq %rdx, %rcx
> 	rep movsb
> 	RET
> 
> AMD Zen 3 does not have FSRM, so it jmp to memcpy_orig (unrolled movq loop).
> 
> 
> On v7.1.0-rc3, I measured these primitives and the kernel's actual memcpy()
> across three CPUs, using a kernel module that vmallocs 16MB src/dst buffer
> and times each primitive for comparison.
> Numbers are mean (in GB/s) ± SD% (= SD as percent of mean).
> 
> 
> 1.) AMD EPYC 7713 (Zen 3), Flags: rep_good only, no ERMS/FSRM:
> 
>   size   unrolled_movq GB/s±SD%   rep_movsq GB/s±SD%  kernel_memcpy GB/s±SD%  
> ------------------------------------------------------------------------------
>    16B      0.38± 8.73%            0.41± 0.43%            0.43± 0.31%
>    32B      0.85± 0.19%            0.80± 8.37%            0.84± 0.07%
>    64B      1.68± 0.35%            1.60± 0.03%            1.59± 9.37%
>   128B      3.23± 0.22%            3.04± 0.62%            3.19± 0.03%
>   256B      5.99± 5.78%            5.62± 4.15%            5.93± 0.42%
>   512B     10.07± 1.36%           10.49± 2.60%           10.02± 0.21%
>     1K     14.49± 0.09%           18.19± 0.37%           14.31± 3.48%
>     2K     17.11± 1.01%           28.04± 2.37%           18.14± 0.56%
>     4K     18.36± 0.22%           39.15± 0.50%           19.57± 1.14%
> 
> - kernel_memcpy is tracking unrolled_movq.
> - rep_movsq is 1.4x-2x faster than the unrolled_movq fallback for >= 1 KiB.
> 
> 2.) On Intel(R) Xeon(R) Platinum 8362
> Flags: rep_good, erms, fsrm
> 
>   size  unrolled_movq GB/s±SD%   rep_movsq GB/s±SD%   rep_movsb GB/s±SD%   kernel_memcpy GB/s±SD%
> --------------------------------------------------------------------------------------------
>    16B      0.89± 0.93%            0.64± 0.10%            0.69± 0.57%            0.66± 3.52%
>    32B      2.08± 2.46%            1.28± 0.15%            1.38± 6.21%            1.33± 4.28%
>    64B      3.97± 2.26%            2.55± 0.24%            2.83± 0.22%            2.65± 4.48%
>   128B      7.45± 0.09%            5.00± 2.53%            5.48± 5.04%            5.30± 1.60%
>   256B     13.24± 0.01%            9.79± 0.57%           10.12± 0.37%            9.81± 0.34%
>   512B     21.67± 0.03%           17.87± 0.02%           18.43± 0.79%           17.81± 0.25%
>     1K     27.84± 1.96%           34.54± 1.24%           35.67± 1.88%           34.56± 2.49%
>     2K     32.67± 2.35%           59.58± 0.01%           65.67± 0.18%           59.35± 1.12%
>     4K     34.85± 0.64%           95.35± 0.00%           96.64± 0.69%           95.35± 0.00%
> 
> - kernel_memcpy is using rep_movsb (FSRM in use). 
> - Below 512 B the unrolled movq loop is ~20-50% faster, >1 KiB FSRM wins.
> 
> 3.) On AMD EPYC 9655 96-Core Processor (Zen 5)
> Flags: rep_good, erms, fsrm
> 
> size   unrolled_movq GB/s±SD%    rep_movsq GB/s±SD%       rep_movsb GB/s±SD%   kernel_memcpy GB/s±SD%
> --------------------------------------------------------------------------------------------
>    16B      0.53± 0.39%            0.53± 0.21%            0.55± 0.13%            0.53± 0.14%
>    32B      1.13± 1.49%            1.06± 0.07%            1.09± 0.16%            1.06± 0.09%
>    64B      2.21± 0.12%            2.13± 0.07%            2.18± 0.14%            2.13± 0.09%
>   128B      4.25± 0.12%            4.26± 0.10%            4.37± 0.12%            4.31± 0.14%
>   256B      8.01± 0.19%            8.61± 0.27%            8.61± 0.18%            8.51± 0.10%
>   512B     14.14± 0.18%           16.80± 0.24%           16.80± 0.23%           16.81± 0.24%
>     1K     22.93± 0.73%           31.70± 0.48%           32.37± 0.28%           32.02± 0.22%
>     2K     30.36± 0.27%           53.24± 1.01%           56.58± 0.22%           56.04± 0.22%
>     4K     35.05± 0.65%           80.25± 0.41%           83.90± 0.20%           76.23± 0.37%
> 
> - kernel_memcpy is using rep_movsb (FSRM in use). 
> - For smaller size, unrolled movq are close enough to be within noise.
> 
> 
> Regarding the fix,
> One option is to make memcpy() fall back to rep movsq instead of unrolled
> movq loop when FSRM is absent. The data shows the benefit on Zen 3. For
> the Intel, unrolled movq is faster for smaller sizes.
> But, I'm not sure if adding these complexities to memcpy() is welcome.
> Happy to work on this if it is helpful.

I was wondering whether optimizing memcpy() further would be of value elsewhere.

Of course, we wouldn't want to degrade it :)

Some direction from x86 folks would be nice.

> 
> Another option is to leave memcpy() untouched for this series and add
> a new copy_pages() helper that the folio copy path can use. It would
> use ALTERNATIVE_2 that picks rep movsb on ERMS/FSRM and rep movsq on
> REP_GOOD and per-page copy_page() loop as the final fallback.

That would fit the clear_pages() design we have. But if that's avoidable, that
would be nice.

-- 
Cheers,

David

  reply	other threads:[~2026-05-18  8:43 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-27 14:20 [RFC PATCH 0/1] " Shivank Garg
2026-04-27 14:20 ` [RFC PATCH 1/1] mm: " Shivank Garg
2026-05-12  9:31   ` David Hildenbrand (Arm)
2026-05-14  5:17     ` Garg, Shivank
2026-05-18  8:43       ` David Hildenbrand (Arm) [this message]
2026-05-18 14:20         ` David Laight
2026-05-19  5:43           ` Garg, Shivank
2026-05-18 16:01         ` Borislav Petkov
2026-05-19  7:44           ` Garg, Shivank

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=60fb497d-a35a-42b9-8bf1-7f9ccbde8ade@kernel.org \
    --to=david@kernel.org \
    --cc=Liam.Howlett@oracle.com \
    --cc=akpm@linux-foundation.org \
    --cc=ankur.a.arora@oracle.com \
    --cc=bharata@amd.com \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=hsalunke@amd.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=ljs@kernel.org \
    --cc=mhocko@suse.com \
    --cc=mingo@redhat.com \
    --cc=rientjes@google.com \
    --cc=rppt@kernel.org \
    --cc=sandipan.das@amd.com \
    --cc=shivankg@amd.com \
    --cc=surenb@google.com \
    --cc=tglx@kernel.org \
    --cc=vbabka@kernel.org \
    --cc=x86@kernel.org \
    /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