Skip to content

Commit 8e38607

Browse files
David Hildenbrandakpm00
authored andcommitted
treewide: provide a generic clear_user_page() variant
Patch series "mm: folio_zero_user: clear page ranges", v11. This series adds clearing of contiguous page ranges for hugepages. The series improves on the current discontiguous clearing approach in two ways: - clear pages in a contiguous fashion. - use batched clearing via clear_pages() wherever exposed. The first is useful because it allows us to make much better use of hardware prefetchers. The second, enables advertising the real extent to the processor. Where specific instructions support it (ex. string instructions on x86; "mops" on arm64 etc), a processor can optimize based on this because, instead of seeing a sequence of 8-byte stores, or a sequence of 4KB pages, it sees a larger unit being operated on. For instance, AMD Zen uarchs (for extents larger than LLC-size) switch to a mode where they start eliding cacheline allocation. This is helpful not just because it results in higher bandwidth, but also because now the cache is not evicting useful cachelines and replacing them with zeroes. Demand faulting a 64GB region shows performance improvement: $ perf bench mem mmap -p $pg-sz -f demand -s 64GB -l 5 baseline +series (GBps +- %stdev) (GBps +- %stdev) pg-sz=2MB 11.76 +- 1.10% 25.34 +- 1.18% [*] +115.47% preempt=* pg-sz=1GB 24.85 +- 2.41% 39.22 +- 2.32% + 57.82% preempt=none|voluntary pg-sz=1GB (similar) 52.73 +- 0.20% [#] +112.19% preempt=full|lazy [*] This improvement is because switching to sequential clearing allows the hardware prefetchers to do a much better job. [#] For pg-sz=1GB a large part of the improvement is because of the cacheline elision mentioned above. preempt=full|lazy improves upon that because, not needing explicit invocations of cond_resched() to ensure reasonable preemption latency, it can clear the full extent as a single unit. In comparison the maximum extent used for preempt=none|voluntary is PROCESS_PAGES_NON_PREEMPT_BATCH (32MB). When provided the full extent the processor forgoes allocating cachelines on this path almost entirely. (The hope is that eventually, in the fullness of time, the lazy preemption model will be able to do the same job that none or voluntary models are used for, allowing us to do away with cond_resched().) Raghavendra also tested previous version of the series on AMD Genoa and sees similar improvement [1] with preempt=lazy. $ perf bench mem map -p $page-size -f populate -s 64GB -l 10 base patched change pg-sz=2MB 12.731939 GB/sec 26.304263 GB/sec 106.6% pg-sz=1GB 26.232423 GB/sec 61.174836 GB/sec 133.2% This patch (of 8): Let's drop all variants that effectively map to clear_page() and provide it in a generic variant instead. We'll use the macro clear_user_page to indicate whether an architecture provides it's own variant. Also, clear_user_page() is only called from the generic variant of clear_user_highpage(), so define it only if the architecture does not provide a clear_user_highpage(). And, for simplicity define it in linux/highmem.h. Note that for parisc, clear_page() and clear_user_page() map to clear_page_asm(), so we can just get rid of the custom clear_user_page() implementation. There is a clear_user_page_asm() function on parisc, that seems to be unused. Not sure what's up with that. Link: https://lkml.kernel.org/r/20260107072009.1615991-1-ankur.a.arora@oracle.com Link: https://lkml.kernel.org/r/20260107072009.1615991-2-ankur.a.arora@oracle.com Signed-off-by: David Hildenbrand <david@redhat.com> Co-developed-by: Ankur Arora <ankur.a.arora@oracle.com> Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Ankur Arora <ankur.a.arora@oracle.com> Cc: "Borislav Petkov (AMD)" <bp@alien8.de> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: David Hildenbrand <david@kernel.org> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Konrad Rzessutek Wilk <konrad.wilk@oracle.com> Cc: Lance Yang <ioworker0@gmail.com> Cc: "Liam R. Howlett" <Liam.Howlett@oracle.com> Cc: Li Zhe <lizhe.67@bytedance.com> Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Cc: Mateusz Guzik <mjguzik@gmail.com> Cc: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Michal Hocko <mhocko@suse.com> Cc: Mike Rapoport <rppt@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Raghavendra K T <raghavendra.kt@amd.com> Cc: Suren Baghdasaryan <surenb@google.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 8b05d2d commit 8e38607

22 files changed

Lines changed: 29 additions & 28 deletions

File tree

arch/alpha/include/asm/page.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#define STRICT_MM_TYPECHECKS
1212

1313
extern void clear_page(void *page);
14-
#define clear_user_page(page, vaddr, pg) clear_page(page)
1514

1615
#define vma_alloc_zeroed_movable_folio(vma, vaddr) \
1716
vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr)

