Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/mm/cow: generalize do_run_with_thp() helper

do_run_with_thp() prepares (PMD-sized) THP memory into different states
before running tests. With the introduction of multi-size THP, we would
like to reuse this logic to also test those smaller THP sizes. So let's
add a thpsize parameter which tells the function what size THP it should
operate on.

A separate commit will utilize this change to add new tests for multi-size
THP, where available.

Link: https://lkml.kernel.org/r/20231207161211.2374093-10-ryan.roberts@arm.com
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Tested-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Tested-by: John Hubbard <jhubbard@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Barry Song <v-songbaohua@oppo.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: David Rientjes <rientjes@google.com>
Cc: "Huang, Ying" <ying.huang@intel.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Itaru Kitayama <itaru.kitayama@gmail.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Luis Chamberlain <mcgrof@kernel.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Yang Shi <shy828301@gmail.com>
Cc: Yin Fengwei <fengwei.yin@intel.com>
Cc: Yu Zhao <yuzhao@google.com>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Ryan Roberts and committed by
Andrew Morton
12dc16b3 9f0704ea

+67 -54
+67 -54
tools/testing/selftests/mm/cow.c
··· 32 32 33 33 static size_t pagesize; 34 34 static int pagemap_fd; 35 - static size_t thpsize; 35 + static size_t pmdsize; 36 36 static int nr_hugetlbsizes; 37 37 static size_t hugetlbsizes[10]; 38 38 static int gup_fd; ··· 734 734 THP_RUN_PARTIAL_SHARED, 735 735 }; 736 736 737 - static void do_run_with_thp(test_fn fn, enum thp_run thp_run) 737 + static void do_run_with_thp(test_fn fn, enum thp_run thp_run, size_t thpsize) 738 738 { 739 739 char *mem, *mmap_mem, *tmp, *mremap_mem = MAP_FAILED; 740 740 size_t size, mmap_size, mremap_size; ··· 759 759 } 760 760 761 761 /* 762 - * Try to populate a THP. Touch the first sub-page and test if we get 763 - * another sub-page populated automatically. 762 + * Try to populate a THP. Touch the first sub-page and test if 763 + * we get the last sub-page populated automatically. 764 764 */ 765 765 mem[0] = 0; 766 - if (!pagemap_is_populated(pagemap_fd, mem + pagesize)) { 766 + if (!pagemap_is_populated(pagemap_fd, mem + thpsize - pagesize)) { 767 767 ksft_test_result_skip("Did not get a THP populated\n"); 768 768 goto munmap; 769 769 } ··· 773 773 switch (thp_run) { 774 774 case THP_RUN_PMD: 775 775 case THP_RUN_PMD_SWAPOUT: 776 + assert(thpsize == pmdsize); 776 777 break; 777 778 case THP_RUN_PTE: 778 779 case THP_RUN_PTE_SWAPOUT: 779 780 /* 780 781 * Trigger PTE-mapping the THP by temporarily mapping a single 781 - * subpage R/O. 782 + * subpage R/O. This is a noop if the THP is not pmdsize (and 783 + * therefore already PTE-mapped). 782 784 */ 783 785 ret = mprotect(mem + pagesize, pagesize, PROT_READ); 784 786 if (ret) { ··· 877 875 munmap(mremap_mem, mremap_size); 878 876 } 879 877 880 - static void run_with_thp(test_fn fn, const char *desc) 878 + static void run_with_thp(test_fn fn, const char *desc, size_t size) 881 879 { 882 - ksft_print_msg("[RUN] %s ... with THP\n", desc); 883 - do_run_with_thp(fn, THP_RUN_PMD); 880 + ksft_print_msg("[RUN] %s ... with THP (%zu kB)\n", 881 + desc, size / 1024); 882 + do_run_with_thp(fn, THP_RUN_PMD, size); 884 883 } 885 884 886 - static void run_with_thp_swap(test_fn fn, const char *desc) 885 + static void run_with_thp_swap(test_fn fn, const char *desc, size_t size) 887 886 { 888 - ksft_print_msg("[RUN] %s ... with swapped-out THP\n", desc); 889 - do_run_with_thp(fn, THP_RUN_PMD_SWAPOUT); 887 + ksft_print_msg("[RUN] %s ... with swapped-out THP (%zu kB)\n", 888 + desc, size / 1024); 889 + do_run_with_thp(fn, THP_RUN_PMD_SWAPOUT, size); 890 890 } 891 891 892 - static void run_with_pte_mapped_thp(test_fn fn, const char *desc) 892 + static void run_with_pte_mapped_thp(test_fn fn, const char *desc, size_t size) 893 893 { 894 - ksft_print_msg("[RUN] %s ... with PTE-mapped THP\n", desc); 895 - do_run_with_thp(fn, THP_RUN_PTE); 894 + ksft_print_msg("[RUN] %s ... with PTE-mapped THP (%zu kB)\n", 895 + desc, size / 1024); 896 + do_run_with_thp(fn, THP_RUN_PTE, size); 896 897 } 897 898 898 - static void run_with_pte_mapped_thp_swap(test_fn fn, const char *desc) 899 + static void run_with_pte_mapped_thp_swap(test_fn fn, const char *desc, size_t size) 899 900 { 900 - ksft_print_msg("[RUN] %s ... with swapped-out, PTE-mapped THP\n", desc); 901 - do_run_with_thp(fn, THP_RUN_PTE_SWAPOUT); 901 + ksft_print_msg("[RUN] %s ... with swapped-out, PTE-mapped THP (%zu kB)\n", 902 + desc, size / 1024); 903 + do_run_with_thp(fn, THP_RUN_PTE_SWAPOUT, size); 902 904 } 903 905 904 - static void run_with_single_pte_of_thp(test_fn fn, const char *desc) 906 + static void run_with_single_pte_of_thp(test_fn fn, const char *desc, size_t size) 905 907 { 906 - ksft_print_msg("[RUN] %s ... with single PTE of THP\n", desc); 907 - do_run_with_thp(fn, THP_RUN_SINGLE_PTE); 908 + ksft_print_msg("[RUN] %s ... with single PTE of THP (%zu kB)\n", 909 + desc, size / 1024); 910 + do_run_with_thp(fn, THP_RUN_SINGLE_PTE, size); 908 911 } 909 912 910 - static void run_with_single_pte_of_thp_swap(test_fn fn, const char *desc) 913 + static void run_with_single_pte_of_thp_swap(test_fn fn, const char *desc, size_t size) 911 914 { 912 - ksft_print_msg("[RUN] %s ... with single PTE of swapped-out THP\n", desc); 913 - do_run_with_thp(fn, THP_RUN_SINGLE_PTE_SWAPOUT); 915 + ksft_print_msg("[RUN] %s ... with single PTE of swapped-out THP (%zu kB)\n", 916 + desc, size / 1024); 917 + do_run_with_thp(fn, THP_RUN_SINGLE_PTE_SWAPOUT, size); 914 918 } 915 919 916 - static void run_with_partial_mremap_thp(test_fn fn, const char *desc) 920 + static void run_with_partial_mremap_thp(test_fn fn, const char *desc, size_t size) 917 921 { 918 - ksft_print_msg("[RUN] %s ... with partially mremap()'ed THP\n", desc); 919 - do_run_with_thp(fn, THP_RUN_PARTIAL_MREMAP); 922 + ksft_print_msg("[RUN] %s ... with partially mremap()'ed THP (%zu kB)\n", 923 + desc, size / 1024); 924 + do_run_with_thp(fn, THP_RUN_PARTIAL_MREMAP, size); 920 925 } 921 926 922 - static void run_with_partial_shared_thp(test_fn fn, const char *desc) 927 + static void run_with_partial_shared_thp(test_fn fn, const char *desc, size_t size) 923 928 { 924 - ksft_print_msg("[RUN] %s ... with partially shared THP\n", desc); 925 - do_run_with_thp(fn, THP_RUN_PARTIAL_SHARED); 929 + ksft_print_msg("[RUN] %s ... with partially shared THP (%zu kB)\n", 930 + desc, size / 1024); 931 + do_run_with_thp(fn, THP_RUN_PARTIAL_SHARED, size); 926 932 } 927 933 928 934 static void run_with_hugetlb(test_fn fn, const char *desc, size_t hugetlbsize) ··· 1101 1091 1102 1092 run_with_base_page(test_case->fn, test_case->desc); 1103 1093 run_with_base_page_swap(test_case->fn, test_case->desc); 1104 - if (thpsize) { 1105 - run_with_thp(test_case->fn, test_case->desc); 1106 - run_with_thp_swap(test_case->fn, test_case->desc); 1107 - run_with_pte_mapped_thp(test_case->fn, test_case->desc); 1108 - run_with_pte_mapped_thp_swap(test_case->fn, test_case->desc); 1109 - run_with_single_pte_of_thp(test_case->fn, test_case->desc); 1110 - run_with_single_pte_of_thp_swap(test_case->fn, test_case->desc); 1111 - run_with_partial_mremap_thp(test_case->fn, test_case->desc); 1112 - run_with_partial_shared_thp(test_case->fn, test_case->desc); 1094 + if (pmdsize) { 1095 + run_with_thp(test_case->fn, test_case->desc, pmdsize); 1096 + run_with_thp_swap(test_case->fn, test_case->desc, pmdsize); 1097 + run_with_pte_mapped_thp(test_case->fn, test_case->desc, pmdsize); 1098 + run_with_pte_mapped_thp_swap(test_case->fn, test_case->desc, pmdsize); 1099 + run_with_single_pte_of_thp(test_case->fn, test_case->desc, pmdsize); 1100 + run_with_single_pte_of_thp_swap(test_case->fn, test_case->desc, pmdsize); 1101 + run_with_partial_mremap_thp(test_case->fn, test_case->desc, pmdsize); 1102 + run_with_partial_shared_thp(test_case->fn, test_case->desc, pmdsize); 1113 1103 } 1114 1104 for (i = 0; i < nr_hugetlbsizes; i++) 1115 1105 run_with_hugetlb(test_case->fn, test_case->desc, ··· 1130 1120 { 1131 1121 int tests = 2 + nr_hugetlbsizes; 1132 1122 1133 - if (thpsize) 1123 + if (pmdsize) 1134 1124 tests += 8; 1135 1125 return tests; 1136 1126 } ··· 1339 1329 { 1340 1330 int i; 1341 1331 1342 - if (!thpsize) 1332 + if (!pmdsize) 1343 1333 return; 1344 1334 1345 1335 ksft_print_msg("[INFO] Anonymous THP tests\n"); ··· 1348 1338 struct test_case const *test_case = &anon_thp_test_cases[i]; 1349 1339 1350 1340 ksft_print_msg("[RUN] %s\n", test_case->desc); 1351 - do_run_with_thp(test_case->fn, THP_RUN_PMD); 1341 + do_run_with_thp(test_case->fn, THP_RUN_PMD, pmdsize); 1352 1342 } 1353 1343 } 1354 1344 1355 1345 static int tests_per_anon_thp_test_case(void) 1356 1346 { 1357 - return thpsize ? 1 : 0; 1347 + return pmdsize ? 1 : 0; 1358 1348 } 1359 1349 1360 1350 typedef void (*non_anon_test_fn)(char *mem, const char *smem, size_t size); ··· 1429 1419 } 1430 1420 1431 1421 /* For alignment purposes, we need twice the thp size. */ 1432 - mmap_size = 2 * thpsize; 1422 + mmap_size = 2 * pmdsize; 1433 1423 mmap_mem = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, 1434 1424 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 1435 1425 if (mmap_mem == MAP_FAILED) { ··· 1444 1434 } 1445 1435 1446 1436 /* We need a THP-aligned memory area. */ 1447 - mem = (char *)(((uintptr_t)mmap_mem + thpsize) & ~(thpsize - 1)); 1448 - smem = (char *)(((uintptr_t)mmap_smem + thpsize) & ~(thpsize - 1)); 1437 + mem = (char *)(((uintptr_t)mmap_mem + pmdsize) & ~(pmdsize - 1)); 1438 + smem = (char *)(((uintptr_t)mmap_smem + pmdsize) & ~(pmdsize - 1)); 1449 1439 1450 - ret = madvise(mem, thpsize, MADV_HUGEPAGE); 1451 - ret |= madvise(smem, thpsize, MADV_HUGEPAGE); 1440 + ret = madvise(mem, pmdsize, MADV_HUGEPAGE); 1441 + ret |= madvise(smem, pmdsize, MADV_HUGEPAGE); 1452 1442 if (ret) { 1453 1443 ksft_test_result_fail("MADV_HUGEPAGE failed\n"); 1454 1444 goto munmap; ··· 1467 1457 goto munmap; 1468 1458 } 1469 1459 1470 - fn(mem, smem, thpsize); 1460 + fn(mem, smem, pmdsize); 1471 1461 munmap: 1472 1462 munmap(mmap_mem, mmap_size); 1473 1463 if (mmap_smem != MAP_FAILED) ··· 1660 1650 run_with_zeropage(test_case->fn, test_case->desc); 1661 1651 run_with_memfd(test_case->fn, test_case->desc); 1662 1652 run_with_tmpfile(test_case->fn, test_case->desc); 1663 - if (thpsize) 1653 + if (pmdsize) 1664 1654 run_with_huge_zeropage(test_case->fn, test_case->desc); 1665 1655 for (i = 0; i < nr_hugetlbsizes; i++) 1666 1656 run_with_memfd_hugetlb(test_case->fn, test_case->desc, ··· 1681 1671 { 1682 1672 int tests = 3 + nr_hugetlbsizes; 1683 1673 1684 - if (thpsize) 1674 + if (pmdsize) 1685 1675 tests += 1; 1686 1676 return tests; 1687 1677 } ··· 1693 1683 ksft_print_header(); 1694 1684 1695 1685 pagesize = getpagesize(); 1696 - thpsize = read_pmd_pagesize(); 1697 - if (thpsize) 1686 + pmdsize = read_pmd_pagesize(); 1687 + if (pmdsize) { 1688 + ksft_print_msg("[INFO] detected PMD size: %zu KiB\n", 1689 + pmdsize / 1024); 1698 1690 ksft_print_msg("[INFO] detected THP size: %zu KiB\n", 1699 - thpsize / 1024); 1691 + pmdsize / 1024); 1692 + } 1700 1693 nr_hugetlbsizes = detect_hugetlb_page_sizes(hugetlbsizes, 1701 1694 ARRAY_SIZE(hugetlbsizes)); 1702 1695 detect_huge_zeropage();