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

wait_for_scan() gives khugepaged a fixed three seconds, whatever a huge
page costs to build. collapse_full() asks for four of them, which is 8M at
a 2M PMD and 2G at a 512M PMD -- arm64 with 64K base pages -- and three
seconds does not cover copying 2G. The escape hatch does not help either:
it wants two full khugepaged passes inside the same three seconds, and one
pass over a 512M PMD takes about that long by itself.

So collapse_full fails there on a collapse that works. Measured with a
probe that faults 4 x 512M, marks it MADV_HUGEPAGE and polls: all four PMDs
collapse, with collapse_alloc=4 at the PMD size and no allocation
failures. Raising only this budget makes the test pass, and it does not
turn into a "Fail" -- which is what khugepaged completing two passes
without collapsing would produce.

Scale the budget with the memory to be collapsed: keep three seconds as
the floor and add a second per 64M. That leaves a 2M PMD at exactly the
three seconds it has now, and gives 35s at a 512M PMD, where the collapse
measures under 3s. Keying it on nr_hpages * hpage_pmd_size rather than the
PMD size alone matters because the callers ask for one or four; scaling
linearly on PMD size alone would ask for 768s, which is not a budget so
much as a hang.

This also brings the helper in line with khugepaged_full_pass(), which
already allows 30s and is why the order-parameterized cases pass at a 512M
PMD while this one did not.

arm64/64K: khugepaged all:anon 21 pass/1 fail -> 22 pass/0 fail. x86-64
unchanged, 129 ok.

Assisted-by: Claude-Code:claude-opus-5
Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]>
---
 tools/testing/selftests/mm/khugepaged.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/mm/khugepaged.c 
b/tools/testing/selftests/mm/khugepaged.c
index 21a8fb24dc43..9213ce1658d0 100644
--- a/tools/testing/selftests/mm/khugepaged.c
+++ b/tools/testing/selftests/mm/khugepaged.c
@@ -573,8 +573,17 @@ static void madvise_collapse(const char *msg, char *p, int 
nr_hpages,
 static bool wait_for_scan(const char *msg, char *p, int nr_hpages,
                          struct mem_ops *ops)
 {
+       /*
+        * The budget has to cover khugepaged copying nr_hpages *
+        * hpage_pmd_size, plus two of its passes over the mm. Three seconds
+        * does that at a 2M PMD, but the same test moves 2G at a 512M PMD
+        * (arm64 with 64K base pages) and 3s is then marginal: it fails on a
+        * collapse that completes correctly, just not inside the budget.
+        * Allow a further second per 64M to collapse.
+        */
+       const unsigned long bytes = (unsigned long)nr_hpages * hpage_pmd_size;
+       int timeout = 6 + 2 * (bytes / (64UL << 20));
        int full_scans;
-       int timeout = 6; /* 3 seconds */
 
        /* Sanity check */
        if (!ops->check_huge(p, 0))
-- 
2.54.0


Reply via email to