Thread (13 messages) 13 messages, 4 authors, 20h ago

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>
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help