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

selftests/mm/khugepaged: enlighten for multi-size THP

The `collapse_max_ptes_none` test was previously failing when a THP size
less than PMD-size had enabled="always". The root cause is because the
test faults in 1 page less than the threshold it set for collapsing. But
when THP is enabled always, we "over allocate" and therefore the threshold
is passed, and collapse unexpectedly succeeds.

Solve this by enlightening khugepaged selftest. Add a command line option
to pass in the desired THP size that should be used for all anonymous
allocations. The harness will then explicitly configure a THP size as
requested and modify the `collapse_max_ptes_none` test so that it faults
in the threshold minus the number of pages in the configured THP size. If
no command line option is provided, default to order 0, as per previous
behaviour.

I chose to use an order in the command line interface, since this makes
the interface agnostic of base page size, making it easier to invoke from
run_vmtests.sh.

Link: https://lkml.kernel.org/r/20231207161211.2374093-9-ryan.roberts@arm.com
Signed-off-by: Ryan Roberts <ryan.roberts@arm.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 Hildenbrand <david@redhat.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
9f0704ea 4f5070a5

+39 -11
+37 -11
tools/testing/selftests/mm/khugepaged.c
··· 28 28 static unsigned long hpage_pmd_size; 29 29 static unsigned long page_size; 30 30 static int hpage_pmd_nr; 31 + static int anon_order; 31 32 32 33 #define PID_SMAPS "/proc/self/smaps" 33 34 #define TEST_FILE "collapse_test_file" ··· 608 607 return ops == &__file_ops && finfo.type == VMA_SHMEM; 609 608 } 610 609 610 + static bool is_anon(struct mem_ops *ops) 611 + { 612 + return ops == &__anon_ops; 613 + } 614 + 611 615 static void alloc_at_fault(void) 612 616 { 613 617 struct thp_settings settings = *thp_current_settings(); ··· 679 673 int max_ptes_none = hpage_pmd_nr / 2; 680 674 struct thp_settings settings = *thp_current_settings(); 681 675 void *p; 676 + int fault_nr_pages = is_anon(ops) ? 1 << anon_order : 1; 682 677 683 678 settings.khugepaged.max_ptes_none = max_ptes_none; 684 679 thp_push_settings(&settings); ··· 693 686 goto skip; 694 687 } 695 688 696 - ops->fault(p, 0, (hpage_pmd_nr - max_ptes_none - 1) * page_size); 689 + ops->fault(p, 0, (hpage_pmd_nr - max_ptes_none - fault_nr_pages) * page_size); 697 690 c->collapse("Maybe collapse with max_ptes_none exceeded", p, 1, 698 691 ops, !c->enforce_pte_scan_limits); 699 - validate_memory(p, 0, (hpage_pmd_nr - max_ptes_none - 1) * page_size); 692 + validate_memory(p, 0, (hpage_pmd_nr - max_ptes_none - fault_nr_pages) * page_size); 700 693 701 694 if (c->enforce_pte_scan_limits) { 702 695 ops->fault(p, 0, (hpage_pmd_nr - max_ptes_none) * page_size); ··· 1083 1076 1084 1077 static void usage(void) 1085 1078 { 1086 - fprintf(stderr, "\nUsage: ./khugepaged <test type> [dir]\n\n"); 1079 + fprintf(stderr, "\nUsage: ./khugepaged [OPTIONS] <test type> [dir]\n\n"); 1087 1080 fprintf(stderr, "\t<test type>\t: <context>:<mem_type>\n"); 1088 1081 fprintf(stderr, "\t<context>\t: [all|khugepaged|madvise]\n"); 1089 1082 fprintf(stderr, "\t<mem_type>\t: [all|anon|file|shmem]\n"); ··· 1092 1085 fprintf(stderr, "\tCONFIG_READ_ONLY_THP_FOR_FS=y\n"); 1093 1086 fprintf(stderr, "\n\tif [dir] is a (sub)directory of a tmpfs mount, tmpfs must be\n"); 1094 1087 fprintf(stderr, "\tmounted with huge=madvise option for khugepaged tests to work\n"); 1088 + fprintf(stderr, "\n\tSupported Options:\n"); 1089 + fprintf(stderr, "\t\t-h: This help message.\n"); 1090 + fprintf(stderr, "\t\t-s: mTHP size, expressed as page order.\n"); 1091 + fprintf(stderr, "\t\t Defaults to 0. Use this size for anon allocations.\n"); 1095 1092 exit(1); 1096 1093 } 1097 1094 1098 - static void parse_test_type(int argc, const char **argv) 1095 + static void parse_test_type(int argc, char **argv) 1099 1096 { 1097 + int opt; 1100 1098 char *buf; 1101 1099 const char *token; 1102 1100 1103 - if (argc == 1) { 1101 + while ((opt = getopt(argc, argv, "s:h")) != -1) { 1102 + switch (opt) { 1103 + case 's': 1104 + anon_order = atoi(optarg); 1105 + break; 1106 + case 'h': 1107 + default: 1108 + usage(); 1109 + } 1110 + } 1111 + 1112 + argv += optind; 1113 + argc -= optind; 1114 + 1115 + if (argc == 0) { 1104 1116 /* Backwards compatibility */ 1105 1117 khugepaged_context = &__khugepaged_context; 1106 1118 madvise_context = &__madvise_context; ··· 1127 1101 return; 1128 1102 } 1129 1103 1130 - buf = strdup(argv[1]); 1104 + buf = strdup(argv[0]); 1131 1105 token = strsep(&buf, ":"); 1132 1106 1133 1107 if (!strcmp(token, "all")) { ··· 1161 1135 if (!file_ops) 1162 1136 return; 1163 1137 1164 - if (argc != 3) 1138 + if (argc != 2) 1165 1139 usage(); 1140 + 1141 + get_finfo(argv[1]); 1166 1142 } 1167 1143 1168 - int main(int argc, const char **argv) 1144 + int main(int argc, char **argv) 1169 1145 { 1170 1146 int hpage_pmd_order; 1171 1147 struct thp_settings default_settings = { ··· 1192 1164 1193 1165 parse_test_type(argc, argv); 1194 1166 1195 - if (file_ops) 1196 - get_finfo(argv[2]); 1197 - 1198 1167 setbuf(stdout, NULL); 1199 1168 1200 1169 page_size = getpagesize(); ··· 1208 1183 default_settings.khugepaged.max_ptes_shared = hpage_pmd_nr / 2; 1209 1184 default_settings.khugepaged.pages_to_scan = hpage_pmd_nr * 8; 1210 1185 default_settings.hugepages[hpage_pmd_order].enabled = THP_INHERIT; 1186 + default_settings.hugepages[anon_order].enabled = THP_ALWAYS; 1211 1187 1212 1188 save_settings(); 1213 1189 thp_push_settings(&default_settings);
+2
tools/testing/selftests/mm/run_vmtests.sh
··· 357 357 358 358 CATEGORY="thp" run_test ./khugepaged 359 359 360 + CATEGORY="thp" run_test ./khugepaged -s 2 361 + 360 362 CATEGORY="thp" run_test ./transhuge-stress -d 20 361 363 362 364 CATEGORY="thp" run_test ./split_huge_page_test