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

selftests/mm/cow: add tests for anonymous multi-size THP

Add tests similar to the existing PMD-sized THP tests, but which operate
on memory backed by (PTE-mapped) multi-size THP. This reuses all the
existing infrastructure. If the test suite detects that multi-size THP is
not supported by the kernel, the new tests are skipped.

Link: https://lkml.kernel.org/r/20231207161211.2374093-11-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
c0f79103 12dc16b3

+70 -12
+70 -12
tools/testing/selftests/mm/cow.c
··· 29 29 #include "../../../../mm/gup_test.h" 30 30 #include "../kselftest.h" 31 31 #include "vm_util.h" 32 + #include "thp_settings.h" 32 33 33 34 static size_t pagesize; 34 35 static int pagemap_fd; 35 36 static size_t pmdsize; 37 + static int nr_thpsizes; 38 + static size_t thpsizes[20]; 36 39 static int nr_hugetlbsizes; 37 40 static size_t hugetlbsizes[10]; 38 41 static int gup_fd; 39 42 static bool has_huge_zeropage; 43 + 44 + static int sz2ord(size_t size) 45 + { 46 + return __builtin_ctzll(size / pagesize); 47 + } 48 + 49 + static int detect_thp_sizes(size_t sizes[], int max) 50 + { 51 + int count = 0; 52 + unsigned long orders; 53 + size_t kb; 54 + int i; 55 + 56 + /* thp not supported at all. */ 57 + if (!pmdsize) 58 + return 0; 59 + 60 + orders = 1UL << sz2ord(pmdsize); 61 + orders |= thp_supported_orders(); 62 + 63 + for (i = 0; orders && count < max; i++) { 64 + if (!(orders & (1UL << i))) 65 + continue; 66 + orders &= ~(1UL << i); 67 + kb = (pagesize >> 10) << i; 68 + sizes[count++] = kb * 1024; 69 + ksft_print_msg("[INFO] detected THP size: %zu KiB\n", kb); 70 + } 71 + 72 + return count; 73 + } 40 74 41 75 static void detect_huge_zeropage(void) 42 76 { ··· 1135 1101 1136 1102 run_with_base_page(test_case->fn, test_case->desc); 1137 1103 run_with_base_page_swap(test_case->fn, test_case->desc); 1138 - if (pmdsize) { 1139 - run_with_thp(test_case->fn, test_case->desc, pmdsize); 1140 - run_with_thp_swap(test_case->fn, test_case->desc, pmdsize); 1141 - run_with_pte_mapped_thp(test_case->fn, test_case->desc, pmdsize); 1142 - run_with_pte_mapped_thp_swap(test_case->fn, test_case->desc, pmdsize); 1143 - run_with_single_pte_of_thp(test_case->fn, test_case->desc, pmdsize); 1144 - run_with_single_pte_of_thp_swap(test_case->fn, test_case->desc, pmdsize); 1145 - run_with_partial_mremap_thp(test_case->fn, test_case->desc, pmdsize); 1146 - run_with_partial_shared_thp(test_case->fn, test_case->desc, pmdsize); 1104 + for (i = 0; i < nr_thpsizes; i++) { 1105 + size_t size = thpsizes[i]; 1106 + struct thp_settings settings = *thp_current_settings(); 1107 + 1108 + settings.hugepages[sz2ord(pmdsize)].enabled = THP_NEVER; 1109 + settings.hugepages[sz2ord(size)].enabled = THP_ALWAYS; 1110 + thp_push_settings(&settings); 1111 + 1112 + if (size == pmdsize) { 1113 + run_with_thp(test_case->fn, test_case->desc, size); 1114 + run_with_thp_swap(test_case->fn, test_case->desc, size); 1115 + } 1116 + 1117 + run_with_pte_mapped_thp(test_case->fn, test_case->desc, size); 1118 + run_with_pte_mapped_thp_swap(test_case->fn, test_case->desc, size); 1119 + run_with_single_pte_of_thp(test_case->fn, test_case->desc, size); 1120 + run_with_single_pte_of_thp_swap(test_case->fn, test_case->desc, size); 1121 + run_with_partial_mremap_thp(test_case->fn, test_case->desc, size); 1122 + run_with_partial_shared_thp(test_case->fn, test_case->desc, size); 1123 + 1124 + thp_pop_settings(); 1147 1125 } 1148 1126 for (i = 0; i < nr_hugetlbsizes; i++) 1149 1127 run_with_hugetlb(test_case->fn, test_case->desc, ··· 1176 1130 { 1177 1131 int tests = 2 + nr_hugetlbsizes; 1178 1132 1133 + tests += 6 * nr_thpsizes; 1179 1134 if (pmdsize) 1180 - tests += 8; 1135 + tests += 2; 1181 1136 return tests; 1182 1137 } 1183 1138 ··· 1736 1689 int main(int argc, char **argv) 1737 1690 { 1738 1691 int err; 1692 + struct thp_settings default_settings; 1739 1693 1740 1694 ksft_print_header(); 1741 1695 1742 1696 pagesize = getpagesize(); 1743 1697 pmdsize = read_pmd_pagesize(); 1744 1698 if (pmdsize) { 1699 + /* Only if THP is supported. */ 1700 + thp_read_settings(&default_settings); 1701 + default_settings.hugepages[sz2ord(pmdsize)].enabled = THP_INHERIT; 1702 + thp_save_settings(); 1703 + thp_push_settings(&default_settings); 1704 + 1745 1705 ksft_print_msg("[INFO] detected PMD size: %zu KiB\n", 1746 1706 pmdsize / 1024); 1747 - ksft_print_msg("[INFO] detected THP size: %zu KiB\n", 1748 - pmdsize / 1024); 1707 + nr_thpsizes = detect_thp_sizes(thpsizes, ARRAY_SIZE(thpsizes)); 1749 1708 } 1750 1709 nr_hugetlbsizes = detect_hugetlb_page_sizes(hugetlbsizes, 1751 1710 ARRAY_SIZE(hugetlbsizes)); ··· 1769 1716 run_anon_test_cases(); 1770 1717 run_anon_thp_test_cases(); 1771 1718 run_non_anon_test_cases(); 1719 + 1720 + if (pmdsize) { 1721 + /* Only if THP is supported. */ 1722 + thp_restore_settings(); 1723 + } 1772 1724 1773 1725 err = ksft_get_fail_cnt(); 1774 1726 if (err)