Re: [REGRESSION] mm/mprotect: shared-dirty base-page toggle slower since v6.17
"Chengfeng Lin" <[email protected]> Wed, 1 Jul 2026 18:50:20 +0800 (GMT+08:00)
| Newsgroups | dev.linux.lists.regressions,org.kernel.vger.linux-kernel,org.kvack.linux-mm |
|---|---|
| Message-ID | <[email protected]> |
Hi, I wanted to add one small follow-up to make the scope clearer. The original reproducer repeatedly does: mprotect(PROT_READ) mprotect(PROT_READ | PROT_WRITE) write-touch I also checked whether the signal only comes from that repeated protect/restore loop. In the follow-up test, each timed iteration creates a fresh 64 MiB shared-dirty mapping, checks that it is still 4 KiB/no THP, and then times exactly one full-range: mprotect(PROT_READ) This is still the same narrow shared-dirty base-page workload, not a separate regression claim. I also checked a MADV_HUGEPAGE control on the current kernel. With the default shmem THP policy, the shared mapping did not actually form THP. After temporarily switching shmem THP to `advise`, the same shared mapping did form THP and the single mprotect(PROT_READ) cost was much lower. So the numbers below are intentionally for the 4 KiB base-page shape. The bare-metal result is: kernel single_protect_ns_per_page v6.16 8 8 8 mean 8.000 v6.17 14 14 14 mean 14.000 v7.1 18 15 18 mean 17.000 All steps reported `expected_match_ratio=100` and `unexpected_results=0`. So a single `mprotect(PROT_READ)` on the prepared shared-dirty range already shows the v6.16 -> v6.17 slowdown. The earlier toggle result is therefore not only measuring steady-state restore/write-touch effects. Follow-up evidence: https://github.com/lcf0399/linux-regression-evidence/tree/8a19614b08d8d2a4c2698c1cfac5a747f12aa021/mprotect-shared-dirty-toggle/bare-metal/20260630-single-protect-followup Updated evidence root: https://github.com/lcf0399/linux-regression-evidence/tree/8a19614b08d8d2a4c2698c1cfac5a747f12aa021/mprotect-shared-dirty-toggle If this scope looks useful, I can provide more runs or narrower measurements around the v6.16..v6.17 window. Thanks, Chengfeng > -----原始邮件----- > 发件人: "Chengfeng Lin" <[email protected]> > 发送时间:2026-06-25 01:28:04 (星期四) > 收件人: "Pedro Falcato" <[email protected]>, "Andrew Morton" <[email protected]>, [email protected] > 抄送: "Liam R. Howlett" <[email protected]>, "Lorenzo Stoakes" <[email protected]>, "Vlastimil Babka" <[email protected]>, "Jann Horn" <[email protected]>, [email protected], [email protected] > 主题: [REGRESSION] mm/mprotect: shared-dirty base-page toggle slower since v6.17 > > Hi, > > I have a refreshed bare-metal result for the shared-dirty mprotect() > slowdown I reported earlier from QEMU/lab testing. > > The reproducer is intentionally narrow: > > - MAP_SHARED | MAP_ANONYMOUS mapping > - 64 MiB range, write-prefaulted before timing > - state check: 4 KiB base pages, no THP backing > - repeated full-range mprotect(PROT_READ) > - restore with mprotect(PROT_READ | PROT_WRITE) > - write-touch after each protect/restore cycle > > So this is not a generic mprotect() regression claim. The scope is the > shared-dirty base-page PTE permission-change path. > > The bare-metal machine is an Intel Core i7-14700 system. The workload is > single-threaded and pinned to one logical CPU with `taskset -c 2`. The primary > metric is `iteration_ns_per_page`, lower is better. It is the wall-clock time > for one full protect/restore/write-touch iteration, divided by the number of > 4 KiB pages in the range. Each benchmark step used 9 external rounds, 1000 > iterations, and 10 warmup iterations. > > First, the v6.12 -> v6.19 result still reproduces on bare metal: > > kernel iteration_ns_per_page > v6.12.77 26 > v6.19.9 37 > > I then narrowed the release window with 3 interleaved boot/run steps per > kernel: > > kernel values mean > v6.16 25 25 25 25.000 > v6.17 37 37 37 37.000 > v6.18 38 38 38 38.000 > v6.18.19 38 38 38 38.000 > v6.19.9 37 36 37 36.667 > > I also checked later context with the same standalone command: > > kernel values mean > v7.0.9 36 36 36 36.000 > v6.19.9 + Pedro v3 patch-only 39 39 39 39.000 > v7.1.0-rc3 mm-unstable/Pedro 39 39 39 39.000 > > I do not treat the mm-unstable result as a clean release-kernel comparison. > It is only a follow-up check, and in this workload it did not improve the > standalone result. > > All of these runs reported `expected_match_ratio=100` and > `unexpected_results=0`. The state check in the standalone output stays in the > same shape: 4 KiB pages, no THP. > > This puts the slowdown in the v6.16 -> v6.17 release window. > > As an attribution check, I also built a v6.17 probe kernel that only changes > the present-PTE path in `mm/mprotect.c::change_pte_range()` for this workload > back to a single-PTE start/commit/flush shape. That is not an upstream patch > and not a clean release-kernel comparison; it is only a hot-path probe. > > The result was: > > kernel values mean > v6.16 25 25 25 25.000 > v6.17 37 37 37 37.000 > v6.17 single-PTE probe 25 25 25 25.000 > > So the targeted probe brings v6.17 back to the v6.16 range for this workload. > That points at the v6.17 PTE-batching shape in `change_pte_range()` as the > main cost for this shared-dirty 4 KiB base-page case. > > I do not want to overstate the attribution. I tried reversing the official > `cac1db8c3aad ("mm: optimize mprotect() by PTE batching")` patch onto my > linux-6.17 tree, but it did not apply cleanly. That means this is not an > exact revert result. I can only say that the slowdown appears in the > v6.16 -> v6.17 window, and that this focused probe brings the v6.17 result > back to the v6.16 range. > > Evidence bundle: > > https://github.com/lcf0399/linux-mm-regression-evidence/tree/acd7fef0e0276ac361971b0960e6611811edf5b3/mprotect-shared-dirty-toggle > > Standalone reproducer: > > https://github.com/lcf0399/linux-mm-regression-evidence/tree/acd7fef0e0276ac361971b0960e6611811edf5b3/mprotect-shared-dirty-toggle/reproducer > > For each installed kernel, the standalone reproducer was run as: > > taskset -c 2 env MAPPING_MB=64 ITERATIONS=1000 WARMUP=10 \ > EXTERNAL_ROUNDS=9 ./run_mprotect_shared_dirty_reproducer.sh > > For the release-window check, a small systemd/GRUB queue booted each target > kernel before running the same command. > > Bare-metal summaries and raw run logs: > > https://github.com/lcf0399/linux-mm-regression-evidence/tree/acd7fef0e0276ac361971b0960e6611811edf5b3/mprotect-shared-dirty-toggle/bare-metal > > Release-window narrowing: > > https://github.com/lcf0399/linux-mm-regression-evidence/tree/acd7fef0e0276ac361971b0960e6611811edf5b3/mprotect-shared-dirty-toggle/bare-metal/20260623-narrow-6.16-6.19-3rounds > > v6.17 single-PTE probe: > > https://github.com/lcf0399/linux-mm-regression-evidence/tree/acd7fef0e0276ac361971b0960e6611811edf5b3/mprotect-shared-dirty-toggle/bare-metal/20260624-6.17-singlepte-probe > > Probe patch used for that attribution run: > > https://github.com/lcf0399/linux-mm-regression-evidence/blob/acd7fef0e0276ac361971b0960e6611811edf5b3/mprotect-shared-dirty-toggle/bare-metal/20260624-6.17-singlepte-probe/0001-mm-mprotect-probe-6.17-single-pte-hotpath.patch > > #regzbot introduced: v6.16..v6.17 > > Does this scope look useful to investigate further? If yes, I can try a more > exact commit-level check or test a patch you think is the right direction. > > Thanks, > Chengfeng >