Kernel commit 90bd6fd31c8097(ksm: allow trees per NUMA node)
introduced a new ksm sysfs knob /sys/kernel/mm/ksm/merge_across_nodes,
which makes NUMA awareness KSM.

The case is designed to check whether KSM can merge the same shared
pages distributed on different numa nodes.

Signed-off-by: Zhouping Liu <[email protected]>
---
 runtest/mm                         |   3 +
 testcases/kernel/mem/include/mem.h |   2 +
 testcases/kernel/mem/ksm/ksm06.c   | 136 +++++++++++++++++++++++++++++++++++++
 testcases/kernel/mem/lib/mem.c     |  77 ++++++++++++++++++++-
 4 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 testcases/kernel/mem/ksm/ksm06.c

diff --git a/runtest/mm b/runtest/mm
index 7c7abf1..a39becd 100644
--- a/runtest/mm
+++ b/runtest/mm
@@ -70,6 +70,9 @@ ksm03_1 ksm03 -u 128
 ksm04 ksm04
 ksm04_1 ksm04 -u 128
 ksm05 ksm05 -I 10
+ksm06 ksm06
+ksm06_1 ksm06 -n 10
+ksn06_2 ksm06 -n 10000
 
 cpuset01 cpuset01 -I 3600
 
diff --git a/testcases/kernel/mem/include/mem.h 
b/testcases/kernel/mem/include/mem.h
index e31783e..342166e 100644
--- a/testcases/kernel/mem/include/mem.h
+++ b/testcases/kernel/mem/include/mem.h
@@ -46,6 +46,8 @@ void testoom(int mempolicy, int lite);
 
 #define PATH_KSM               "/sys/kernel/mm/ksm/"
 
+void test_ksm_merge_across_nodes(unsigned long nr_pages);
+
 /* THP */
 
 #define PATH_THP               "/sys/kernel/mm/transparent_hugepage/"
diff --git a/testcases/kernel/mem/ksm/ksm06.c b/testcases/kernel/mem/ksm/ksm06.c
new file mode 100644
index 0000000..346a9b4
--- /dev/null
+++ b/testcases/kernel/mem/ksm/ksm06.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 Linux Test Project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it
+ * is free of the rightful claim of any third person regarding
+ * infringement or the like.  Any license provided herein, whether
+ * implied or otherwise, applies only to this software file.  Patent
+ * licenses, if any, provided herein do not apply to combinations of
+ * this program with other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/*
+ * The case is designed to test new sysfs boolean knob
+ * /sys/kernel/mm/ksm/merge_across_nodes, which was introduced by
+ * commit 90bd6fd31c8097ee (ksm: allow trees per NUMA node).
+ * when merge_across_nodes is set to zero only pages from the same
+ * node are merged, otherwise pages from all nodes can be merged
+ * together.
+ */
+
+#include "config.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <fcntl.h>
+#if HAVE_NUMAIF_H
+#include <numaif.h>
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "numa_helper.h"
+#include "test.h"
+#include "safe_macros.h"
+#include "usctest.h"
+#include "mem.h"
+
+char *TCID = "ksm06";
+int TST_TOTAL = 1;
+
+#if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
+       && HAVE_MPOL_CONSTANTS
+
+static int run;
+static int sleep_millisecs;
+static int merge_across_nodes;
+static int n_flag;
+static unsigned long nr_pages;
+
+static char *n_opt;
+option_t options[] = {
+       { "n:", &n_flag, &n_opt },
+       { NULL, NULL, NULL }
+};
+static void usage(void);
+
+int main(int argc, char *argv[])
+{
+       int lc;
+       char *msg;
+
+       msg = parse_opts(argc, argv, options, &usage);
+       if (msg != NULL)
+               tst_brkm(TBROK, NULL, "OPTION PASING ERROR - %s", msg);
+       if (n_flag)
+               nr_pages = SAFE_STRTOUL(NULL, n_opt, 0, ULONG_MAX);
+       else
+               nr_pages = 100;
+
+       setup();
+
+       for (lc = 0; TEST_LOOPING(lc); lc++) {
+               tst_count = 0;
+
+               test_ksm_merge_across_nodes(nr_pages);
+       }
+
+       cleanup();
+       tst_exit();
+}
+
+void setup(void)
+{
+       if (access(PATH_KSM "merge_across_nodes", F_OK) == -1)
+               tst_brkm(TCONF, NULL, "no merge_across_nodes sysfs knob");
+
+       if (!is_numa(NULL))
+               tst_brkm(TCONF, NULL, "The case need a NUMA system.");
+
+       /* save the current value */
+       SAFE_FILE_SCANF(NULL, PATH_KSM "run", "%d", &run);
+       SAFE_FILE_SCANF(NULL, PATH_KSM "merge_across_nodes",
+                       "%d", &merge_across_nodes);
+       SAFE_FILE_SCANF(NULL, PATH_KSM "sleep_millisecs",
+                       "%d", &sleep_millisecs);
+
+       tst_sig(FORK, DEF_HANDLER, cleanup);
+       TEST_PAUSE;
+}
+
+void cleanup(void)
+{
+       SAFE_FILE_PRINTF(NULL, PATH_KSM "merge_across_nodes",
+                        "%d", merge_across_nodes);
+       SAFE_FILE_PRINTF(NULL, PATH_KSM "sleep_millisecs",
+                        "%d", sleep_millisecs);
+       SAFE_FILE_PRINTF(NULL, PATH_KSM "run", "%d", run);
+
+       TEST_CLEANUP;
+}
+
+static void usage(void)
+{
+       printf("  -n x    Allocate x pages memory per node\n");
+}
+
+#else /* no NUMA */
+int main(void)
+{
+       tst_brkm(TCONF, NULL, "no NUMA development packages installed.");
+}
+#endif
diff --git a/testcases/kernel/mem/lib/mem.c b/testcases/kernel/mem/lib/mem.c
index 1232b4f..7cda3c5 100644
--- a/testcases/kernel/mem/lib/mem.c
+++ b/testcases/kernel/mem/lib/mem.c
@@ -96,7 +96,7 @@ static void set_global_mempolicy(int mempolicy)
 #if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
        && HAVE_MPOL_CONSTANTS
        unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 };
