[PATCH 7/9] mm/mglru: skip PUD subtrees during aging
Baoquan He <[email protected]>
| Newsgroups | org.kvack.linux-mm |
|---|---|
| Message-ID | <[email protected]> |
The aging walk into present PUD and iterates all its 512 PMDs, testing the PMD-level Bloom filter on each. Add a coarser PUD-level filter (pud_filters) one level up: - walk_pmd_range() now reports whether it found any young leaf entries, - and walk_pud_range() records that in the PUD filter and, - on subsequent generations, skips the whole 1GB subtree when the filter says it had none last generation. The double-buffered filter flips with each new iteration, and the existing eviction feedback (lru_gen_look_around()) keeps hot regions marked, so newly hot or migrated-in pages are re-checked promptly rather than suppressed indefinitely. force_scan walks bypass the PUD test, so manual aging and newly added mm's always rescan and re-populate the filter. Signed-off-by: Baoquan He <[email protected]> --- mm/vmscan.c | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 062504f287da..7a6c15be1c2a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2817,6 +2817,8 @@ static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) * walk_pmd_range(); the eviction also report them when walking the rmap * in lru_gen_look_around(). * + * A second, coarser pair of filters (pud_filters) sits one level up. + * * For future optimizations: * 1. It's not necessary to keep both filters all the time. The spare one can be * freed after the RCU grace period and reallocated if needed again. @@ -2908,6 +2910,23 @@ static void reset_pmd_bloom_filter(struct lru_gen_mm_state *mm_state, unsigned l __reset_bloom_filter(mm_state->pmd_filters, seq); } +static bool test_pud_bloom_filter(struct lru_gen_mm_state *mm_state, unsigned long seq, + void *item) +{ + return __test_bloom_filter(mm_state->pud_filters, seq, item); +} + +static void update_pud_bloom_filter(struct lru_gen_mm_state *mm_state, unsigned long seq, + void *item) +{ + __update_bloom_filter(mm_state->pud_filters, seq, item); +} + +static void reset_pud_bloom_filter(struct lru_gen_mm_state *mm_state, unsigned long seq) +{ + __reset_bloom_filter(mm_state->pud_filters, seq); +} + /****************************************************************************** * mm_struct list ******************************************************************************/ @@ -3158,8 +3177,10 @@ static bool iterate_mm_list(struct lru_gen_mm_walk *walk, struct mm_struct **ite spin_unlock(&mm_list->lock); - if (mm && first) + if (mm && first) { reset_pmd_bloom_filter(mm_state, walk->seq + 1); + reset_pud_bloom_filter(mm_state, walk->seq + 1); + } if (*iter) mmdrop(*iter); @@ -3744,10 +3765,11 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long addr, struct vm_area *first = -1; } -static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, +static bool walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, struct mm_walk *args) { int i; + bool young = false; pmd_t *pmd; unsigned long next; unsigned long addr; @@ -3784,8 +3806,10 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, walk->mm_stats[MM_LEAF_TOTAL]++; - if (pfn != -1) + if (pfn != -1) { walk_pmd_range_locked(pud, addr, vma, args, bitmap, &first); + young = true; + } continue; } @@ -3795,6 +3819,7 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, continue; walk_pmd_range_locked(pud, addr, vma, args, bitmap, &first); + young = true; } if (!walk->force_scan && !test_pmd_bloom_filter(mm_state, walk->seq, pmd + i)) @@ -3806,6 +3831,7 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, continue; walk->mm_stats[MM_NONLEAF_ADDED]++; + young = true; /* carry over to the next generation */ update_pmd_bloom_filter(mm_state, walk->seq + 1, pmd + i); @@ -3815,6 +3841,8 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, if (i < PTRS_PER_PMD && get_next_vma(PUD_MASK, PMD_SIZE, args, &start, &end)) goto restart; + + return young; } static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end, @@ -3825,6 +3853,7 @@ static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end, unsigned long addr; unsigned long next; struct lru_gen_mm_walk *walk = args->private; + struct lru_gen_mm_state *mm_state = get_mm_state(walk->lruvec); VM_WARN_ON_ONCE(p4d_leaf(*p4d)); @@ -3838,7 +3867,12 @@ static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end, if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val))) continue; - walk_pmd_range(&val, addr, next, args); + /* Skip a subtree whose 512 PMDs all failed the PMD-level filter last gen */ + if (!walk->force_scan && !test_pud_bloom_filter(mm_state, walk->seq, pud + i)) + continue; + + if (walk_pmd_range(&val, addr, next, args)) + update_pud_bloom_filter(mm_state, walk->seq + 1, pud + i); if (need_resched() || walk->batched >= MAX_LRU_BATCH) { end = (addr | ~PUD_MASK) + 1; @@ -6027,6 +6061,8 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg) for (i = 0; i < NR_BLOOM_FILTERS; i++) { bitmap_free(mm_state->pmd_filters[i]); mm_state->pmd_filters[i] = NULL; + bitmap_free(mm_state->pud_filters[i]); + mm_state->pud_filters[i] = NULL; } } } -- 2.54.0