arch/arc/include/asm/page.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ struct page;
3232

3333
void copy_user_highpage(struct page *to, struct page *from,
3434
unsigned long u_vaddr, struct vm_area_struct *vma);
35+
36+
#define clear_user_page clear_user_page
3537
void clear_user_page(void *to, unsigned long u_vaddr, struct page *page);
3638

3739
typedef struct {

arch/arm/include/asm/page-nommu.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#define clear_page(page) memset((page), 0, PAGE_SIZE)
1212
#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE)
1313

14-
#define clear_user_page(page, vaddr, pg) clear_page(page)
1514
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
1615

1716
/*

arch/arm64/include/asm/page.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ struct folio *vma_alloc_zeroed_movable_folio(struct vm_area_struct *vma,
3636
bool tag_clear_highpages(struct page *to, int numpages);
3737
#define __HAVE_ARCH_TAG_CLEAR_HIGHPAGES
3838

39-
#define clear_user_page(page, vaddr, pg) clear_page(page)
4039
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
4140

4241
typedef struct page *pgtable_t;

arch/csky/abiv1/inc/abi/page.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ static inline unsigned long pages_do_alias(unsigned long addr1,
1010
return (addr1 ^ addr2) & (SHMLBA-1);
1111
}
1212

13+
#define clear_user_page clear_user_page
1314
static inline void clear_user_page(void *addr, unsigned long vaddr,
1415
struct page *page)
1516
{

arch/csky/abiv2/inc/abi/page.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
11
/* SPDX-License-Identifier: GPL-2.0 */
2-
3-
static inline void clear_user_page(void *addr, unsigned long vaddr,
4-
struct page *page)
5-
{
6-
clear_page(addr);
7-
}
8-
92
static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
103
struct page *page)
114
{

arch/hexagon/include/asm/page.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ static inline void clear_page(void *page)
113113
/*
114114
* Under assumption that kernel always "sees" user map...
115115
*/
116-
#define clear_user_page(page, vaddr, pg) clear_page(page)
117116
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
118117

119118
static inline unsigned long virt_to_pfn(const void *kaddr)

arch/loongarch/include/asm/page.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
extern void clear_page(void *page);
3131
extern void copy_page(void *to, void *from);
3232

33-
#define clear_user_page(page, vaddr, pg) clear_page(page)
3433
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
3534

3635
extern unsigned long shm_align_mask;

arch/m68k/include/asm/page_no.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ extern unsigned long memory_end;
1010
#define clear_page(page) memset((page), 0, PAGE_SIZE)
1111
#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE)
1212

13-
#define clear_user_page(page, vaddr, pg) clear_page(page)
1413
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
1514

1615
#define vma_alloc_zeroed_movable_folio(vma, vaddr) \

arch/microblaze/include/asm/page.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ typedef unsigned long pte_basic_t;
4545
# define copy_page(to, from) memcpy((to), (from), PAGE_SIZE)
4646
# define clear_page(pgaddr) memset((pgaddr), 0, PAGE_SIZE)
4747

48-
# define clear_user_page(pgaddr, vaddr, page) memset((pgaddr), 0, PAGE_SIZE)
4948
# define copy_user_page(vto, vfrom, vaddr, topg) \
5049
memcpy((vto), (vfrom), PAGE_SIZE)
5150

0 commit comments

Comments
 (0)