[PATCH 4/5] mm/khugepaged: add accounting for successful hint or non-hint collapse
From: Luka Bai
Date: Sun May 31 2026 - 00:25:17 EST
From: Luka Bai <lukabai@xxxxxxxxxxx>
Add two mthp attributes for the accounting of the number of successful
khugepaged collapse, either by hint or not by hint so that we can know
them easily from userspace. Note that these two statistics only care
about the collapse initiated by khugepaged, and they will not consider
the collapse raised by MADV_COLLAPSE.
Signed-off-by: Luka Bai <lukabai@xxxxxxxxxxx>
---
include/linux/huge_mm.h | 2 ++
mm/huge_memory.c | 4 ++++
mm/khugepaged.c | 18 +++++++++++++++++-
3 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index edece3e26985..9df0d7f71e95 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -147,6 +147,8 @@ enum mthp_stat_item {
MTHP_STAT_COLLAPSE_EXCEED_SWAP,
MTHP_STAT_COLLAPSE_EXCEED_NONE,
MTHP_STAT_COLLAPSE_EXCEED_SHARED,
+ MTHP_STAT_KHUGEPAGED_COLLAPSE_HINT,
+ MTHP_STAT_KHUGEPAGED_COLLAPSE_NON_HINT,
__MTHP_STAT_COUNT
};
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index bf9b480bb3b0..0031fb4b0b09 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -720,6 +720,8 @@ DEFINE_MTHP_STAT_ATTR(nr_anon_partially_mapped, MTHP_STAT_NR_ANON_PARTIALLY_MAPP
DEFINE_MTHP_STAT_ATTR(collapse_exceed_swap_pte, MTHP_STAT_COLLAPSE_EXCEED_SWAP);
DEFINE_MTHP_STAT_ATTR(collapse_exceed_none_pte, MTHP_STAT_COLLAPSE_EXCEED_NONE);
DEFINE_MTHP_STAT_ATTR(collapse_exceed_shared_pte, MTHP_STAT_COLLAPSE_EXCEED_SHARED);
+DEFINE_MTHP_STAT_ATTR(khugepaged_collapse_hint, MTHP_STAT_KHUGEPAGED_COLLAPSE_HINT);
+DEFINE_MTHP_STAT_ATTR(khugepaged_collapse_non_hint, MTHP_STAT_KHUGEPAGED_COLLAPSE_NON_HINT);
static struct attribute *anon_stats_attrs[] = {
@@ -775,6 +777,8 @@ static struct attribute *any_stats_attrs[] = {
&split_failed_attr.attr,
&collapse_alloc_attr.attr,
&collapse_alloc_failed_attr.attr,
+ &khugepaged_collapse_hint_attr.attr,
+ &khugepaged_collapse_non_hint_attr.attr,
NULL,
};
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 3f5eb8be06d1..2f21c0b6ab46 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -147,6 +147,15 @@ struct mthp_range {
struct collapse_control {
bool is_khugepaged;
+ /*
+ * True while khugepaged is draining a collapse hint queued via
+ * khugepaged_add_collapse_hint(). Used by collapse_single_pmd() to
+ * attribute a successful collapse to MTHP_STAT_KHUGEPAGED_COLLAPSE_HINT
+ * or MTHP_STAT_KHUGEPAGED_COLLAPSE_NON_HINT. Only meaningful when the
+ * collapse is initiated by khugepaged (is_khugepaged == true).
+ */
+ bool from_priority_hint;
+
/* Num pages scanned per node */
u32 node_load[MAX_NUMNODES];
@@ -3012,8 +3021,13 @@ static enum scan_result collapse_single_pmd(unsigned long addr,
mmap_read_unlock(mm);
}
end:
- if (cc->is_khugepaged && result == SCAN_SUCCEED)
+ if (cc->is_khugepaged && result == SCAN_SUCCEED) {
++khugepaged_pages_collapsed;
+ count_mthp_stat(HPAGE_PMD_ORDER,
+ cc->from_priority_hint ?
+ MTHP_STAT_KHUGEPAGED_COLLAPSE_HINT :
+ MTHP_STAT_KHUGEPAGED_COLLAPSE_NON_HINT);
+ }
return result;
}
@@ -3227,7 +3241,9 @@ static int collapse_scan_one_priority_entry(unsigned int progress_max,
addr + HPAGE_PMD_SIZE > ALIGN_DOWN(vma->vm_end, HPAGE_PMD_SIZE))
goto skip_hint;
+ cc->from_priority_hint = true;
*result = collapse_single_pmd(addr, vma, &lock_dropped, cc);
+ cc->from_priority_hint = false;
if (*result != SCAN_SUCCEED)
(*fail_count)++;
skip_hint:
--
2.52.0