• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * There are two tunables overcommit_memory and overcommit_ratio under
3  * /proc/sys/vm/, which can control memory overcommitment.
4  *
5  * The overcommit_memory contains a flag that enables memory
6  * overcommitment, it has three values:
7  * - When this flag is 0, the kernel attempts to estimate the amount
8  *   of free memory left when userspace requests more memory.
9  * - When this flag is 1, the kernel pretends there is always enough
10  *   memory until it actually runs out.
11  * - When this flag is 2, the kernel uses a "never overcommit" policy
12  *   that attempts to prevent any overcommit of memory.
13  *
14  * The overcommit_ratio tunable defines the amount by which the kernel
15  * overextends its memory resources in the event that overcommit_memory
16  * is set to the value of 2. The value in this file represents a
17  * percentage added to the amount of actual RAM in a system when
18  * considering whether to grant a particular memory request.
19  * The general formula for this tunable is:
20  * CommitLimit = SwapTotal + MemTotal * overcommit_ratio
21  * CommitLimit, SwapTotal and MemTotal can read from /proc/meminfo.
22  *
23  * The program is designed to test the two tunables:
24  *
25  * When overcommit_memory = 0, allocatable memory can't overextends
26  * the amount of free memory. I choose the three cases:
27  * a. less than free_total:    free_total / 2, alloc should pass.
28  * b. greater than free_total: free_total * 2, alloc should fail.
29  * c. equal to sum_total:      sum_tatal,      alloc should fail
30  *
31  * When overcommit_memory = 1, it can alloc enough much memory, I
32  * choose the three cases:
33  * a. less than sum_total:    sum_total / 2, alloc should pass
34  * b. equal to sum_total:     sum_total,     alloc should pass
35  * c. greater than sum_total: sum_total * 2, alloc should pass
36  * *note: sum_total = SwapTotal + MemTotal
37  *
38  * When overcommit_memory = 2, the total virtual address space on
39  * the system is limited to CommitLimit(Swap+RAM*overcommit_ratio)
40  * commit_left(allocatable memory) = CommitLimit - Committed_AS
41  * a. less than commit_left:    commit_left / 2, alloc should pass
42  * b. greater than commit_left: commit_left * 2, alloc should fail
43  * c. overcommit limit:         CommitLimit,     alloc should fail
44  * *note: CommitLimit is the current overcommit limit.
45  *        Committed_AS is the amount of memory that system has used.
46  * it couldn't choose 'equal to commit_left' as a case, because
47  * commit_left rely on Committed_AS, but the Committed_AS is not stable.
48  *
49  * References:
50  * - Documentation/sysctl/vm.txt
51  * - Documentation/vm/overcommit-accounting
52  *
53  * ********************************************************************
54  * Copyright (C) 2012 Red Hat, Inc.
55  *
56  * This program is free software; you can redistribute it and/or
57  * modify it under the terms of version 2 of the GNU General Public
58  * License as published by the Free Software Foundation.
59  *
60  * This program is distributed in the hope that it would be useful,
61  * but WITHOUT ANY WARRANTY; without even the implied warranty of
62  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
63  *
64  * Further, this software is distributed without any warranty that it
65  * is free of the rightful claim of any third person regarding
66  * infringement or the like.  Any license provided herein, whether
67  * implied or otherwise, applies only to this software file.  Patent
68  * licenses, if any, provided herein do not apply to combinations of
69  * this program with other software, or any other product whatsoever.
70  *
71  * You should have received a copy of the GNU General Public License
72  * along with this program; if not, write the Free Software
73  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
74  * 02110-1301, USA.
75  *
76  * ********************************************************************
77  */
78 
79 #include <errno.h>
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include "test.h"
83 #include "safe_macros.h"
84 #include "mem.h"
85 
86 #define DEFAULT_OVER_RATIO	50L
87 #define EXPECT_PASS		0
88 #define EXPECT_FAIL		1
89 
90 char *TCID = "overcommit_memory";
91 static long old_overcommit_memory;
92 static long old_overcommit_ratio;
93 static long overcommit_ratio;
94 static long sum_total;
95 static long free_total;
96 static long commit_limit;
97 static long commit_left;
98 static int R_flag;
99 static char *R_opt;
100 option_t options[] = {
101 	{"R:", &R_flag, &R_opt},
102 	{NULL, NULL, NULL}
103 };
104 
105 static void overcommit_memory_test(void);
106 static int heavy_malloc(long size);
107 static void alloc_and_check(long size, int expect_result);
108 static void usage(void);
109 static void update_mem(void);
110 
main(int argc,char * argv[])111 int main(int argc, char *argv[])
112 {
113 	int lc;
114 
115 	tst_parse_opts(argc, argv, options, &usage);
116 
117 #if __WORDSIZE == 32
118 	tst_brkm(TCONF, NULL, "test is not designed for 32-bit system.");
119 #endif
120 
121 	if (R_flag)
122 		overcommit_ratio = SAFE_STRTOL(NULL, R_opt, 0, LONG_MAX);
123 	else
124 		overcommit_ratio = DEFAULT_OVER_RATIO;
125 
126 	setup();
127 
128 	for (lc = 0; TEST_LOOPING(lc); lc++) {
129 		tst_count = 0;
130 
131 		overcommit_memory_test();
132 	}
133 
134 	cleanup();
135 
136 	tst_exit();
137 }
138 
setup(void)139 void setup(void)
140 {
141 	long mem_total, swap_total;
142 	struct rlimit lim;
143 
144 	tst_require_root();
145 
146 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
147 
148 	TEST_PAUSE;
149 
150 	if (access(PATH_SYSVM "overcommit_memory", F_OK) == -1 ||
151 	    access(PATH_SYSVM "overcommit_ratio", F_OK) == -1)
152 		tst_brkm(TCONF, NULL, "The system "
153 			 "can't support to test %s", TCID);
154 
155 	old_overcommit_memory = get_sys_tune("overcommit_memory");
156 	old_overcommit_ratio = get_sys_tune("overcommit_ratio");
157 
158 	mem_total = read_meminfo("MemTotal:");
159 	tst_resm(TINFO, "MemTotal is %ld kB", mem_total);
160 	swap_total = read_meminfo("SwapTotal:");
161 	tst_resm(TINFO, "SwapTotal is %ld kB", swap_total);
162 	sum_total = mem_total + swap_total;
163 
164 	commit_limit = read_meminfo("CommitLimit:");
165 	tst_resm(TINFO, "CommitLimit is %ld kB", commit_limit);
166 
167 	SAFE_GETRLIMIT(NULL, RLIMIT_AS, &lim);
168 
169 	if (lim.rlim_cur != RLIM_INFINITY) {
170 		lim.rlim_cur = RLIM_INFINITY;
171 		lim.rlim_max = RLIM_INFINITY;
172 
173 		tst_resm(TINFO, "Increasing RLIM_AS to INFINITY");
174 
175 		SAFE_SETRLIMIT(NULL, RLIMIT_AS, &lim);
176 	}
177 
178 	set_sys_tune("overcommit_ratio", overcommit_ratio, 1);
179 }
180 
cleanup(void)181 void cleanup(void)
182 {
183 	set_sys_tune("overcommit_memory", old_overcommit_memory, 0);
184 	set_sys_tune("overcommit_ratio", old_overcommit_ratio, 0);
185 }
186 
usage(void)187 static void usage(void)
188 {
189 	printf("  -R n    Percentage of overcommitting memory\n");
190 }
191 
overcommit_memory_test(void)192 static void overcommit_memory_test(void)
193 {
194 	/* start to test overcommit_memory=2 */
195 	set_sys_tune("overcommit_memory", 2, 1);
196 
197 	update_mem();
198 	alloc_and_check(commit_left * 2, EXPECT_FAIL);
199 	alloc_and_check(commit_limit, EXPECT_FAIL);
200 	update_mem();
201 	alloc_and_check(commit_left / 2, EXPECT_PASS);
202 
203 	/* start to test overcommit_memory=0 */
204 	set_sys_tune("overcommit_memory", 0, 1);
205 
206 	update_mem();
207 	alloc_and_check(free_total / 2, EXPECT_PASS);
208 	update_mem();
209 	alloc_and_check(free_total * 2, EXPECT_FAIL);
210 	alloc_and_check(sum_total, EXPECT_FAIL);
211 
212 	/* start to test overcommit_memory=1 */
213 	set_sys_tune("overcommit_memory", 1, 1);
214 
215 	alloc_and_check(sum_total / 2, EXPECT_PASS);
216 	alloc_and_check(sum_total, EXPECT_PASS);
217 	alloc_and_check(sum_total * 2, EXPECT_PASS);
218 
219 }
220 
heavy_malloc(long size)221 static int heavy_malloc(long size)
222 {
223 	char *p;
224 
225 	p = malloc(size * KB);
226 	if (p != NULL) {
227 		tst_resm(TINFO, "malloc %ld kB successfully", size);
228 		free(p);
229 		return 0;
230 	} else {
231 		tst_resm(TINFO, "malloc %ld kB failed", size);
232 		return 1;
233 	}
234 }
235 
alloc_and_check(long size,int expect_result)236 static void alloc_and_check(long size, int expect_result)
237 {
238 	int result;
239 
240 	/* try to alloc size kB memory */
241 	result = heavy_malloc(size);
242 
243 	switch (expect_result) {
244 	case EXPECT_PASS:
245 		if (result == 0)
246 			tst_resm(TPASS, "alloc passed as expected");
247 		else
248 			tst_resm(TFAIL, "alloc failed, expected to pass");
249 		break;
250 	case EXPECT_FAIL:
251 		if (result != 0)
252 			tst_resm(TPASS, "alloc failed as expected");
253 		else
254 			tst_resm(TFAIL, "alloc passed, expected to fail");
255 		break;
256 	default:
257 		tst_brkm(TBROK, cleanup, "Invaild numbler parameter: %d",
258 			 expect_result);
259 	}
260 }
261 
update_mem(void)262 static void update_mem(void)
263 {
264 	long mem_free, swap_free;
265 	long committed;
266 
267 	mem_free = read_meminfo("MemFree:");
268 	swap_free = read_meminfo("SwapFree:");
269 	free_total = mem_free + swap_free;
270 	commit_limit = read_meminfo("CommitLimit:");
271 
272 	if (get_sys_tune("overcommit_memory") == 2) {
273 		committed = read_meminfo("Committed_AS:");
274 		commit_left = commit_limit - committed;
275 
276 		if (commit_left < 0) {
277 			tst_resm(TINFO, "CommitLimit is %ld, Committed_AS"
278 				 " is %ld", commit_limit, committed);
279 			tst_brkm(TBROK, cleanup, "Unexpected error: "
280 				 "CommitLimit < Committed_AS");
281 		}
282 	}
283 }
284