[LTP] [PATCH] mempolicy/mbind: update syscall tests for weighted interleave

Gregory Price gourry.memverge@gmail.com
Fri Mar 29 19:07:42 CET 2024


Add the MPOL_WEIGHTED_INTERLEAVE policy to the syscall test suite for
get_mempolicy, set_mempolicy, and mbind.

The functional memory distribution test only tests that the default
behavior of WEIGHTED_INTERLEAVE is the same as INTERLEAVE, since the
values for each node default to '1', and because behavior actually
depends on what node the test runs on.  This test at least demonstrates
the interleave mechanism is in use and works by default as intended.

MPOL_WEIGHTED_INTERLEAVE is ifdef defined because it is not upstream
in libnuma yet, so this ensures compilation.

Signed-off-by: Gregory Price <gregory.price@memverge.com>
---
 .../syscalls/get_mempolicy/get_mempolicy01.c  |  15 ++
 testcases/kernel/syscalls/mbind/mbind01.c     |  17 ++
 testcases/kernel/syscalls/mbind/mbind02.c     |   5 +
 testcases/kernel/syscalls/mbind/mbind03.c     |   5 +
 testcases/kernel/syscalls/mbind/mbind04.c     |   5 +
 .../kernel/syscalls/set_mempolicy/.gitignore  |   2 +
 .../kernel/syscalls/set_mempolicy/Makefile    |   2 +-
 .../syscalls/set_mempolicy/set_mempolicy06.c  | 122 +++++++++++++++
 .../syscalls/set_mempolicy/set_mempolicy07.c  | 148 ++++++++++++++++++
 9 files changed, 320 insertions(+), 1 deletion(-)
 create mode 100644 testcases/kernel/syscalls/set_mempolicy/set_mempolicy06.c
 create mode 100644 testcases/kernel/syscalls/set_mempolicy/set_mempolicy07.c

diff --git a/testcases/kernel/syscalls/get_mempolicy/get_mempolicy01.c b/testcases/kernel/syscalls/get_mempolicy/get_mempolicy01.c
index 23f62091a..8b0aa60bf 100644
--- a/testcases/kernel/syscalls/get_mempolicy/get_mempolicy01.c
+++ b/testcases/kernel/syscalls/get_mempolicy/get_mempolicy01.c
@@ -26,6 +26,10 @@
 #include <errno.h>
 #include "tst_numa.h"
 
+#ifndef
+#define MPOL_WEIGHTED_INTERLEAVE 6
+#endif
+
 #define MEM_LENGTH	(4 * 1024 * 1024)
 #define PAGES_ALLOCATED 16u
 
@@ -68,6 +72,11 @@ static struct test_case tcase[] = {
 		.alloc = test_set_mempolicy_default,
 		.exp_nodemask = &nodemask,
 	},