-       unsigned int num_nodes, *nodes;
+       int num_nodes, *nodes;
        int ret;
 
        if (mempolicy) {
@@ -467,6 +467,81 @@ void create_same_memory(int size, int num, int unit)
                                 WEXITSTATUS(status));
 }
 
+void test_ksm_merge_across_nodes(unsigned long nr_pages)
+{
+       char **memory;
+       int i, ret;
+       int num_nodes, *nodes;
+       unsigned long length;
+       unsigned long pagesize;
+       unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 };
+
+       ret = get_allowed_nodes_arr(NH_MEMS|NH_CPUS, &num_nodes, &nodes);
+       if (ret != 0)
+               tst_brkm(TBROK|TERRNO, cleanup, "get_allowed_nodes_arr");
+       if (num_nodes < 2) {
+               tst_resm(TINFO, "need NUMA system support");
+               free(nodes);
+               return;
+       }
+
+       pagesize = sysconf(_SC_PAGE_SIZE);
+       length = nr_pages * pagesize;
+
+       memory = (char **)malloc(num_nodes * sizeof(char *));
+       for (i = 0; i < num_nodes; i++) {
+               memory[i] = mmap(NULL, length, PROT_READ|PROT_WRITE,
+                           MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+               if (memory[i] == MAP_FAILED)
+                       tst_brkm(TBROK|TERRNO, tst_exit, "mmap");
+               if (madvise(memory[i], length, MADV_MERGEABLE) == -1)
+                       tst_brkm(TBROK|TERRNO, tst_exit, "madvise");
+
+#if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
+       && HAVE_MPOL_CONSTANTS
+               clean_node(nmask);
+               set_node(nmask, nodes[i]);
+               /*
+                * Use mbind() to make sure each node contains
+                * length size memory.
+                */
+               ret = mbind(memory[i], length, MPOL_BIND, nmask, MAXNODES, 0);
+               if (ret == -1)
+                       tst_brkm(TBROK|TERRNO, tst_exit, "mbind");
+#endif
+
+               memset(memory[i], 10, length);
+       }
+
+       SAFE_FILE_PRINTF(cleanup, PATH_KSM "sleep_millisecs", "0");
+       SAFE_FILE_PRINTF(cleanup, PATH_KSM "pages_to_scan", "%ld",
+                        nr_pages * num_nodes);
+       /*
+        * merge_across_nodes setting can be changed only when there
+        * are no ksm shared pages in system, so set run 2 to unmerge
+        * pages first, then to 1 after changing merge_across_nodes,
+        * to remerge according to the new setting.
+        */
+       SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "2");
+       wait_ksmd_done();
+       tst_resm(TINFO, "Start to test KSM with merge_across_nodes=1");
+       SAFE_FILE_PRINTF(cleanup, PATH_KSM "merge_across_nodes", "1");
+       SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "1");
+       group_check(1, 1, nr_pages * num_nodes - 1, 0, 0, 0,
+                   nr_pages * num_nodes);
+
+       SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "2");
+       wait_ksmd_done();
+       tst_resm(TINFO, "Start to test KSM with merge_across_nodes=0");
+       SAFE_FILE_PRINTF(cleanup, PATH_KSM "merge_across_nodes", "0");
+       SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "1");
+       group_check(1, num_nodes, nr_pages * num_nodes - num_nodes,
+                   0, 0, 0, nr_pages * num_nodes);
+
+       SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "2");
+       wait_ksmd_done();
+}
+
 void check_ksm_options(int *size, int *num, int *unit)
 {
        if (opt_size) {
-- 
1.7.11.7


------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and 
their applications. This 200-page book is written by three acclaimed 
leaders in the field. The early access version is available now. 
Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list

Reply via email to