# Re: \[PATCH v5 5/6\] mm/mglru: add tracepoint for scan\_folios()

- From: Barry Song \<baohua@kernel.org\>
- Date: 2026-10-31 21:02:51 
- List: linux-trace-kernel
- Page: https://ratatoskr.run/linux-trace-kernel/2026/10/17838482
- Thread: https://ratatoskr.run/linux-trace-kernel/2026/10/17837167/t.md

```text
On Sat, Oct 31, 2026 at 5:01 PM Ridong Chen [ref] wrote:
>
> From: Ridong Chen <redacted>
>
> MGLRU's scan_folios() emits the classic-LRU tracepoint
> trace_mm_vmscan_lru_isolate(), which predates MGLRU. It reports the
> scan/isolate counts and the LRU type, but carries no generation or
> memcg context, so a trace of an MGLRU run cannot tell which memcg a
> given scan belongs to, nor how far reclaim has progressed through the
> generations.
>
> Add mm_mglru_scan_folios next to it, reporting the same counters plus
> nr_sorted (folios moved to a younger generation by sort_folio()) and
> the context the classic tracepoint lacks: the node id and memcg id of
> the lruvec, and the max_seq, tier and min_seq of the type being
> scanned.
>
> Now that struct scan_control is visible to the trace header, pass sc,
> lruvec, type and tier straight in and derive everything else in
> TP_fast_assign(), so nothing is computed at the call site when the
> event is disabled. The int fields are grouped at the end of the entry
> to avoid padding on 64-bit.
>
> scan_folios() is the MGLRU-specific layer where folios are actually
> scanned, so it has no classic-LRU counterpart. The existing tracepoint
> is left unchanged.
>
> Signed-off-by: Ridong Chen <redacted>
> ---

Ran a test on this:

/sys/kernel/tracing/events/vmscan/mm_mglru_scan_folios # cat format
name: mm_mglru_scan_folios
ID: 491
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;

field:u64 memcg_id; offset:8; size:8; signed:0;
field:unsigned long nr_requested; offset:16; size:8; signed:0;
field:unsigned long nr_scanned; offset:24; size:8; signed:0;
field:unsigned long nr_sorted; offset:32; size:8; signed:0;
field:unsigned long nr_skipped; offset:40; size:8; signed:0;
field:unsigned long nr_taken; offset:48; size:8; signed:0;
field:unsigned long max_seq; offset:56; size:8; signed:0;
field:unsigned long min_seq; offset:64; size:8; signed:0;
field:int nid; offset:72; size:4; signed:1;
field:int highest_zoneidx; offset:76; size:4; signed:1;
field:int order; offset:80; size:4; signed:1;
field:int lru; offset:84; size:4; signed:1;
field:int tier; offset:88; size:4; signed:1;

print fmt: "nid=%d memcg_id=%llu classzone=%d order=%d
nr_requested=%lu nr_scanned=%lu nr_sorted=%lu nr_skipped=%lu
nr_taken=%lu lru=%s max_seq=%lu tier=%d min_seq=%lu", REC->nid,
REC->memcg_id, REC->highest_zoneidx, REC->order, REC->nr_requested,
REC->nr_scanned, REC->nr_sorted, REC->nr_skipped, REC->nr_taken,
__print_symbolic(REC->lru, {0, "inactive_anon"}, {1, "active_anon"},
{2, "inactive_file"}, {3, "active_file"}, {4, "unevictable"}),
REC->max_seq, REC->tier, REC->min_seq



~ # echo 1 > /sys/kernel/tracing/events/vmscan/mm_mglru_scan_folios/enable
~ # ./a.out
[+] mapped 500 MB at 0xffff9f000000 (128000 pages)
[+] duration: 60 seconds
[+] first pass done, start looping writes
^C
~ # cat /sys/kernel/tracing/trace | grep mglru_scan_folios | head
         kswapd0-50      [000] d..1.   650.877105:
mm_mglru_scan_folios: nid=0 memcg_id=1 classzone=2 order=0
nr_requested=64 nr_scanned=0 nr_sorted=0 nr_skipped=0 nr_taken=0
lru=inactive_anon max_seq=3 tier=3 min_seq=1
         kswapd0-50      [000] d..1.   650.877686:
mm_mglru_scan_folios: nid=0 memcg_id=1 classzone=2 order=0
nr_requested=64 nr_scanned=64 nr_sorted=0 nr_skipped=0 nr_taken=64
lru=inactive_file max_seq=3 tier=3 min_seq=0
         kswapd0-50      [000] d..1.   650.907558:
mm_mglru_scan_folios: nid=0 memcg_id=1 classzone=2 order=0
nr_requested=64 nr_scanned=0 nr_sorted=0 nr_skipped=0 nr_taken=0
lru=inactive_anon max_seq=3 tier=3 min_seq=1
         kswapd0-50      [000] d..1.   650.907729:
mm_mglru_scan_folios: nid=0 memcg_id=1 classzone=2 order=0
nr_requested=64 nr_scanned=64 nr_sorted=0 nr_skipped=0 nr_taken=64
lru=inactive_file max_seq=3 tier=3 min_seq=0
         kswapd0-50      [000] d..1.   650.909040:
mm_mglru_scan_folios: nid=0 memcg_id=1 classzone=2 order=0
nr_requested=64 nr_scanned=0 nr_sorted=0 nr_skipped=0 nr_taken=0
lru=inactive_anon max_seq=3 tier=3 min_seq=1
         kswapd0-50      [000] d..1.   650.909198:
mm_mglru_scan_folios: nid=0 memcg_id=1 classzone=2 order=0
nr_requested=64 nr_scanned=64 nr_sorted=0 nr_skipped=0 nr_taken=64
lru=inactive_file max_seq=3 tier=3 min_seq=0
         kswapd0-50      [000] d..1.   650.910520:
mm_mglru_scan_folios: nid=0 memcg_id=1 classzone=2 order=0
nr_requested=64 nr_scanned=0 nr_sorted=0 nr_skipped=0 nr_taken=0
lru=inactive_anon max_seq=3 tier=3 min_seq=1
         kswapd0-50      [000] d..1.   650.910710:
mm_mglru_scan_folios: nid=0 memcg_id=1 classzone=2 order=0
nr_requested=64 nr_scanned=64 nr_sorted=4 nr_skipped=0 nr_taken=60
lru=inactive_file max_seq=3 tier=3 min_seq=0
         kswapd0-50      [000] d..1.   650.911866:
mm_mglru_scan_folios: nid=0 memcg_id=1 classzone=2 order=0
nr_requested=64 nr_scanned=0 nr_sorted=0 nr_skipped=0 nr_taken=0
lru=inactive_anon max_seq=3 tier=3 min_seq=1
         kswapd0-50      [000] d..1.   650.911988:
mm_mglru_scan_folios: nid=0 memcg_id=1 classzone=2 order=0
nr_requested=64 nr_scanned=66 nr_sorted=0 nr_skipped=0 nr_taken=66
lru=inactive_file max_seq=3 tier=3 min_seq=0

The LRU naming feels a bit weird to me. We have
"inactive_file" and "inactive_anon", but MGLRU doesn't
have active/inactive lists. I guess it's not a big issue,
though, since we also use the same names in
trace_mm_vmscan_lru_isolate() in scan_folios().

For the patch:

Tested-by: Barry Song <baohua@kernel.org>
Reviewed-by: Barry Song <baohua@kernel.org>
```