+	{
+		POLICY_DESC(MPOL_WEIGHTED_INTERLEAVE),
+		.alloc = test_set_mempolicy_default,
+		.exp_nodemask = &nodemask,
+	},
 	{
 		POLICY_DESC_NO_TARGET(MPOL_PREFERRED),
 		.alloc = test_set_mempolicy_none,
@@ -95,6 +104,12 @@ static struct test_case tcase[] = {
 		.alloc = test_set_mempolicy_default,
 		.exp_nodemask = &nodemask,
 	},
+	{
+		POLICY_DESC_FLAGS(MPOL_WEIGHTED_INTERLEAVE, MPOL_F_ADDR),
+		.pre_test = test_mbind_default,
+		.alloc = test_set_mempolicy_default,
+		.exp_nodemask = &nodemask,
+	},
 	{
 		POLICY_DESC_FLAGS_NO_TARGET(MPOL_PREFERRED, MPOL_F_ADDR),
 		.pre_test = test_mbind_none,
diff --git a/testcases/kernel/syscalls/mbind/mbind01.c b/testcases/kernel/syscalls/mbind/mbind01.c
index 4b8d168cd..d3d3b0049 100644
--- a/testcases/kernel/syscalls/mbind/mbind01.c
+++ b/testcases/kernel/syscalls/mbind/mbind01.c
@@ -20,6 +20,10 @@
 #include "tst_numa.h"
 #include "lapi/numaif.h"
 
+#ifndef
+#define MPOL_WEIGHTED_INTERLEAVE 6
+#endif
+
 #ifdef HAVE_NUMA_V2
 
 #define MEM_LENGTH (4 * 1024 * 1024)
@@ -80,6 +84,12 @@ static struct test_case tcase[] = {
 		.err = EINVAL,
 		.test = test_none,
 	},
+	{
+		POLICY_DESC_TEXT(MPOL_WEIGHTED_INTERLEAVE, "no target"),
+		.ret = -1,
+		.err = EINVAL,
+		.test = test_none,
+	},
 	{
 		POLICY_DESC(MPOL_INTERLEAVE),
 		.ret = 0,
@@ -87,6 +97,13 @@ static struct test_case tcase[] = {
 		.test = test_default,
 		.exp_nodemask = &nodemask,
 	},
+	{
+		POLICY_DESC(MPOL_WEIGHTED_INTERLEAVE),
+		.ret = 0,
+		.err = 0,
+		.test = test_default,
+		.exp_nodemask = &nodemask,
+	},
 	{
 		POLICY_DESC_TEXT(MPOL_PREFERRED, "no target"),
 		.ret = 0,
diff --git a/testcases/kernel/syscalls/mbind/mbind02.c b/testcases/kernel/syscalls/mbind/mbind02.c
index cd6a03226..66d9cd826 100644
--- a/testcases/kernel/syscalls/mbind/mbind02.c
+++ b/testcases/kernel/syscalls/mbind/mbind02.c
@@ -23,6 +23,10 @@
 #include "tst_test.h"
 #include "tst_numa.h"
 
+#ifndef MPOL_WEIGHTED_INTERLEAVE
+#define MPOL_WEIGHTED_INTERLEAVE 6
+#endif
+
 #ifdef HAVE_NUMA_V2
 
 static size_t page_size;
@@ -92,6 +96,7 @@ static const int modes[] = {
 	MPOL_PREFERRED,
 	MPOL_BIND,
 	MPOL_INTERLEAVE,
+	MPOL_WEIGHTED_INTERLEAVE,
 };
 
 static void verify_mbind(unsigned int n)
diff --git a/testcases/kernel/syscalls/mbind/mbind03.c b/testcases/kernel/syscalls/mbind/mbind03.c
index 3d477c9cb..7da3c217d 100644
--- a/testcases/kernel/syscalls/mbind/mbind03.c
+++ b/testcases/kernel/syscalls/mbind/mbind03.c
@@ -20,6 +20,10 @@
 #include "tst_test.h"
 #include "tst_numa.h"
 
+#ifndef MPOL_WEIGHTED_INTERLEAVE
+#define MPOL_WEIGHTED_INTERLEAVE 6
+#endif
+
 #ifdef HAVE_NUMA_V2
 
 static size_t page_size;
@@ -103,6 +107,7 @@ static const int modes[] = {
 	MPOL_PREFERRED,
 	MPOL_BIND,
 	MPOL_INTERLEAVE,
+	MPOL_WEIGHTED_INTERLEAVE,
 };
 
 static void verify_mbind(unsigned int n)
diff --git a/testcases/kernel/syscalls/mbind/mbind04.c b/testcases/kernel/syscalls/mbind/mbind04.c
index 50028835f..db41f9e29 100644
--- a/testcases/kernel/syscalls/mbind/mbind04.c
+++ b/testcases/kernel/syscalls/mbind/mbind04.c
@@ -20,6 +20,10 @@
 #include "tst_test.h"
 #include "tst_numa.h"
 
+#ifndef MPOL_WEIGHTED_INTERLEAVE
+#define MPOL_WEIGHTED_INTERLEAVE 6
+#endif
+
 #ifdef HAVE_NUMA_V2
 
 static size_t page_size;
@@ -114,6 +118,7 @@ static const int modes[] = {
 	MPOL_PREFERRED,
 	MPOL_BIND,
 	MPOL_INTERLEAVE,
+	MPOL_WEIGHTED_INTERLEAVE,
 };
 
 static void verify_mbind(unsigned int n)
diff --git a/testcases/kernel/syscalls/set_mempolicy/.gitignore b/testcases/kernel/syscalls/set_mempolicy/.gitignore
index 4c121d2e0..3af10e9f9 100644
--- a/testcases/kernel/syscalls/set_mempolicy/.gitignore
+++ b/testcases/kernel/syscalls/set_mempolicy/.gitignore
@@ -3,3 +3,5 @@
 /set_mempolicy03
 /set_mempolicy04
 /set_mempolicy05
+/set_mempolicy06
+/set_mempolicy07
diff --git a/testcases/kernel/syscalls/set_mempolicy/Makefile b/testcases/kernel/syscalls/set_mempolicy/Makefile
index 100780dc3..04208837d 100644
--- a/testcases/kernel/syscalls/set_mempolicy/Makefile
+++ b/testcases/kernel/syscalls/set_mempolicy/Makefile
@@ -5,7 +5,7 @@ LTPLIBS = ltpnuma
 
 include $(top_srcdir)/include/mk/testcases.mk
 
-NEEDS_LIBS = set_mempolicy01 set_mempolicy02 set_mempolicy03 set_mempolicy04
+NEEDS_LIBS = set_mempolicy01 set_mempolicy02 set_mempolicy03 set_mempolicy04 set_mempolicy05 set_mempolicy06 set_mempolicy07
 
 $(NEEDS_LIBS): LDLIBS  += $(NUMA_LIBS)
 $(NEEDS_LIBS): LTPLDLIBS = -lltpnuma
diff --git a/testcases/kernel/syscalls/set_mempolicy/set_mempolicy06.c b/testcases/kernel/syscalls/set_mempolicy/set_mempolicy06.c
new file mode 100644
index 000000000..287fd316a
--- /dev/null
+++ b/testcases/kernel/syscalls/set_mempolicy/set_mempolicy06.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+/*
+ * We are testing set_mempolicy() with MPOL_WEIGHTED_INTERLEAVE.
+ *
+ * The test tries different subsets of memory nodes, sets the mask with
+ * memopolicy, and checks that the memory was interleaved between the nodes
+ * accordingly.
+ */
+
+#include <errno.h>
+#include "config.h"
+#ifdef HAVE_NUMA_V2
+# include <numa.h>
+# include <numaif.h>
+#endif
+#include "tst_test.h"
+#include "tst_numa.h"
+
+#ifdef HAVE_NUMA_V2
+
+#include "set_mempolicy.h"
+
+#ifndef MPOL_WEIGHTED_INTERLEAVE
+#define MPOL_WEIGHTED_INTERLEAVE 6
+#endif
+
+#define ALLOC_ON_NODE 8
+
+static size_t page_size;
+static struct tst_nodemap *nodes;
+
+static void setup(void)
+{
+	page_size = getpagesize();
+
+	nodes = tst_get_nodemap(TST_NUMA_MEM, 2 * ALLOC_ON_NODE * page_size / 1024);
+	if (nodes->cnt <= 1)
+		tst_brk(TCONF, "Test requires at least two NUMA memory nodes");
+}
+
+static void cleanup(void)
+{
+	tst_nodemap_free(nodes);
+}
+
+static void alloc_and_check(size_t size, unsigned int *exp_alloc)
+{
+	unsigned int i;
+	const char *prefix = "child: ";
+
+	if (SAFE_FORK()) {
+		prefix = "parent: ";
+		tst_reap_children();
+	}
+
+	tst_nodemap_reset_counters(nodes);
+	alloc_fault_count(nodes, NULL, size * page_size);
+
+	for (i = 0; i < nodes->cnt; i++) {
+		if (nodes->counters[i] == exp_alloc[i]) {
+			tst_res(TPASS, "%sNode %u allocated %u",
+					prefix, nodes->map[i], exp_alloc[i]);
+		} else {
+			tst_res(TFAIL, "%sNode %u allocated %u, expected %u",
+					prefix, nodes->map[i], nodes->counters[i],
+					exp_alloc[i]);
+		}
+	}
+}
+
+static void verify_set_mempolicy(unsigned int n)
+{
+	struct bitmask *bm = numa_allocate_nodemask();
+	unsigned int exp_alloc[nodes->cnt];
+	unsigned int alloc_per_node = n ? ALLOC_ON_NODE : 2;
+	unsigned int alloc_on_nodes = n ? 2 : nodes->cnt;
+	unsigned int alloc_total = alloc_per_node * alloc_on_nodes;
+	unsigned int i;
+
+	memset(exp_alloc, 0, sizeof(exp_alloc));
+
+	for (i = 0; i < alloc_on_nodes; i++) {
+		exp_alloc[i] = alloc_per_node;
+		numa_bitmask_setbit(bm, nodes->map[i]);
+	}
+
+	TEST(set_mempolicy(MPOL_WEIGHTED_INTERLEAVE, bm->maskp, bm->size+1));
+
+	tst_res(TINFO, "Allocating on nodes 1-%u - %u pages",
+			alloc_on_nodes, alloc_total);
+
+	if (TST_RET) {
+		tst_res(TFAIL | TTERRNO,
+				"set_mempolicy(MPOL_WEIGHTED_INTERLEAVE)");
+		return;
+	}
+
+	tst_res(TPASS, "set_mempolicy(MPOL_WEIGHTED_INTERLEAVE)");
+
+	numa_free_nodemask(bm);
+
+	alloc_and_check(alloc_total, exp_alloc);
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.cleanup = cleanup,
+	.test = verify_set_mempolicy,
+	.tcnt = 2,
+	.forks_child = 1,
+	.needs_checkpoints = 1,
+};
+
+#else
+
+TST_TEST_TCONF(NUMA_ERROR_MSG);
+
+#endif /* HAVE_NUMA_V2 */
diff --git a/testcases/kernel/syscalls/set_mempolicy/set_mempolicy07.c b/testcases/kernel/syscalls/set_mempolicy/set_mempolicy07.c
new file mode 100644
index 000000000..d88998ed5
--- /dev/null
+++ b/testcases/kernel/syscalls/set_mempolicy/set_mempolicy07.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+/*
+ * We are testing set_mempolicy() with MPOL_WEIGHTED_INTERLEAVE on mmaped buffers
+ * backed by files.
+ *
+ * Apparently it takes a larger sample for the allocations to be correctly
+ * interleaved. The reason for this is that buffers for file metadata are
+ * allocated in batches in order not to loose performance. Also the pages
+ * cannot be interleaved completely evenly unless the number of pages is
+ * divideable by the number of nodes, which will not happen even if we tried
+ * hard since we do not have control over metadata blocks for instance. Hence
+ * we cannot really expect to allocate a single file and have the memory
+ * interleaved precisely but it works well if we allocate statistic for a more
+ * than a few files.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include "config.h"
+#ifdef HAVE_NUMA_V2
+# include <numa.h>
+# include <numaif.h>
+#endif
+#include "tst_test.h"
+#include "tst_numa.h"
+
+#define MNTPOINT "mntpoint"
+#define FILES 10
+
+#ifdef HAVE_NUMA_V2
+
+#ifndef MPOL_WEIGHTED_INTERLEAVE
+#define MPOL_WEIGHTED_INTERLEAVE 6
+#endif
+
+#include "set_mempolicy.h"
+
+static size_t page_size;
+static struct tst_nodemap *nodes;
+
+static void setup(void)
+{
+	int node_min_pages = FILES * (FILES + 1) / 2 * 10 + FILES * 10;
+
+	page_size = getpagesize();
+
+	nodes = tst_get_nodemap(TST_NUMA_MEM, node_min_pages * page_size / 1024);
+	if (nodes->cnt <= 1)
+		tst_brk(TCONF, "Test requires at least two NUMA memory nodes");
+}
+
+static void cleanup(void)
+{
+	tst_nodemap_free(nodes);
+}
+
+static void alloc_and_check(void)
+{
+	unsigned int i, j;
+	char path[1024];
+	unsigned int total_pages = 0;
+	unsigned int sum_pages = 0;
+
+	tst_nodemap_reset_counters(nodes);
+
+	/*
+	 * The inner loop loops node->cnt times to ensure the sum could
+	 * be evenly distributed among the nodes.
+	 */
+	for (i = 1; i <= FILES; i++) {
+		for (j = 1; j <= nodes->cnt; j++) {
+			size_t size = 10 * i + j % 10;
+
+			snprintf(path, sizeof(path), MNTPOINT "/numa-test-file-%i-%i", i, j);
+			alloc_fault_count(nodes, path, size * page_size);
+			total_pages += size;
+		}
+	}
+
+	for (i = 0; i < nodes->cnt; i++) {
+		float threshold = 1.00 * total_pages / 60; /* five percents */
+		float min_pages = 1.00 * total_pages / nodes->cnt - threshold;
+		float max_pages = 1.00 * total_pages / nodes->cnt + threshold;
+
+		if (nodes->counters[i] > min_pages && nodes->counters[i] < max_pages) {
+			tst_res(TPASS, "Node %u allocated %u <%.2f,%.2f>",
+					nodes->map[i], nodes->counters[i], min_pages, max_pages);
+		} else {
+			tst_res(TFAIL, "Node %u allocated %u, expected <%.2f,%.2f>",
+					nodes->map[i], nodes->counters[i], min_pages, max_pages);
+		}
+
+		sum_pages += nodes->counters[i];
+	}
+
+	if (sum_pages != total_pages) {
+		tst_res(TFAIL, "Sum of nodes %u != allocated pages %u",
+				sum_pages, total_pages);
+		return;
+	}
+
+	tst_res(TPASS, "Sum of nodes equals to allocated pages (%u)", total_pages);
+}
+
+static void verify_set_mempolicy(void)
+{
+	struct bitmask *bm = numa_allocate_nodemask();
+	unsigned int alloc_on_nodes = nodes->cnt;
+	unsigned int i;
+
+	for (i = 0; i < alloc_on_nodes; i++)
+		numa_bitmask_setbit(bm, nodes->map[i]);
+
+	TEST(set_mempolicy(MPOL_WEIGHTED_INTERLEAVE, bm->maskp, bm->size+1));
+
+	if (TST_RET) {
+		tst_res(TFAIL | TTERRNO,
+				"set_mempolicy(MPOL_WEIGHTED_INTERLEAVE)");
+		return;
+	}
+
+	tst_res(TPASS, "set_mempolicy(MPOL_WEIGHTED_INTERLEAVE)");
+
+	alloc_and_check();
+
+	numa_free_nodemask(bm);
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.cleanup = cleanup,
+	.test_all = verify_set_mempolicy,
+	.forks_child = 1,
+	.needs_root = 1,
+	.all_filesystems = 1,
+	.mntpoint = MNTPOINT,
+	.needs_checkpoints = 1,
+};
+
+#else
+
+TST_TEST_TCONF(NUMA_ERROR_MSG);
+
+#endif /* HAVE_NUMA_V2 */
-- 
2.39.1



More information about the ltp mailing list