Home | History | Annotate | Download | only in ksm
      1 /*
      2  * Kernel Samepage Merging (KSM) for Memory Resource Controller and NUMA
      3  *
      4  * Basic tests were to start several programs with same and different
      5  * memory contents and ensure only to merge the ones with the same
      6  * contents. When changed the content of one of merged pages in a
      7  * process and to the mode "unmerging", it should discard all merged
      8  * pages there. Also tested it is possible to disable KSM. There are
      9  * also command-line options to specify the memory allocation size, and
     10  * number of processes have same memory contents so it is possible to
     11  * test more advanced things like KSM + OOM etc.
     12  *
     13  * Prerequisites:
     14  *
     15  * 1) ksm and ksmtuned daemons need to be disabled. Otherwise, it could
     16  *    distrub the testing as they also change some ksm tunables depends
     17  *    on current workloads.
     18  *
     19  * The test steps are:
     20  * - Check ksm feature and backup current run setting.
     21  * - Change run setting to 1 - merging.
     22  * - 3 memory allocation programs have the memory contents that 2 of
     23  *   them are all 'a' and one is all 'b'.
     24  * - Check ksm statistics and verify the content.
     25  * - 1 program changes the memory content from all 'a' to all 'b'.
     26  * - Check ksm statistics and verify the content.
     27  * - All programs change the memory content to all 'd'.
     28  * - Check ksm statistics and verify the content.
     29  * - Change one page of a process.
     30  * - Check ksm statistics and verify the content.
     31  * - Change run setting to 2 - unmerging.
     32  * - Check ksm statistics and verify the content.
     33  * - Change run setting to 0 - stop.
     34  *
     35  * Copyright (C) 2010  Red Hat, Inc.
     36  *
     37  * This program is free software; you can redistribute it and/or
     38  * modify it under the terms of version 2 of the GNU General Public
     39  * License as published by the Free Software Foundation.
     40  *
     41  * This program is distributed in the hope that it would be useful,
     42  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     44  *
     45  * Further, this software is distributed without any warranty that it
     46  * is free of the rightful claim of any third person regarding
     47  * infringement or the like.  Any license provided herein, whether
     48  * implied or otherwise, applies only to this software file.  Patent
     49  * licenses, if any, provided herein do not apply to combinations of
     50  * this program with other software, or any other product whatsoever.
     51  *
     52  * You should have received a copy of the GNU General Public License
     53  * along with this program; if not, write the Free Software
     54  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     55  * 02110-1301, USA.
     56  */
     57 
     58 #include "config.h"
     59 #include <sys/types.h>
     60 #include <sys/stat.h>
     61 #include <errno.h>
     62 #include <fcntl.h>
     63 #if HAVE_NUMAIF_H
     64 #include <numaif.h>
     65 #endif
     66 #include <signal.h>
     67 #include <stdio.h>
     68 #include <unistd.h>
     69 #include "test.h"
     70 #include "mem.h"
     71 
     72 char *TCID = "ksm04";
     73 int TST_TOTAL = 1;
     74 
     75 static int merge_across_nodes;
     76 
     77 #if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
     78 	&& HAVE_MPOL_CONSTANTS
     79 option_t ksm_options[] = {
     80 	{"n:", &opt_num, &opt_numstr},
     81 	{"s:", &opt_size, &opt_sizestr},
     82 	{"u:", &opt_unit, &opt_unitstr},
     83 	{NULL, NULL, NULL}
     84 };
     85 
     86 int main(int argc, char *argv[])
     87 {
     88 	int lc;
     89 	int size = 128, num = 3, unit = 1;
     90 	unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 };
     91 	unsigned int node;
     92 
     93 	tst_parse_opts(argc, argv, ksm_options, ksm_usage);
     94 
     95 	node = get_a_numa_node(tst_exit);
     96 	set_node(nmask, node);
     97 
     98 	setup();
     99 
    100 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    101 		tst_count = 0;
    102 		check_ksm_options(&size, &num, &unit);
    103 
    104 		write_memcg();
    105 
    106 		if (set_mempolicy(MPOL_BIND, nmask, MAXNODES) == -1) {
    107 			if (errno != ENOSYS)
    108 				tst_brkm(TBROK | TERRNO, cleanup,
    109 					 "set_mempolicy");
    110 			else
    111 				tst_brkm(TCONF, cleanup,
    112 					 "set_mempolicy syscall is not "
    113 					 "implemented on your system.");
    114 		}
    115 		create_same_memory(size, num, unit);
    116 
    117 		write_cpusets(node);
    118 		create_same_memory(size, num, unit);
    119 	}
    120 	cleanup();
    121 	tst_exit();
    122 }
    123 
    124 void cleanup(void)
    125 {
    126 	if (access(PATH_KSM "merge_across_nodes", F_OK) == 0)
    127 		FILE_PRINTF(PATH_KSM "merge_across_nodes",
    128 				 "%d", merge_across_nodes);
    129 
    130 	restore_max_page_sharing();
    131 
    132 	umount_mem(CPATH, CPATH_NEW);
    133 	umount_mem(MEMCG_PATH, MEMCG_PATH_NEW);
    134 }
    135 
    136 void setup(void)
    137 {
    138 	tst_require_root();
    139 
    140 	if (tst_kvercmp(2, 6, 32) < 0)
    141 		tst_brkm(TCONF, NULL, "2.6.32 or greater kernel required");
    142 	if (access(PATH_KSM, F_OK) == -1)
    143 		tst_brkm(TCONF, NULL, "KSM configuration is not enabled");
    144 
    145 	if (access(PATH_KSM "merge_across_nodes", F_OK) == 0) {
    146 		SAFE_FILE_SCANF(NULL, PATH_KSM "merge_across_nodes",
    147 				"%d", &merge_across_nodes);
    148 		SAFE_FILE_PRINTF(NULL, PATH_KSM "merge_across_nodes", "1");
    149 	}
    150 
    151 	save_max_page_sharing();
    152 
    153 	tst_sig(FORK, DEF_HANDLER, cleanup);
    154 	TEST_PAUSE;
    155 	mount_mem("cpuset", "cpuset", NULL, CPATH, CPATH_NEW);
    156 	mount_mem("memcg", "cgroup", "memory", MEMCG_PATH, MEMCG_PATH_NEW);
    157 }
    158 
    159 #else /* no NUMA */
    160 int main(void)
    161 {
    162 	tst_brkm(TCONF, NULL, "no NUMA development packages installed.");
    163 }
    164 #endif
    165