Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] skip empty PUD subtrees during aging with a PUD-level Bloom filter
@ 2026-09-01  6:37 Baoquan He
  2026-09-01  6:37 ` [PATCH v2 1/4] mm/mglru: add MM_WALK_EMPTY stats and tracepoint Baoquan He
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Baoquan He @ 2026-09-01  6:37 UTC (permalink / raw)
  To: linux-mm
  Cc: akpm, baohua, kasong, shakeel.butt, axelrasmussen, yuanchu,
	weixugc, david, rostedt, mhiramat, hannes, Baoquan He

Problem
=======
 
MGLRU's aging walks every present PUD of every mm in the mm_list. When
an mm has no pages on a given NUMA node, all 512 PMDs in each PUD fail
the existing PMD-level Bloom filter test, yet the walker still walks
into every PUD and iterates every PMD. This is pure waste.
 
These cross-node empty walks are structural: lru_gen_use_mm() sets
mm->lru_gen.bitmap to -1 (all nodes) at each context switch, so the
aging walker on every node including kswap, direct reclaim or proactive
aging independently walks the same mm. On the test of 2-node KVM
guest, node 1's walks of the node-0-pinned workload scan ~1235 PTE
entries per walk while finding no folio for node 1's lruvec.

Approach
========
  
Add a PUD-level Bloom filter, one level above the existing PMD filter.
The walker now:
  
  1. Tests the PUD filter before descending into a PUD subtree.
  2. If the PUD had no young entries last generation, skips the entire
     1GB region -- avoiding 512 PMD lookups. 
  3. walk_pmd_range() reports whether it found any young leaf entries;
     walk_pud_range() records that in the double-buffered PUD filter.
  4. The rmap feedback path (lru_gen_look_around()) marks hot PUDs, so
     newly hot or migrated-in regions are re-examined promptly.
  5. force_scan walks bypass the PUD test, so manual aging and newly
     added mm's always re-populate the filter.
 
The double-buffered filter flips each aging generation and the eviction
feedback keeps hot regions marked, so correctness holds without tracking
per-page residency or touching the page fault / rmap hot paths.

Test
====
 
Empty-walk suppression (8GB / 2-NUMA KVM guest, 32 x 64MB workers pinned
to node 0 via numactl --membind=0, 100 aging passes, 3 runs):
 
  node 1 (foreign mm walks):
    baseline (no PUD filter):   ~1235-1254 PTE entries scanned per walk
    with PUD filter:              0.04 / 1.3 / 2.0 per walk
                                (>99.8% reduction; what remains is a few
                                 other processes' pages on node 1,the
                                 cross-node workload mms are fully suppressed)
    pud_skipped:                 ~3.1 1GB subtrees per walk
    worker RSS delta:             0% (no premature reclaim)
 
Build-time regression (make -j4 in a 3G memory cgroup, 4 vCPU / 8GB
2-NUMA KVM guest, 3 runs each; the host was kept idle during the runs):
 
              baseline   patched
  build time  11m48      11m26     (within run-to-run variance; one
                                    patched run of 10m37 was an outlier)
  pgpgin      138k       139k      (unchanged)
  pgmajfault  1950       1950      (unchanged)

The PUD-level filter reduces the leaf scanning of empty aging walks on
the foreign node by >99.8% with no premature reclaim. The build test
shows no measurable regression.

Change log:
==========

v1->v2:
 
- Drop the empty_map (mm-level skip) mechanism. Per Barry Song's
  review, the PUD-level filter alone achieves the goal; empty_map added
  complexity (an mm_struct field, a skip_empty knob, re-scan bookkeeping)
  without being necessary. It can be revisited if very large memory
  systems make the residual walk count meaningful again.
- Rename the counters: MM_LEAF_ELIGIBLE -> MM_LEAF_ASSOCIATED,
  MM_LEAF_TOTAL_EMPTY -> MM_LEAF_EMPTY_WALKS; MM_WALK_EMPTY kept with its
  comment clarified.
- Patch 1 adds the per-walk counters and the mm_vmscan_lru_gen_walk()
  tracepoint used for the measurements below; the series is now 4 patches.

RFC-v1:

- Bloom filter helpers are named symmetrically -
  test/update/reset_pmd_bloom_filter() alongside the PUD-level ones, and
  the struct field filters -> pmd_filters (Barry).
- An mm is marked empty only when its page tables were actually walked
  (a failed mmap_read_trylock() or a stale seq is not empty), and the skip
  is invalidated on the major page-fault and migration paths. (Sashiko)
- Reworked the re-scan: the old shared counter across nodes got stuck at
  the slowest node, so the skip never really engaged. Now each node re-scans
  its empty mms every N passes on its own clock. N is the skip_empty knob
  (default 4, proper read/write with input validation). (Sashiko)
- Added measurement counters/tracepoint, and a kernel-build regression
  test (no measurable impact).

Baoquan He (4):
  mm/mglru: add MM_WALK_EMPTY stats and tracepoint
  mm/mglru: add PUD-level Bloom filter state and generic helpers
  mm/mglru: skip cold PUD subtrees during aging
  mm/mglru: count PUD subtrees skipped by the PUD-level filter

 include/linux/mmzone.h        |  11 ++-
 include/trace/events/vmscan.h |  30 ++++++++
 mm/vmscan.c                   | 132 +++++++++++++++++++++++++++-------
 3 files changed, 147 insertions(+), 26 deletions(-)


base-commit: 42d64d4fef83a241c919c8693fdf0a21b2cb6061
-- 
2.54.0



^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-09-04  4:38 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01  6:37 [PATCH v2 0/4] skip empty PUD subtrees during aging with a PUD-level Bloom filter Baoquan He
2026-09-01  6:37 ` [PATCH v2 1/4] mm/mglru: add MM_WALK_EMPTY stats and tracepoint Baoquan He
2026-09-01  7:11   ` Barry Song
2026-09-01  8:18     ` Baoquan He
2026-09-01 23:37       ` Barry Song
2026-09-01  6:37 ` [PATCH v2 2/4] mm/mglru: add PUD-level Bloom filter state and generic helpers Baoquan He
2026-09-01  6:37 ` [PATCH v2 3/4] mm/mglru: skip cold PUD subtrees during aging Baoquan He
2026-09-01 23:53   ` Barry Song
2026-09-02  2:29     ` Baoquan He
2026-09-02  3:22     ` Baoquan He
2026-09-04  3:41       ` Barry Song
2026-09-04  4:38         ` Baoquan He
2026-09-01  6:37 ` [PATCH v2 4/4] mm/mglru: count PUD subtrees skipped by the PUD-level filter Baoquan He

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox