From: "Kiryl Shutsemau (Meta)" <[email protected]>

The anonymous scan reports nothing, and its verdict decides everything
after it: which orders selection may still try, and whether the table is
refused outright.  The only way to see it was to infer it from what the
candidates did afterwards, or from their absence.

Add mm_collapse_scan: where the table was scanned, how many slots were
holes or the zeropage, how many were swapped out, which orders survived
the scan, and the verdict.

The first two counts are why a table yields a smaller window than
expected.  The third is what a PMD candidate will have to read back.  The
order mask is the scan's whole output to selection in one number: a table
refused as a unit shows an empty mask, which distinguishes it at a glance
from one that merely lost the PMD order.

The file scan already reported through mm_khugepaged_scan_file; this gives
the anonymous side the same.

Assisted-by: Claude-Code:claude-opus-5
Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]>
---
 include/trace/events/huge_memory.h | 34 ++++++++++++++++++++++++++++++
 mm/collapse.c                      |  2 ++
 2 files changed, 36 insertions(+)

diff --git a/include/trace/events/huge_memory.h 
b/include/trace/events/huge_memory.h
index 86131845b761..573cf5428969 100644
--- a/include/trace/events/huge_memory.h
+++ b/include/trace/events/huge_memory.h
@@ -126,6 +126,40 @@ TRACE_EVENT(mm_collapse_huge_page,
                __entry->order)
 );
 
+TRACE_EVENT(mm_collapse_scan,
+
+       TP_PROTO(struct mm_struct *mm, unsigned long addr, int none_or_zero,
+                int unmapped, unsigned long orders, int result),
+
+       TP_ARGS(mm, addr, none_or_zero, unmapped, orders, result),
+
+       TP_STRUCT__entry(
+               __field(struct mm_struct *, mm)
+               __field(unsigned long, addr)
+               __field(int, none_or_zero)
+               __field(int, unmapped)
+               __field(unsigned long, orders)
+               __field(int, result)
+       ),
+
+       TP_fast_assign(
+               __entry->mm = mm;
+               __entry->addr = addr;
+               __entry->none_or_zero = none_or_zero;
+               __entry->unmapped = unmapped;
+               __entry->orders = orders;
+               __entry->result = result;
+       ),
+
+       TP_printk("mm=%p, addr=0x%lx, none_or_zero=%d, unmapped=%d, 
orders=0x%lx, result=%s",
+               __entry->mm,
+               __entry->addr,
+               __entry->none_or_zero,
+               __entry->unmapped,
+               __entry->orders,
+               __print_symbolic(__entry->result, SCAN_STATUS))
+);
+
 TRACE_EVENT(mm_collapse_candidate,
 
        TP_PROTO(struct mm_struct *mm, unsigned long addr, unsigned int order,
diff --git a/mm/collapse.c b/mm/collapse.c
index f0d80204c2bd..b750a1fc81a5 100644
--- a/mm/collapse.c
+++ b/mm/collapse.c
@@ -2097,6 +2097,8 @@ static enum scan_result collapse_scan_table(struct 
vm_area_struct *vma,
                cc->select_orders &= ~BIT(HPAGE_PMD_ORDER);
 
        cc->scan_unmapped = unmapped;
+       trace_mm_collapse_scan(vma->vm_mm, start, none_or_zero, unmapped,
+                              cc->select_orders, result);
        return result;
 }
 
-- 
2.54.0


Reply via email to