From: Balbir Singh <balbirs@nvidia.com>
To: Li Zhe <lizhe.67@bytedance.com>
Cc: akpm@linux-foundation.org, apopple@nvidia.com, arnd@arndb.de,
bp@alien8.de, dave.hansen@linux.intel.com, david@kernel.org,
kees@kernel.org, mingo@redhat.com, rppt@kernel.org,
tglx@kernel.org, linux-arch@vger.kernel.org,
linux-hardening@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-mm@kvack.org, x86@kernel.org
Subject: Re: [PATCH v6 0/8] mm: optimize zone-device memmap initialization
Date: Mon, 13 Jul 2026 11:44:03 +1000 [thread overview]
Message-ID: <alRCNbTlRFyD8f-1@parvat> (raw)
In-Reply-To: <20260709112520.24857-1-lizhe.67@bytedance.com>
On Thu, Jul 09, 2026 at 07:25:12PM +0800, Li Zhe wrote:
> memmap_init_zone_device() can take a noticeable amount of time when large
> pmem namespaces are bound or rebound, because it initializes nearly
> identical struct page descriptors one PFN at a time. This series reduces
> that ZONE_DEVICE memmap initialization overhead by reusing prepared
> struct page templates and, on x86, using memcpy_nt() for the template
> copy path.
>
Is the slowness specific to an architecture? Do you have any test
results from any other arch?
> The main target is large fsdax/devdax pmem configurations, where the
> cost of initializing the memmap shows up directly in nd_pmem/dax_pmem
> bind and rebind latency.
>
> Patches 1-3 are preparatory cleanups and helper extraction. Patches 4-5
> add the template-copy fast path for head pages and compound tails.
> Patches 6-8 introduce memcpy_nt()/memcpy_nt_drain(), extend the x86
> fixed-size memcpy_flushcache() inline cases used by that helper, and
> switch the template-copy path over to memcpy_nt().
>
> The fast path remains disabled when the page_ref_set tracepoint is
> active, and sanitized builds stay on the slow path so their instrumented
> stores are preserved. Architectures without a specialized memcpy_nt()
> backend continue to fall back to memcpy().
>
> Tested in a VM with a 100 GB fsdax namespace device configured with
> map=dev and a 100 GB devdax namespace (align=2097152) on Intel Ice Lake
> server.
>
> Test procedure:
> Rebind the nd_pmem and dax_pmem driver 30 times and collect the memmap
> initialization time from the pr_debug() output of
> memmap_init_zone_device().
>
> Base(v7.2-rc1):
> First binding for nd_pmem driver: 1456 ms
> Average of subsequent rebinds: 244.28 ms
>
> First binding for dax_pmem driver: 1462 ms
> Average of subsequent rebinds: 273.31 ms
>
> With this series applied:
> First binding for nd_pmem driver: 1272 ms
> Average of subsequent rebinds: 96.79 ms
>
> First binding for dax_pmem driver: 1354 ms
> Average of subsequent rebinds: 119.04 ms
>
> This reduces the average rebind time by about 60.4% for nd_pmem and
> 56.4% for dax_pmem.
>
> As an additional data point, I also ran a smaller set of measurements on
> the same physical x86_64 host with a 100 GB PMEM region created via the
> memmap= kernel command line, configured as fsdax and devdax namespaces
> with map=dev and 2 MiB alignment.
>
> For brevity, the individual patches keep only the VM results rather than
> including a second set of physical-host measurements throughout the
> series. The physical-host numbers below are included only as
> supplemental evidence that the same optimization also provides a similar
> benefit on a non-virtualized system.
>
> Test procedure:
> Reconfigure the namespace mode, rebind the nd_pmem or dax_pmem driver
> once, and collect the memmap initialization time from the pr_debug()
> output of memmap_init_zone_device().
>
> Base (v7.2-rc1):
> nd_pmem / fsdax: 179 ms
> dax_pmem / devdax: 264 ms
>
> With this series applied:
> nd_pmem / fsdax: 82 ms
> dax_pmem / devdax: 113 ms
>
> This reduces the measured rebind time by about 54.2% for nd_pmem and
> 57.2% for dax_pmem on that setup, which is broadly consistent with the
> VM results above.
>
> As another supplemental data point, I also measured the test_hmm.ko
> module on the same physical x86_64 host, using the test_hmm.ko setup
> from the previous discussion that times ten 64 GB
> memremap_pages()/memunmap_pages() iterations during module insertion[1].
> By default, module insertion initializes two DEVICE_PRIVATE dmirror
> devices, so two avg memremap values are reported; each value is the
> average for one 64 GB chunk.
>
> This is not the primary target workload of the series, but it exercises
> the same large ZONE_DEVICE memmap initialization path and shows the same
> direction of improvement.
>
> Base (v7.2-rc1):
> avg memremap reported during module insertion: 116689362 ns, 116539263 ns
>
> With this series applied:
> avg memremap reported during module insertion: 54607108 ns, 54458236 ns
>
> This corresponds to about a 53.2% reduction based on the mean of the
> reported values, which is again consistent with the pmem bind/rebind
> results above.
>
That is a good result, thanks for sharing
> [1] https://lore.kernel.org/all/aiEoByaQdRR3xtM5@nvdebian.thelocal/
>
> Li Zhe (8):
> mm: fix stale ZONE_DEVICE refcount comment
> mm: factor zone-device page init helpers out of
> __init_zone_device_page
> mm: add a set_page_section_from_pfn() helper
> mm: add a template-based fast path for zone-device page init
> mm: extend the template fast path to zone-device compound tails
> string: introduce memcpy_nt() helpers
> x86/string: extend memcpy_flushcache() fixed-size fastpaths
> mm: use memcpy_nt() in zone-device template copies
>
> arch/x86/include/asm/string_64.h | 78 ++++++++++++-
> include/linux/mm.h | 15 ++-
> include/linux/string.h | 23 ++++
> mm/mm_init.c | 186 ++++++++++++++++++++++++++-----
> 4 files changed, 273 insertions(+), 29 deletions(-)
>
> ---
> v5: https://lore.kernel.org/all/20260701090553.62691-1-lizhe.67@bytedance.com/
> v4: https://lore.kernel.org/all/20260603080152.64728-1-lizhe.67@bytedance.com/
> v3: https://lore.kernel.org/all/20260527033636.28231-1-lizhe.67@bytedance.com/
> v2: https://lore.kernel.org/all/20260521040124.10608-1-lizhe.67@bytedance.com/
> v1: https://lore.kernel.org/all/20260515082045.63029-1-lizhe.67@bytedance.com/
>
> Changelogs:
>
> v5->v6:
> - Rework patch 6 so the x86 memcpy_nt_drain() helper uses wmb()
> instead of an open-coded sfence, while architectures that do not
> override memcpy_nt() keep the generic no-op drain fallback.
> Suggested by Borislav Petkov.
> - Rework patch 6 to use the usual self-macro override pattern for
> memcpy_nt() and memcpy_nt_drain() instead of a dedicated
> __HAVE_ARCH_MEMCPY_NT feature macro. Suggested by David
> Hildenbrand.
> - Drop the default: case from pagemap_resets_refcount() and drop the
> WARN_ONCE() after the switch so newly added enum memory_type values
> remain visible to compiler switch checking. Suggested by David
> Hildenbrand.
> - Drop the unnecessary empty set_page_section() stub from patch 3, keep
> set_page_section_from_pfn() as the only !SECTION_IN_PAGE_FLAGS no-op
> helper and fix its indentation. Suggested by David Hildenbrand.
> - Rework patch 4 so the reusable head-page template is seeded from the
> first loop iteration, keeping the main loop intact while ensuring the
> first page is initialized only once; also drop the extra template
> memcpy helper, as suggested by Alistair Popple.
> - Rework patch 5 similarly for compound tails: seed the reusable tail
> template from the first tail-page iteration so the first tail page is
> initialized only once, while keeping the main tail loop intact, as
> suggested by Alistair Popple.
> - Rework patch 7 to rename the internal fixed-size MOVNTI helpers to
> movnti_*(), keep memcpy_flushcache() as the externally visible
> wrapper, fold the new 32/48/64/80/96-byte copies into the main
> fixed-size switch, clarify in the code and changelog that the
> ZONE_DEVICE template-copy path relies on the 64/80/96-byte struct
> page copies while 32/48-byte copies stay inline as well, and drop the
> separate alignment check based on the physical-host microbenchmark
> results. Suggested by Borislav Petkov.
> - Run v6 VM spot checks for the fsdax/devdax map=dev paths. The
> results stayed in the same ballpark as v5, so keep the previously
> posted v5 full-run numbers in this version instead of replacing them
> with another partial data set.
>
> For changelogs of earlier revisions, please refer to the v5 cover letter.
>
> --
> 2.20.1
Balbir
next prev parent reply other threads:[~2026-07-13 1:44 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-09 11:25 [PATCH v6 0/8] mm: optimize zone-device memmap initialization Li Zhe
2026-07-09 11:25 ` [PATCH v6 1/8] mm: fix stale ZONE_DEVICE refcount comment Li Zhe
2026-07-14 2:25 ` Muchun Song
2026-07-09 11:25 ` [PATCH v6 2/8] mm: factor zone-device page init helpers out of __init_zone_device_page Li Zhe
2026-07-14 2:44 ` Muchun Song
2026-07-14 11:35 ` Balbir Singh
2026-07-09 11:25 ` [PATCH v6 3/8] mm: add a set_page_section_from_pfn() helper Li Zhe
2026-07-14 2:45 ` Muchun Song
2026-07-14 12:09 ` Balbir Singh
2026-07-09 11:25 ` [PATCH v6 4/8] mm: add a template-based fast path for zone-device page init Li Zhe
2026-07-13 13:28 ` Muchun Song
2026-07-14 8:38 ` Muchun Song
2026-07-09 11:25 ` [PATCH v6 5/8] mm: extend the template fast path to zone-device compound tails Li Zhe
2026-07-09 11:25 ` [PATCH v6 6/8] string: introduce memcpy_nt() helpers Li Zhe
2026-07-14 9:24 ` Muchun Song
2026-07-09 11:25 ` [PATCH v6 7/8] x86/string: extend memcpy_flushcache() fixed-size fastpaths Li Zhe
2026-07-09 11:25 ` [PATCH v6 8/8] mm: use memcpy_nt() in zone-device template copies Li Zhe
2026-07-14 9:45 ` Muchun Song
2026-07-14 11:22 ` Muchun Song
2026-07-13 1:44 ` Balbir Singh [this message]
2026-07-13 3:18 ` [PATCH v6 0/8] mm: optimize zone-device memmap initialization ByteDance
2026-07-13 13:15 ` Muchun Song
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=alRCNbTlRFyD8f-1@parvat \
--to=balbirs@nvidia.com \
--cc=akpm@linux-foundation.org \
--cc=apopple@nvidia.com \
--cc=arnd@arndb.de \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=david@kernel.org \
--cc=kees@kernel.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=lizhe.67@bytedance.com \
--cc=mingo@redhat.com \
--cc=rppt@kernel.org \
--cc=tglx@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