Re: [PATCH v5 5/6] mm/mglru: add tracepoint for scan_folios()
flat view
From: Barry Song <baohua@kernel.org>
Date: 2026-10-31 21:02:51
Also in:
bpf, cgroups, linux-mm, lkml
On Sat, Oct 31, 2026 at 5:01 PM Ridong Chen [off-list 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>