mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
selftests/mm: run every supported collapse order by default
The mTHP collapse cases only run when the caller names both the context
and an order, so a plain ./khugepaged covers the PMD contexts on anon and
nothing else. run_vmtests.sh pinned order 4 and covered no other.
Run the mTHP cases once per supported anon THP order below the PMD when -c
is absent, and pull that context into both the no-argument invocation and
"all". Also:
- -c still pins one order, and now says what is wrong instead of
printing the usage text.
- Both orders end up as array indices and shift counts, so -s and -c
are range-checked before they get there.
- The mTHP context has only anon cases, so a run that names a different
mem_type -- "all:shmem", say -- drops it again rather than refusing
to start. Naming both explicitly still refuses.
- A case carries the order it was registered at, so a result names it:
# Run test: collapse_single_mthp (mthp_khugepaged:anon, order 6)
On x86-64 with 4K pages that is orders 2 through 8, and ./khugepaged goes
from 29 results in 17 seconds to 77 in 29, so run_vmtests.sh can drop its
pinned order-4 line.
Link: https://lore.kernel.org/20260919002451.496763-15-kirill@shutemov.name
Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Tested-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Assisted-by: LLM
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Barry Song <baohua@kernel.org>
Cc: "David Hildenbrand (arm)" <david@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Hugh Dickens <hughd@google.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: kernel-team@meta.com
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Liam Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport (Microsoft) <rppt@kernel.org>
Cc: Nico Pache (Red Hat) <nico.pache@linux.dev>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Shuah Khan (Samsung OSG) <shuah@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Usama Arif <usama.arif@linux.dev>
Cc: "Vlastimil Babka (SUSE)" <vbabka@kernel.org>
Cc: Zi Yan <ziy@nvidia.com>
This commit is contained in:
parent
e1fe35d6c8
commit
e5d767fe33
|
|
@ -30,6 +30,9 @@ static unsigned long page_size;
|
|||
static int hpage_pmd_nr;
|
||||
static int anon_order;
|
||||
static int collapse_order;
|
||||
static bool collapse_order_set;
|
||||
static int collapse_orders[NR_ORDERS];
|
||||
static int nr_collapse_orders;
|
||||
static int pagemap_fd = -1;
|
||||
static int kpageflags_fd = -1;
|
||||
|
||||
|
|
@ -1525,12 +1528,14 @@ static void usage(void)
|
|||
fprintf(stderr, "\t\t-s: mTHP size, expressed as page order.\n");
|
||||
fprintf(stderr, "\t\t Defaults to 0. Use this size for anon or shmem allocations.\n");
|
||||
fprintf(stderr, "\t\t-c: collapse order for mTHP collapse, expressed as page order.\n");
|
||||
fprintf(stderr, "\t\t Defaults to every supported order below the PMD.\n");
|
||||
fprintf(stderr, "\t\t -s, if set, is the source order for the mixed-source case.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void parse_test_type(int argc, char **argv)
|
||||
{
|
||||
bool mthp_context_implied = false;
|
||||
int opt;
|
||||
char *buf;
|
||||
const char *token;
|
||||
|
|
@ -1542,6 +1547,7 @@ static void parse_test_type(int argc, char **argv)
|
|||
break;
|
||||
case 'c':
|
||||
collapse_order = atoi(optarg);
|
||||
collapse_order_set = true;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
|
|
@ -1549,12 +1555,25 @@ static void parse_test_type(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Both orders end up as array indices and shift counts, so neither
|
||||
* can be negative, and a zero collapse order asks for base pages.
|
||||
*/
|
||||
if (anon_order < 0 || anon_order > hpage_pmd_order)
|
||||
ksft_exit_fail_msg("-s takes an order in 0..%d, not %d\n",
|
||||
hpage_pmd_order, anon_order);
|
||||
if (collapse_order_set &&
|
||||
(collapse_order <= 0 || collapse_order >= hpage_pmd_order))
|
||||
ksft_exit_fail_msg("-c takes an order in 1..%d, not %d\n",
|
||||
hpage_pmd_order - 1, collapse_order);
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (argc == 0) {
|
||||
/* Backwards compatibility */
|
||||
/* No arguments: anon under every context */
|
||||
khugepaged_context = &__khugepaged_context;
|
||||
mthp_khugepaged_context = &__mthp_khugepaged_context;
|
||||
madvise_context = &__madvise_context;
|
||||
anon_ops = &__anon_ops;
|
||||
return;
|
||||
|
|
@ -1565,13 +1584,14 @@ static void parse_test_type(int argc, char **argv)
|
|||
|
||||
if (!strcmp(token, "all")) {
|
||||
khugepaged_context = &__khugepaged_context;
|
||||
mthp_khugepaged_context = &__mthp_khugepaged_context;
|
||||
madvise_context = &__madvise_context;
|
||||
/* The mTHP context has only anon cases; let other mem_types drop it */
|
||||
mthp_context_implied = true;
|
||||
} else if (!strcmp(token, "khugepaged")) {
|
||||
khugepaged_context = &__khugepaged_context;
|
||||
} else if (!strcmp(token, "mthp_khugepaged")) {
|
||||
mthp_khugepaged_context = &__mthp_khugepaged_context;
|
||||
if (collapse_order <= 0 || collapse_order >= hpage_pmd_order)
|
||||
usage();
|
||||
} else if (!strcmp(token, "madvise")) {
|
||||
madvise_context = &__madvise_context;
|
||||
} else {
|
||||
|
|
@ -1587,20 +1607,20 @@ static void parse_test_type(int argc, char **argv)
|
|||
read_write_file_write_ops = &__read_write_file_write_ops;
|
||||
anon_ops = &__anon_ops;
|
||||
shmem_ops = &__shmem_ops;
|
||||
if (mthp_khugepaged_context)
|
||||
usage();
|
||||
} else if (!strcmp(buf, "anon")) {
|
||||
anon_ops = &__anon_ops;
|
||||
} else if (!strcmp(buf, "file")) {
|
||||
read_only_file_ops = &__read_only_file_ops;
|
||||
read_write_file_read_ops = &__read_write_file_read_ops;
|
||||
read_write_file_write_ops = &__read_write_file_write_ops;
|
||||
if (mthp_khugepaged_context)
|
||||
if (mthp_khugepaged_context && !mthp_context_implied)
|
||||
usage();
|
||||
mthp_khugepaged_context = NULL;
|
||||
} else if (!strcmp(buf, "shmem")) {
|
||||
shmem_ops = &__shmem_ops;
|
||||
if (mthp_khugepaged_context)
|
||||
if (mthp_khugepaged_context && !mthp_context_implied)
|
||||
usage();
|
||||
mthp_khugepaged_context = NULL;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
|
|
@ -1622,6 +1642,7 @@ struct test_case {
|
|||
struct mem_ops *ops;
|
||||
const char *desc;
|
||||
test_fn fn;
|
||||
int order; /* mTHP contexts: the collapse order */
|
||||
};
|
||||
|
||||
#define MAX_TEST_CASES 256
|
||||
|
|
@ -1637,6 +1658,7 @@ static int nr_test_cases;
|
|||
.ops = o, \
|
||||
.desc = #t, \
|
||||
.fn = t, \
|
||||
.order = collapse_order, \
|
||||
}; \
|
||||
} \
|
||||
} while (0)
|
||||
|
|
@ -1677,13 +1699,35 @@ int main(int argc, char **argv)
|
|||
|
||||
parse_test_type(argc, argv);
|
||||
|
||||
if (mthp_khugepaged_context &&
|
||||
!(thp_supported_orders() & (1UL << collapse_order)))
|
||||
ksft_exit_skip("Order %d is not a supported anon THP order\n",
|
||||
collapse_order);
|
||||
if (mthp_khugepaged_context && collapse_order <= anon_order)
|
||||
ksft_exit_skip("-c %d needs a source order below it, -s says %d\n",
|
||||
collapse_order, anon_order);
|
||||
if (mthp_khugepaged_context) {
|
||||
unsigned long orders = thp_supported_orders();
|
||||
|
||||
if (collapse_order_set) {
|
||||
if (!(orders & (1UL << collapse_order)))
|
||||
ksft_exit_skip("Order %d is not a supported anon THP order\n",
|
||||
collapse_order);
|
||||
if (collapse_order <= anon_order)
|
||||
ksft_exit_skip("-c %d needs a source order below it, -s says %d\n",
|
||||
collapse_order, anon_order);
|
||||
collapse_orders[nr_collapse_orders++] = collapse_order;
|
||||
} else {
|
||||
/*
|
||||
* Every supported order above the source: -s makes the
|
||||
* fault path hand out folios of that order, so a target
|
||||
* at or below it has nothing to collapse.
|
||||
*/
|
||||
int first = anon_order + 1;
|
||||
|
||||
if (first < MIN_MTHP_ORDER)
|
||||
first = MIN_MTHP_ORDER;
|
||||
for (int i = first; i < hpage_pmd_order; i++) {
|
||||
if (orders & (1UL << i))
|
||||
collapse_orders[nr_collapse_orders++] = i;
|
||||
}
|
||||
if (!nr_collapse_orders)
|
||||
ksft_print_msg("mTHP cases skipped: no order above the source\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (mthp_khugepaged_context) {
|
||||
pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
|
||||
|
|
@ -1732,7 +1776,17 @@ int main(int argc, char **argv)
|
|||
TEST(collapse_full, khugepaged_context, read_write_file_read_ops);
|
||||
TEST(collapse_full, khugepaged_context, read_write_file_write_ops);
|
||||
TEST(collapse_full, khugepaged_context, shmem_ops);
|
||||
TEST(collapse_full, mthp_khugepaged_context, anon_ops);
|
||||
for (int i = 0; i < nr_collapse_orders; i++) {
|
||||
collapse_order = collapse_orders[i];
|
||||
TEST(collapse_full, mthp_khugepaged_context, anon_ops);
|
||||
TEST(collapse_empty, mthp_khugepaged_context, anon_ops);
|
||||
TEST(collapse_single_mthp, mthp_khugepaged_context, anon_ops);
|
||||
TEST(collapse_order_single_window, mthp_khugepaged_context, anon_ops);
|
||||
TEST(collapse_order_partial_window, mthp_khugepaged_context, anon_ops);
|
||||
TEST(collapse_order_max_ptes_none, mthp_khugepaged_context, anon_ops);
|
||||
TEST(collapse_order_mixed_sources, mthp_khugepaged_context, anon_ops);
|
||||
}
|
||||
|
||||
TEST(collapse_full, madvise_context, anon_ops);
|
||||
TEST(collapse_full, madvise_context, read_only_file_ops);
|
||||
TEST(collapse_full, madvise_context, read_write_file_read_ops);
|
||||
|
|
@ -1740,15 +1794,8 @@ int main(int argc, char **argv)
|
|||
TEST(collapse_full, madvise_context, shmem_ops);
|
||||
|
||||
TEST(collapse_empty, khugepaged_context, anon_ops);
|
||||
TEST(collapse_empty, mthp_khugepaged_context, anon_ops);
|
||||
TEST(collapse_empty, madvise_context, anon_ops);
|
||||
|
||||
TEST(collapse_single_mthp, mthp_khugepaged_context, anon_ops);
|
||||
TEST(collapse_order_single_window, mthp_khugepaged_context, anon_ops);
|
||||
TEST(collapse_order_partial_window, mthp_khugepaged_context, anon_ops);
|
||||
TEST(collapse_order_max_ptes_none, mthp_khugepaged_context, anon_ops);
|
||||
TEST(collapse_order_mixed_sources, mthp_khugepaged_context, anon_ops);
|
||||
|
||||
TEST(collapse_single_pte_entry, khugepaged_context, anon_ops);
|
||||
TEST(collapse_single_pte_entry, khugepaged_context, read_only_file_ops);
|
||||
TEST(collapse_single_pte_entry, khugepaged_context, read_write_file_read_ops);
|
||||
|
|
@ -1821,7 +1868,15 @@ int main(int argc, char **argv)
|
|||
for (int i = 0; i < nr_test_cases; i++) {
|
||||
struct test_case *t = &test_cases[i];
|
||||
|
||||
ksft_print_msg("\n# Run test: %s (%s:%s)\n", t->desc, t->ctx->name, t->ops->name);
|
||||
if (t->ctx == &__mthp_khugepaged_context) {
|
||||
collapse_order = t->order;
|
||||
ksft_print_msg("\n# Run test: %s (%s:%s, order %d)\n",
|
||||
t->desc, t->ctx->name, t->ops->name,
|
||||
t->order);
|
||||
} else {
|
||||
ksft_print_msg("\n# Run test: %s (%s:%s)\n", t->desc,
|
||||
t->ctx->name, t->ops->name);
|
||||
}
|
||||
t->fn(t->ctx, t->ops);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -392,8 +392,6 @@ CATEGORY="thp" run_test ./khugepaged all:shmem
|
|||
|
||||
CATEGORY="thp" run_test ./khugepaged -s 4 all:shmem
|
||||
|
||||
CATEGORY="thp" run_test ./khugepaged -c 4 mthp_khugepaged:anon
|
||||
|
||||
# Try to create XFS if not provided
|
||||
if [ -z "${SPLIT_HUGE_PAGE_TEST_XFS_PATH}" ]; then
|
||||
if test_selected "thp"; then
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user