mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Yuan-Hao Hsu <aa9736195201@gmail.com>
To: Andrew Morton <akpm@linux-foundation.org>,
	David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>,
	liam@infradead.org, Vlastimil Babka <vbabka@kernel.org>,
	Mike Rapoport <rppt@kernel.org>,
	Suren Baghdasaryan <surenb@google.com>,
	Michal Hocko <mhocko@suse.com>, Barry Song <baohua@kernel.org>,
	Ryan Roberts <ryan.roberts@arm.com>, Dev Jain <dev.jain@arm.com>,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org
Subject: [PATCH v2 2/2] mm/memory: reuse the whole exclusive large folio on a write fault
Date: Sat, 19 Sep 2026 15:31:33 +0800	[thread overview]
Message-ID: <20260919073134.639-3-aa9736195201@gmail.com> (raw)
In-Reply-To: <20260919073134.639-1-aa9736195201@gmail.com>

With blocks of 16 PTEs a PTE-mapped 2M THP still takes 32 reuse faults
and a 1M folio 16.  Lift the bound to the page table: the walk then
covers the PTEs that map the folio in this page table, at most
PTRS_PER_PTE of them, and one fault does the work for the folio.

Its cost, measured as the time of the store that takes it, against
420 ns for a reuse fault today (x86-64, i7-12700KF, medians, ns):

                          reuse fault   fault that     COW fault that
                          (patched)     allocated it   copies 4K
      1M mTHP            5,400- 5,700   63,000-68,000          1,500
      2M THP, PTE-mapped  10,000-10,500         126,000          1,500

That is 14-20 ns per PTE, about 2 ns of it the scan.  Builds that
differ only by NOPs in front of the function take either 10,100 or
7,500 ns for the 2M folio, with a period of 32 bytes: the loop of
modify_prot_commit_ptes() changes speed with its address.

What it buys, 256 MiB after fork() and the child's exit, medians of 15
runs, two boots of each kernel:

                                   16 PTEs         whole folio
  one byte per page, seq
      1M mTHP                     5.7 /  5.8 ms    4.1 /  4.0 ms
      2M THP, PTE-mapped          5.7 /  5.8 ms    3.9 /  3.9 ms
  one byte per page, random order
      2M THP, PTE-mapped          7.4 /  7.5 ms    4.9 /  5.1 ms
  memset()
      2M THP, PTE-mapped         40.2 / 39.4 ms   38.1 / 37.2 ms
  8 threads, random order
      2M THP, PTE-mapped          0.9 /  1.0 ms    0.7 /  0.7 ms
  one store per 64K, 2M folios    3.3 /  3.3 ms    1.5 /  1.6 ms
  one store per 2M, 2M folios     0.1 /  0.1 ms    1.4 /  1.4 ms

The last row is the pattern where the whole-folio fault is pure cost:
511 pages made writable that nobody writes, 1.3 ms more per 256 MiB,
paid once per fork().  Anything that stores to more than one page per
64K comes out ahead.

Link: https://lore.kernel.org/all/36933711-ae0f-468c-93bd-d6a67d974c9d@redhat.com/
Assisted-by: LLM sparse
Signed-off-by: Yuan-Hao Hsu <aa9736195201@gmail.com>
---
 mm/memory.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/mm/memory.c b/mm/memory.c
index 73e5691b3ed8..85c883d1e558 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4355,19 +4355,12 @@ static bool wp_can_reuse_anon_folio(struct folio *folio,
 	return true;
 }
 
-/*
- * The pages of the folio around the one that faulted are handled in aligned
- * blocks of this many PTEs: a 64K folio with 4K pages, and the size of a
- * contpte block on arm64.
- */
-#define WP_REUSE_NR_PTES	16
-
 /*
  * wp_can_reuse_anon_folio() found a large folio to be exclusive to this MM.
  * That holds for all of its pages and not only for the one that faulted: mark
- * the ones in the same block exclusive as well and map them writable, like
- * mprotect() would. Each of them would otherwise take a write fault of its own
- * that repeats the check on the very same folio.
+ * the ones that this page table maps exclusive as well and map them writable,
+ * like mprotect() would. Each of them would otherwise take a write fault of
+ * its own that repeats the check on the very same folio.
  *
  * The PTE that faulted is among them; wp_page_reuse() completes it.
  */
@@ -4378,17 +4371,17 @@ static void wp_reuse_large_anon_folio(struct vm_fault *vmf,
 	const unsigned long idx = folio_page_idx(folio, vmf->page);
 	struct vm_area_struct *vma = vmf->vma;
 	unsigned long addr = vmf->address;
-	unsigned long block = ALIGN_DOWN(addr, WP_REUSE_NR_PTES * PAGE_SIZE);
+	unsigned long pt_start = ALIGN_DOWN(addr, PMD_SIZE);
 	unsigned long nr_before, nr_after, end;
 	struct page *page;
 	unsigned int nr, i;
 	pte_t *ptep, pte;
 
-	/* Stay within the folio, the VMA and the block. */
-	nr_before = min3(idx, (addr - block) >> PAGE_SHIFT,
+	/* Stay within the folio, the VMA and the page table. */
+	nr_before = min3(idx, (addr - pt_start) >> PAGE_SHIFT,
 			 (addr - vma->vm_start) >> PAGE_SHIFT);
 	nr_after = min3(folio_nr_pages(folio) - idx,
-			(block + WP_REUSE_NR_PTES * PAGE_SIZE - addr) >> PAGE_SHIFT,
+			(pt_start + PMD_SIZE - addr) >> PAGE_SHIFT,
 			(vma->vm_end - addr) >> PAGE_SHIFT);
 	end = addr + (nr_after << PAGE_SHIFT);
 	addr -= nr_before << PAGE_SHIFT;
-- 
2.43.0


  parent reply	other threads:[~2026-09-19  7:31 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-18  6:42 [PATCH] " Yuan-Hao Hsu
2026-09-18 12:14 ` David Hildenbrand (Arm)
2026-09-18 18:28   ` Yuan-Hao Hsu
2026-09-18 23:48     ` Barry Song
2026-09-19  7:24       ` Yuan-Hao Hsu
2026-09-18 13:54 ` Lorenzo Stoakes (ARM)
2026-09-19  7:31 ` [PATCH v2 0/2] " Yuan-Hao Hsu
2026-09-19  7:31   ` [PATCH v2 1/2] mm/memory: reuse 16 PTEs of an " Yuan-Hao Hsu
2026-09-19  7:31   ` Yuan-Hao Hsu [this message]
2026-09-19 10:10     ` [PATCH v2 2/2] mm/memory: reuse the whole " David Hildenbrand (Arm)
2026-09-19 11:18       ` Yuan-Hao Hsu
2026-09-19 10:08   ` [PATCH v2 0/2] " David Hildenbrand (Arm)
2026-09-19 11:18     ` Yuan-Hao Hsu

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=20260919073134.639-3-aa9736195201@gmail.com \
    --to=aa9736195201@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=baohua@kernel.org \
    --cc=david@kernel.org \
    --cc=dev.jain@arm.com \
    --cc=liam@infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=ljs@kernel.org \
    --cc=mhocko@suse.com \
    --cc=rppt@kernel.org \
    --cc=ryan.roberts@arm.com \
    --cc=surenb@google.com \
    --cc=vbabka@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

all inboxes | Powered by JetHome®