From: Stefan Roesch <shr@devkernel.io>
To: kernel-team@fb.com
Cc: shr@devkernel.io, linux-mm@kvack.org, riel@surriel.com,
mhocko@suse.com, david@redhat.com,
linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org,
akpm@linux-foundation.org
Subject: [RFC PATCH v2 16/19] selftests/vm: add KSM prctl merge test
Date: Fri, 10 Feb 2023 13:50:20 -0800 [thread overview]
Message-ID: <20230210215023.2740545-17-shr@devkernel.io> (raw)
In-Reply-To: <20230210215023.2740545-1-shr@devkernel.io>
This adds the -t option to the ksm_tests program. The -t flag allows to
specify if it should use madvise or prctl ksm merging.
Signed-off-by: Stefan Roesch <shr@devkernel.io>
---
tools/testing/selftests/mm/Makefile | 3 +-
tools/testing/selftests/mm/ksm_tests.c | 116 +++++++++++++++++--------
2 files changed, 80 insertions(+), 39 deletions(-)
diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile
index d90cdc06aa59..507cb22bdebd 100644
--- a/tools/testing/selftests/mm/Makefile
+++ b/tools/testing/selftests/mm/Makefile
@@ -29,7 +29,8 @@ MACHINE ?= $(shell echo $(uname_M) | sed -e 's/aarch64.*/arm64/' -e 's/ppc64.*/p
# LDLIBS.
MAKEFLAGS += --no-builtin-rules
-CFLAGS = -Wall -I $(top_srcdir) -I $(top_srcdir)/usr/include $(EXTRA_CFLAGS) $(KHDR_INCLUDES)
+CFLAGS = -Wall -I $(top_srcdir)/tools/include/uapi
+CFLAGS += -I $(top_srcdir) -I $(top_srcdir)/usr/include $(EXTRA_CFLAGS) $(KHDR_INCLUDES)
LDLIBS = -lrt -lpthread
TEST_GEN_FILES = cow
TEST_GEN_FILES += compaction_test
diff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c
index f9eb4d67e0dd..386a0929c8a3 100644
--- a/tools/testing/selftests/mm/ksm_tests.c
+++ b/tools/testing/selftests/mm/ksm_tests.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
@@ -21,6 +23,7 @@
#define KSM_PROT_STR_DEFAULT "rw"
#define KSM_USE_ZERO_PAGES_DEFAULT false
#define KSM_MERGE_ACROSS_NODES_DEFAULT true
+#define KSM_MERGE_TYPE_DEFAULT 0
#define MB (1ul << 20)
struct ksm_sysfs {
@@ -33,6 +36,12 @@ struct ksm_sysfs {
unsigned long use_zero_pages;
};
+enum ksm_merge_type {
+ KSM_MERGE_MADVISE,
+ KSM_MERGE_PRCTL,
+ KSM_MERGE_LAST = KSM_MERGE_PRCTL
+};
+
enum ksm_test_name {
CHECK_KSM_MERGE,
CHECK_KSM_UNMERGE,
@@ -129,6 +138,10 @@ static void print_help(void)
printf(" -m: change merge_across_nodes tunable\n"
" Default: %d\n", KSM_MERGE_ACROSS_NODES_DEFAULT);
printf(" -s: the size of duplicated memory area (in MiB)\n");
+ printf(" -t: KSM merge type\n"
+ " Default: 0\n"
+ " 0: madvise merging\n"
+ " 1: prctl merging\n");
exit(0);
}
@@ -176,12 +189,21 @@ static int ksm_do_scan(int scan_count, struct timespec start_time, int timeout)
return 0;
}
-static int ksm_merge_pages(void *addr, size_t size, struct timespec start_time, int timeout)
+static int ksm_merge_pages(int merge_type, void *addr, size_t size,
+ struct timespec start_time, int timeout)
{
- if (madvise(addr, size, MADV_MERGEABLE)) {
- perror("madvise");
- return 1;
+ if (merge_type == KSM_MERGE_MADVISE) {
+ if (madvise(addr, size, MADV_MERGEABLE)) {
+ perror("madvise");
+ return 1;
+ }
+ } else if (merge_type == KSM_MERGE_PRCTL) {
+ if (prctl(PR_SET_MEMORY_MERGE, 1)) {
+ perror("prctl");
+ return 1;
+ }
}
+
if (ksm_write_sysfs(KSM_FP("run"), 1))
return 1;
@@ -266,7 +288,8 @@ static int ksm_restore(struct ksm_sysfs *ksm_sysfs)
return 0;
}
-static int check_ksm_merge(int mapping, int prot, long page_count, int timeout, size_t page_size)
+static int check_ksm_merge(int merge_type, int mapping, int prot,
+ long page_count, int timeout, size_t page_size)
{
void *map_ptr;
struct timespec start_time;
@@ -281,13 +304,16 @@ static int check_ksm_merge(int mapping, int prot, long page_count, int timeout,
if (!map_ptr)
return KSFT_FAIL;
- if (ksm_merge_pages(map_ptr, page_size * page_count, start_time, timeout))
+ if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout))
goto err_out;
/* verify that the right number of pages are merged */
if (assert_ksm_pages_count(page_count)) {
printf("OK\n");
- munmap(map_ptr, page_size * page_count);
+ if (merge_type == KSM_MERGE_MADVISE)
+ munmap(map_ptr, page_size * page_count);
+ else if (merge_type == KSM_MERGE_PRCTL)
+ prctl(PR_SET_MEMORY_MERGE, 0);
return KSFT_PASS;
}
@@ -297,7 +323,7 @@ static int check_ksm_merge(int mapping, int prot, long page_count, int timeout,
return KSFT_FAIL;
}
-static int check_ksm_unmerge(int mapping, int prot, int timeout, size_t page_size)
+static int check_ksm_unmerge(int merge_type, int mapping, int prot, int timeout, size_t page_size)
{
void *map_ptr;
struct timespec start_time;
@@ -313,7 +339,7 @@ static int check_ksm_unmerge(int mapping, int prot, int timeout, size_t page_siz
if (!map_ptr)
return KSFT_FAIL;
- if (ksm_merge_pages(map_ptr, page_size * page_count, start_time, timeout))
+ if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout))
goto err_out;
/* change 1 byte in each of the 2 pages -- KSM must automatically unmerge them */
@@ -337,8 +363,8 @@ static int check_ksm_unmerge(int mapping, int prot, int timeout, size_t page_siz
return KSFT_FAIL;
}
-static int check_ksm_zero_page_merge(int mapping, int prot, long page_count, int timeout,
- bool use_zero_pages, size_t page_size)
+static int check_ksm_zero_page_merge(int merge_type, int mapping, int prot, long page_count,
+ int timeout, bool use_zero_pages, size_t page_size)
{
void *map_ptr;
struct timespec start_time;
@@ -356,7 +382,7 @@ static int check_ksm_zero_page_merge(int mapping, int prot, long page_count, int
if (!map_ptr)
return KSFT_FAIL;
- if (ksm_merge_pages(map_ptr, page_size * page_count, start_time, timeout))
+ if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout))
goto err_out;
/*
@@ -402,8 +428,8 @@ static int get_first_mem_node(void)
return get_next_mem_node(numa_max_node());
}
-static int check_ksm_numa_merge(int mapping, int prot, int timeout, bool merge_across_nodes,
- size_t page_size)
+static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeout,
+ bool merge_across_nodes, size_t page_size)
{
void *numa1_map_ptr, *numa2_map_ptr;
struct timespec start_time;
@@ -439,8 +465,8 @@ static int check_ksm_numa_merge(int mapping, int prot, int timeout, bool merge_a
memset(numa2_map_ptr, '*', page_size);
/* try to merge the pages */
- if (ksm_merge_pages(numa1_map_ptr, page_size, start_time, timeout) ||
- ksm_merge_pages(numa2_map_ptr, page_size, start_time, timeout))
+ if (ksm_merge_pages(merge_type, numa1_map_ptr, page_size, start_time, timeout) ||
+ ksm_merge_pages(merge_type, numa2_map_ptr, page_size, start_time, timeout))
goto err_out;
/*
@@ -466,7 +492,8 @@ static int check_ksm_numa_merge(int mapping, int prot, int timeout, bool merge_a
return KSFT_FAIL;
}
-static int ksm_merge_hugepages_time(int mapping, int prot, int timeout, size_t map_size)
+static int ksm_merge_hugepages_time(int merge_type, int mapping, int prot,
+ int timeout, size_t map_size)
{
void *map_ptr, *map_ptr_orig;
struct timespec start_time, end_time;
@@ -508,7 +535,7 @@ static int ksm_merge_hugepages_time(int mapping, int prot, int timeout, size_t m
perror("clock_gettime");
goto err_out;
}
- if (ksm_merge_pages(map_ptr, map_size, start_time, timeout))
+ if (ksm_merge_pages(merge_type, map_ptr, map_size, start_time, timeout))
goto err_out;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &end_time)) {
perror("clock_gettime");
@@ -533,7 +560,7 @@ static int ksm_merge_hugepages_time(int mapping, int prot, int timeout, size_t m
return KSFT_FAIL;
}
-static int ksm_merge_time(int mapping, int prot, int timeout, size_t map_size)
+static int ksm_merge_time(int merge_type, int mapping, int prot, int timeout, size_t map_size)
{
void *map_ptr;
struct timespec start_time, end_time;
@@ -549,7 +576,7 @@ static int ksm_merge_time(int mapping, int prot, int timeout, size_t map_size)
perror("clock_gettime");
goto err_out;
}
- if (ksm_merge_pages(map_ptr, map_size, start_time, timeout))
+ if (ksm_merge_pages(merge_type, map_ptr, map_size, start_time, timeout))
goto err_out;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &end_time)) {
perror("clock_gettime");
@@ -574,7 +601,7 @@ static int ksm_merge_time(int mapping, int prot, int timeout, size_t map_size)
return KSFT_FAIL;
}
-static int ksm_unmerge_time(int mapping, int prot, int timeout, size_t map_size)
+static int ksm_unmerge_time(int merge_type, int mapping, int prot, int timeout, size_t map_size)
{
void *map_ptr;
struct timespec start_time, end_time;
@@ -589,7 +616,7 @@ static int ksm_unmerge_time(int mapping, int prot, int timeout, size_t map_size)
perror("clock_gettime");
goto err_out;
}
- if (ksm_merge_pages(map_ptr, map_size, start_time, timeout))
+ if (ksm_merge_pages(merge_type, map_ptr, map_size, start_time, timeout))
goto err_out;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
@@ -621,7 +648,7 @@ static int ksm_unmerge_time(int mapping, int prot, int timeout, size_t map_size)
return KSFT_FAIL;
}
-static int ksm_cow_time(int mapping, int prot, int timeout, size_t page_size)
+static int ksm_cow_time(int merge_type, int mapping, int prot, int timeout, size_t page_size)
{
void *map_ptr;
struct timespec start_time, end_time;
@@ -660,7 +687,7 @@ static int ksm_cow_time(int mapping, int prot, int timeout, size_t page_size)
memset(map_ptr + page_size * i, '+', i / 2 + 1);
memset(map_ptr + page_size * (i + 1), '+', i / 2 + 1);
}
- if (ksm_merge_pages(map_ptr, page_size * page_count, start_time, timeout))
+ if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout))
goto err_out;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
@@ -697,6 +724,7 @@ int main(int argc, char *argv[])
int ret, opt;
int prot = 0;
int ksm_scan_limit_sec = KSM_SCAN_LIMIT_SEC_DEFAULT;
+ int merge_type = KSM_MERGE_TYPE_DEFAULT;
long page_count = KSM_PAGE_COUNT_DEFAULT;
size_t page_size = sysconf(_SC_PAGESIZE);
struct ksm_sysfs ksm_sysfs_old;
@@ -705,7 +733,7 @@ int main(int argc, char *argv[])
bool merge_across_nodes = KSM_MERGE_ACROSS_NODES_DEFAULT;
long size_MB = 0;
- while ((opt = getopt(argc, argv, "ha:p:l:z:m:s:MUZNPCHD")) != -1) {
+ while ((opt = getopt(argc, argv, "ha:p:l:z:m:s:t:MUZNPCHD")) != -1) {
switch (opt) {
case 'a':
prot = str_to_prot(optarg);
@@ -745,6 +773,17 @@ int main(int argc, char *argv[])
printf("Size must be greater than 0\n");
return KSFT_FAIL;
}
+ case 't':
+ {
+ int tmp = atoi(optarg);
+
+ if (tmp < 0 || tmp > KSM_MERGE_LAST) {
+ printf("Invalid merge type\n");
+ return KSFT_FAIL;
+ }
+ merge_type = atoi(optarg);
+ }
+ break;
case 'M':
break;
case 'U':
@@ -795,35 +834,36 @@ int main(int argc, char *argv[])
switch (test_name) {
case CHECK_KSM_MERGE:
- ret = check_ksm_merge(MAP_PRIVATE | MAP_ANONYMOUS, prot, page_count,
+ ret = check_ksm_merge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot, page_count,
ksm_scan_limit_sec, page_size);
break;
case CHECK_KSM_UNMERGE:
- ret = check_ksm_unmerge(MAP_PRIVATE | MAP_ANONYMOUS, prot, ksm_scan_limit_sec,
- page_size);
+ ret = check_ksm_unmerge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
+ ksm_scan_limit_sec, page_size);
break;
case CHECK_KSM_ZERO_PAGE_MERGE:
- ret = check_ksm_zero_page_merge(MAP_PRIVATE | MAP_ANONYMOUS, prot, page_count,
- ksm_scan_limit_sec, use_zero_pages, page_size);
+ ret = check_ksm_zero_page_merge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
+ page_count, ksm_scan_limit_sec, use_zero_pages,
+ page_size);
break;
case CHECK_KSM_NUMA_MERGE:
- ret = check_ksm_numa_merge(MAP_PRIVATE | MAP_ANONYMOUS, prot, ksm_scan_limit_sec,
- merge_across_nodes, page_size);
+ ret = check_ksm_numa_merge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
+ ksm_scan_limit_sec, merge_across_nodes, page_size);
break;
case KSM_MERGE_TIME:
if (size_MB == 0) {
printf("Option '-s' is required.\n");
return KSFT_FAIL;
}
- ret = ksm_merge_time(MAP_PRIVATE | MAP_ANONYMOUS, prot, ksm_scan_limit_sec,
- size_MB);
+ ret = ksm_merge_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
+ ksm_scan_limit_sec, size_MB);
break;
case KSM_MERGE_TIME_HUGE_PAGES:
if (size_MB == 0) {
printf("Option '-s' is required.\n");
return KSFT_FAIL;
}
- ret = ksm_merge_hugepages_time(MAP_PRIVATE | MAP_ANONYMOUS, prot,
+ ret = ksm_merge_hugepages_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
ksm_scan_limit_sec, size_MB);
break;
case KSM_UNMERGE_TIME:
@@ -831,12 +871,12 @@ int main(int argc, char *argv[])
printf("Option '-s' is required.\n");
return KSFT_FAIL;
}
- ret = ksm_unmerge_time(MAP_PRIVATE | MAP_ANONYMOUS, prot,
+ ret = ksm_unmerge_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
ksm_scan_limit_sec, size_MB);
break;
case KSM_COW_TIME:
- ret = ksm_cow_time(MAP_PRIVATE | MAP_ANONYMOUS, prot, ksm_scan_limit_sec,
- page_size);
+ ret = ksm_cow_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
+ ksm_scan_limit_sec, page_size);
break;
}
--
2.30.2
next prev parent reply other threads:[~2023-02-10 22:04 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-02-10 21:50 [RFC PATCH v2 00/19] mm: process/cgroup ksm support Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 01/19] mm: add new flag to enable ksm per process Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 02/19] mm: add flag to __ksm_enter Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 03/19] mm: add flag to __ksm_exit call Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 04/19] mm: invoke madvise for all vmas in scan_get_next_rmap_item Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 05/19] mm: support disabling of ksm for a process Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 06/19] mm: add new prctl option to get and set " Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 07/19] mm: split off pages_volatile function Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 08/19] mm: expose general_profit metric Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 09/19] docs: document general_profit sysfs knob Stefan Roesch
2023-02-11 8:17 ` Bagas Sanjaya
2023-02-15 23:00 ` Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 10/19] mm: calculate ksm process profit metric Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 11/19] mm: add ksm_merge_type() function Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 12/19] mm: expose ksm process profit metric in ksm_stat Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 13/19] mm: expose ksm merge type " Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 14/19] docs: document new procfs ksm knobs Stefan Roesch
2023-02-11 8:18 ` Bagas Sanjaya
2023-02-10 21:50 ` [RFC PATCH v2 15/19] tools: add new prctl flags to prctl in tools dir Stefan Roesch
2023-02-10 21:50 ` Stefan Roesch [this message]
2023-02-10 21:50 ` [RFC PATCH v2 17/19] selftests/vm: add KSM get merge type test Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 18/19] selftests/vm: add KSM fork test Stefan Roesch
2023-02-10 21:50 ` [RFC PATCH v2 19/19] selftests/vm: add two functions for debugging merge outcome Stefan Roesch
2023-02-10 23:23 ` [RFC PATCH v2 00/19] mm: process/cgroup ksm support Matthew Wilcox
2023-02-11 2:41 ` Rik van Riel
2023-02-21 16:10 ` Johannes Weiner
2023-02-21 17:59 ` Stefan Roesch
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230210215023.2740545-17-shr@devkernel.io \
--to=shr@devkernel.io \
--cc=akpm@linux-foundation.org \
--cc=david@redhat.com \
--cc=kernel-team@fb.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mhocko@suse.com \
--cc=riel@surriel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.