Re: [RFC PATCH v2 4/5] mm: mglru: run aging when pages are severely imbalanced across gens

From: Kairui Song

Date: Thu Jul 30 2026 - 08:23:29 EST


On Sun, Jul 26, 2026 at 8:21 PM Barry Song (Xiaomi) <baohua@xxxxxxxxxx> wrote:
>
> From: lyugaofei <lyugaofei@xxxxxxxxxx>
>
> This partially restores the reclaim behavior introduced in Yu
> Zhao's initial MGLRU commit, ac35a4902370 ("mm: multi-gen LRU:
> minimal implementation"):
> /*
> * It's also ideal to spread pages out evenly, i.e., 1/(MIN_NR_GENS+1)
> * of the total number of pages for each generation. A reasonable range
> * for this average portion is [1/MIN_NR_GENS, 1/(MIN_NR_GENS+2)]. The
> * aging cares about the upper bound of hot pages, while the eviction
> * cares about the lower bound of cold pages.
> */
> if (young * MIN_NR_GENS > total)
> return true;
> if (old * (MIN_NR_GENS + 2) < total)
> return true;
>
> But with a stricter condition: the younger generations must contain
> at least four times as many folios as the older generations. This
> allows aging to keep folios of the preferred type spread across the
> reclaimable generations.
>
> Signed-off-by: lyugaofei <lyugaofei@xxxxxxxxxx>
> Co-developed-by: Barry Song (Xiaomi) <baohua@xxxxxxxxxx>
> Signed-off-by: Barry Song (Xiaomi) <baohua@xxxxxxxxxx>
> ---
> mm/vmscan.c | 37 ++++++++++++++++++++++++++++++++++++-
> 1 file changed, 36 insertions(+), 1 deletion(-)
>
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index d6bd64b4dced..7c13dedb0b1f 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -4956,9 +4956,40 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
> return scanned;
> }
>
> +static bool lru_gen_imbalanced(struct lruvec *lruvec, int type,
> + unsigned long max_seq, unsigned long min_seq,
> + int swappiness)
> +{
> + struct lru_gen_folio *lrugen = &lruvec->lrugen;
> + unsigned long young = 0, old = 0, seq;
> +
> + /*
> + * reclaim is forced to a single type in those cases, so there is
> + * no need to consider the swappiness bias
> + */
> + if (swappiness == MIN_SWAPPINESS || swappiness > MAX_SWAPPINESS)
> + return false;
> +
> + for (seq = min_seq; seq <= max_seq; seq++) {
> + int gen = lru_gen_from_seq(seq);
> + unsigned long size = 0;
> + int zone;
> +
> + for (zone = 0; zone < MAX_NR_ZONES; zone++)
> + size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L);
> +
> + if (seq + MIN_NR_GENS > max_seq)
> + young += size;
> + else
> + old += size;
> + }
> + return young > old * 4;

Hi Barry,

MAX_NR_GEN could be tunable, would it be better to use a macro like
MAX_NR_GEN or MIN_NR_GEN here?

And I know there are experiments to extend MGLRU to run aging
periodically so each gen has a fixed age:

https://lwn.net/Articles/976985/

Not sure if this will conflict if this is a hardcoded aging behavior,
and if we want things like that in the future, these are useful on
servers, I think android might benefit foo.