[PATCH 13/16] selftests/mm: parameterize the mixed-source collapse case by source order
From: Kiryl Shutsemau
Date: Sun Aug 02 2026 - 16:01:14 EST
From: "Kiryl Shutsemau (Meta)" <kas@xxxxxxxxxx>
collapse_order_mixed_sources faults its region as order-2 folios and
collapses them to the -o target, covering collapse of sources that are
already large folios of an order below the target. But it only ever tests
one source order, and order 2 sits below the contpte threshold on both
arm64 page-size configs -- so a source-side contpte unfold is never
exercised deterministically by this suite.
Let -s name the source order when combined with -o (it was rejected
before): the mixed-source case then faults at order @anon_order instead of
the fixed order 2, keeping order 2 as the default when -s is absent. -s
stays constrained to a supported mTHP order strictly below the target; the
other order-parameterized cases keep their order-0 sources (the source
order is enabled locally, not globally), so -s under -o is a knob on the
mixed-source case alone.
This makes e.g. -s 5 -o 7 on arm64/64K collapse contpte-mapped sources
into a larger mTHP, covering the source-unfold path directly.
Assisted-by: Claude-Code:claude-opus-5
Signed-off-by: Kiryl Shutsemau (Meta) <kas@xxxxxxxxxx>
---
tools/testing/selftests/mm/khugepaged.c | 42 +++++++++++++++++++------
1 file changed, 32 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selftests/mm/khugepaged.c
index b074b005b62f..21a8fb24dc43 100644
--- a/tools/testing/selftests/mm/khugepaged.c
+++ b/tools/testing/selftests/mm/khugepaged.c
@@ -1363,28 +1363,32 @@ static void collapse_order_mixed_sources(struct collapse_context *c,
struct mem_ops *ops)
{
struct thp_settings settings = *thp_current_settings();
+ int source_order = anon_order ? anon_order : MIN_MTHP_ORDER;
void *p;
- if (anon_target_order <= MIN_MTHP_ORDER) {
+ /* Sources must be a supported mTHP order strictly below the target. */
+ if (source_order >= anon_target_order ||
+ !(thp_supported_orders() & (1UL << source_order))) {
ksft_test_result_skip("%s: no source order below target\n",
__func__);
return;
}
- /* Fault the whole region as order-MIN_MTHP_ORDER folios. */
- settings.hugepages[MIN_MTHP_ORDER].enabled = THP_ALWAYS;
+ /* Fault the whole region as order-@source_order folios. */
+ settings.hugepages[source_order].enabled = THP_ALWAYS;
thp_push_settings(&settings);
p = ops->setup_area(1);
ops->fault(p, 0, hpage_pmd_size);
thp_pop_settings();
- if (!is_range_backed_by_folio_orders(p, hpage_pmd_size, MIN_MTHP_ORDER,
+ if (!is_range_backed_by_folio_orders(p, hpage_pmd_size, source_order,
pagemap_fd, kpageflags_fd))
ksft_exit_fail_msg("Region not backed by order-%d folios after fault\n",
- MIN_MTHP_ORDER);
+ source_order);
madvise(p, hpage_pmd_size, MADV_HUGEPAGE);
- ksft_print_msg("Collapse region backed by smaller large folios...");
+ ksft_print_msg("Collapse region backed by order-%d sources...",
+ source_order);
if (!khugepaged_wait_full_pass())
fail("Timeout");
else if (range_collapsed(p, hpage_pmd_size))
@@ -1414,7 +1418,9 @@ static void usage(void)
fprintf(stderr, "\t\t Defaults to 0. Use this size for anon or shmem allocations.\n");
fprintf(stderr, "\t\t-o: collapse target order for khugepaged:anon.\n");
fprintf(stderr, "\t\t Runs the order-parameterized collapse cases instead\n");
- fprintf(stderr, "\t\t of the PMD cases. Cannot be combined with -s.\n");
+ fprintf(stderr, "\t\t of the PMD cases.\n");
+ fprintf(stderr, "\t\t With -s, -s names the mTHP source order for the\n");
+ fprintf(stderr, "\t\t mixed-source case (source order below the target).\n");
exit(1);
}
@@ -1438,7 +1444,15 @@ static void parse_test_type(int argc, char **argv)
}
}
- if (anon_target_order && anon_order)
+ /*
+ * -s and -o compose: -s then names the mTHP source order for the
+ * mixed-source case, which needs a source strictly below the
+ * target (and at or above the smallest mTHP order). Alone, -s is
+ * the source order for the default PMD suite; alone, -o is the
+ * collapse target for the order-parameterized suite.
+ */
+ if (anon_target_order && anon_order &&
+ (anon_order < MIN_MTHP_ORDER || anon_order >= anon_target_order))
usage();
argv += optind;
@@ -1573,9 +1587,17 @@ int main(int argc, char **argv)
default_settings.khugepaged.max_ptes_shared = hpage_pmd_nr / 2;
default_settings.khugepaged.pages_to_scan = hpage_pmd_nr * 8;
default_settings.hugepages[hpage_pmd_order].enabled = THP_INHERIT;
- default_settings.hugepages[anon_order].enabled = THP_ALWAYS;
default_settings.shmem_hugepages[hpage_pmd_order].enabled = SHMEM_INHERIT;
- default_settings.shmem_hugepages[anon_order].enabled = SHMEM_ALWAYS;
+ /*
+ * Under -o the order-parameterized cases want order-0 sources by
+ * default; the mixed-source case enables its own (possibly -s
+ * selected) source order locally. Enabling it globally here would
+ * make every case fault that order.
+ */
+ if (!anon_target_order) {
+ default_settings.hugepages[anon_order].enabled = THP_ALWAYS;
+ default_settings.shmem_hugepages[anon_order].enabled = SHMEM_ALWAYS;
+ }
if (anon_target_order) {
/*
--
2.54.0