On 11/3/2026 6:00 PM, Barry Song wrote:
On Tue, Nov 3, 2026 at 4:39 PM Ridong Chen <[email protected]> wrote:



On 11/3/2026 2:48 PM, Barry Song wrote:
On Tue, Nov 3, 2026 at 10:58 AM Ridong Chen <[email protected]> wrote:

From: Ridong Chen <[email protected]>

Aging in MGLRU advances max_seq via inc_max_seq(), creating a new
youngest generation. There is currently no tracepoint on this path, so
the moment a new generation is created, and how the min_seq of each type
trails behind it, cannot be observed as it happens.

We might be more interested in why aging is triggered rather
than the exact moment when max_seq is advanced.

With your patch, we get:

~ # cat /sys/kernel/tracing/trace | grep mglru_inc_max_seq
             a.out-93      [001] d..1.   278.276539:
mm_mglru_inc_max_seq: nid=0 memcg_id=1 max_seq=4 anon_min_seq=2
file_min_seq=1 nr_anon={0x0,0xf016,0x12,0x0}
nr_file={0x1886,0xb,0x4c,0x0}
           kswapd0-50      [000] d..1.   278.422400:
mm_mglru_inc_max_seq: nid=0 memcg_id=1 max_seq=5 anon_min_seq=2
file_min_seq=2 nr_anon={0x5,0xccb6,0x3439,0x0}
nr_file={0x4ae,0x4f,0x55,0x0}
           kswapd0-50      [000] d..1.   278.508003:
mm_mglru_inc_max_seq: nid=0 memcg_id=1 max_seq=6 anon_min_seq=3
file_min_seq=4 nr_anon={0xccb6,0x3d29,0x1,0x0}
nr_file={0x0,0x59,0x7,0x0}
           kswapd0-50      [000] d..1.   280.046056:
mm_mglru_inc_max_seq: nid=0 memcg_id=1 max_seq=7 anon_min_seq=4
file_min_seq=5 nr_anon={0x3bf3,0xcbbd,0x23e,0x0}
nr_file={0x0,0xb,0x1,0x0}
           kswapd0-50      [000] d..1.   280.124876:
mm_mglru_inc_max_seq: nid=0 memcg_id=1 max_seq=8 anon_min_seq=5
file_min_seq=6 nr_anon={0xcafd,0x3e31,0x0,0x0}
nr_file={0x0,0x5,0x7,0x0}
             a.out-96      [001] d..1.   290.629014:
mm_mglru_inc_max_seq: nid=0 memcg_id=1 max_seq=9 anon_min_seq=7
file_min_seq=6 nr_anon={0x0,0x10615,0xb,0x0}
nr_file={0x331,0xb,0x9a,0x0}
           kswapd0-50      [000] d..1.   290.653098:
mm_mglru_inc_max_seq: nid=0 memcg_id=1 max_seq=10 anon_min_seq=7
file_min_seq=7 nr_anon={0x15,0xef23,0x18c4,0x0}
nr_file={0xb,0xb8,0x55,0x0}
             a.out-96      [001] d..1.   290.684875:
mm_mglru_inc_max_seq: nid=0 memcg_id=1 max_seq=11 anon_min_seq=8
file_min_seq=9 nr_anon={0xeee3,0x1afb,0x2,0x0}
nr_file={0x0,0x76,0x4,0x0}

You can see that the youngest generation is always zero,
because you're just getting the newly added youngest
generation :-)


Hi Barry,

Thank you very much for testing and reviewing.

This somehow suggests that the information is redundant, as
there is always a zero there.

I suspect we'll need an additional tracepoint to show why
aging is triggered and at what sc->priority it happens.

But do you know why you trace the moment just after aging
is completed, rather than the reason why aging is needed?

My original goal was to pair it with mm_mglru_scan_folios, to see how
the aging window of each memcg moves. The per-generation anon/file
nr_pages were added following your suggestion on v1. I put it at the
end of inc_max_seq() because of the restart there, as max_seq and
min_seq are only final after that.

The per-generation anon/file nr_pages are perfectly good, as
they can also help explain why aging is needed, especially
now that we're introducing new code for imbalance-based
aging.


You make a very good point that the reason for aging is also
important. So I'd like to discuss which way is better:

1) Keep mm_mglru_inc_max_seq, and add another tracepoint at the aging
   decision in try_to_shrink_lruvec(), reporting why aging is needed
   and at what sc->priority.

2) Replace mm_mglru_inc_max_seq with a single tracepoint in
   try_to_shrink_lruvec(), right before try_to_inc_max_seq(), reporting
   the reason, sc->priority, swappiness, max_seq/min_seq and the
   per-generation nr_pages before aging. The youngest generation is
   not empty at that point, and the new window after aging can still
   be seen from the following mm_mglru_scan_folios.

Which one do you prefer?

Maybe we should keep option 2 for now. Understanding why
we are aging and at what priority is much more important,
especially since we're still introducing some
imbalance-based aging code.

It should be quite simple, just a matter of moving the code
around a little.

If we later find a good reason to have option 1, we can
always add it, right?


Hi Barry,

Agreed, I'll go with option 2. Two things I'd like to confirm first:

1) To report the reason, should_run_aging() would need to return it
 instead of a bool, e.g. an enum like:

  enum lru_gen_aging_reason {
        AGING_NONE,
        AGING_NO_EVICTABLE,     /* eviction is not possible anymore */
        AGING_MIN_GENS,         /* better to age, eviction still possible */
  };
        
Or just report sc->priority, swappiness, max_seq/min_seq and the
per-generation nr_pages, and let users derive the reason from them?
The former is more direct, the latter keeps should_run_aging()
unchanged.

2) try_to_shrink_lruvec() has changed quite a lot recently, e.g.
Kairui's reclaim loop rework, and your swappiness series also touches it, including the aging part. Is it stable enough now to carry a tracepoint there?

--
Best regards
Ridong


Reply via email to