xref: /aosp_15_r20/external/ltp/testcases/kernel/mem/ksm/ksm04.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2010-2017  Red Hat, Inc.
4  */
5 
6 /*\
7  * [Description]
8  *
9  * Prerequisites:
10  *
11  * ksm and ksmtuned daemons need to be disabled. Otherwise, it could
12  * distrub the testing as they also change some ksm tunables depends
13  * on current workloads.
14  *
15  * [Algorithm]
16  *
17  * - Check ksm feature and backup current run setting.
18  * - Change run setting to 1 - merging.
19  * - 3 memory allocation programs have the memory contents that 2 of
20  *   them are all 'a' and one is all 'b'.
21  * - Check ksm statistics and verify the content.
22  * - 1 program changes the memory content from all 'a' to all 'b'.
23  * - Check ksm statistics and verify the content.
24  * - All programs change the memory content to all 'd'.
25  * - Check ksm statistics and verify the content.
26  * - Change one page of a process.
27  * - Check ksm statistics and verify the content.
28  * - Change run setting to 2 - unmerging.
29  * - Check ksm statistics and verify the content.
30  * - Change run setting to 0 - stop.
31  */
32 
33 #include "config.h"
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <signal.h>
39 #include <stdio.h>
40 #include <unistd.h>
41 #include "mem.h"
42 #include "ksm_common.h"
43 
44 #ifdef HAVE_NUMA_V2
45 #include <numaif.h>
46 
verify_ksm(void)47 static void verify_ksm(void)
48 {
49 	unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 };
50 	unsigned int node;
51 
52 	node = get_a_numa_node();
53 	set_node(nmask, node);
54 
55 	SAFE_CG_PRINTF(tst_cg, "memory.max", "%lu", TESTMEM);
56 
57 	if (set_mempolicy(MPOL_BIND, nmask, MAXNODES) == -1) {
58 		if (errno != ENOSYS)
59 			tst_brk(TBROK | TERRNO, "set_mempolicy");
60 		else
61 			tst_brk(TCONF, "set_mempolicy syscall is not "
62 					"implemented on your system.");
63 	}
64 	create_same_memory(size, num, unit);
65 
66 	write_cpusets(tst_cg, node);
67 	create_same_memory(size, num, unit);
68 }
69 
setup(void)70 static void setup(void)
71 {
72 	parse_ksm_options(opt_sizestr, &size, opt_numstr, &num, opt_unitstr, &unit);
73 
74 	SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid());
75 
76 	if (opt_sizestr && size > DEFAULT_MEMSIZE)
77 		tst_set_max_runtime(32 * (size / DEFAULT_MEMSIZE));
78 }
79 
80 static struct tst_test test = {
81 	.needs_root = 1,
82 	.forks_child = 1,
83 	.options = (struct tst_option[]) {
84 		{"n:", &opt_numstr,  "Number of processes"},
85 		{"s:", &opt_sizestr, "Memory allocation size in MB"},
86 		{"u:", &opt_unitstr, "Memory allocation unit in MB"},
87 		{}
88 	},
89 	.setup = setup,
90 	.save_restore = (const struct tst_path_val[]) {
91 		{"/sys/kernel/mm/ksm/run", NULL, TST_SR_TBROK},
92 		{"/sys/kernel/mm/ksm/sleep_millisecs", NULL, TST_SR_TBROK},
93 		{"/sys/kernel/mm/ksm/max_page_sharing", NULL,
94 			TST_SR_SKIP_MISSING | TST_SR_TCONF_RO},
95 		{"/sys/kernel/mm/ksm/merge_across_nodes", "1",
96 			TST_SR_SKIP_MISSING | TST_SR_TCONF_RO},
97 		{"/sys/kernel/mm/ksm/smart_scan", "0",
98 			TST_SR_SKIP_MISSING | TST_SR_TBROK_RO},
99 		{}
100 	},
101 	.needs_kconfigs = (const char *const[]){
102 		"CONFIG_KSM=y",
103 		NULL
104 	},
105 	.test_all = verify_ksm,
106 	.max_runtime = 32,
107 	.needs_cgroup_ctrls = (const char *const []){
108 		"memory", "cpuset", NULL
109 	},
110 };
111 
112 #else
113 	TST_TEST_TCONF(NUMA_ERROR_MSG);
114 #endif
115