blob: cbc671090f48f9c0ec8b964ff82870f4eabec3b0 [file] [log] [blame]
Zhouping Liuc9f2fd52012-02-13 20:07:08 +08001/*
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"
Caspar Zhang79667fa2012-03-12 14:41:46 +080084#include "mem.h"
Zhouping Liuc9f2fd52012-02-13 20:07:08 +080085
86#define DEFAULT_OVER_RATIO 50L
87#define EXPECT_PASS 0
88#define EXPECT_FAIL 1
89
90char *TCID = "overcommit_memory";
91static long old_overcommit_memory;
92static long old_overcommit_ratio;
93static long overcommit_ratio;
94static long sum_total;
95static long free_total;
96static long commit_limit;
97static long commit_left;
98static int R_flag;
99static char *R_opt;
100option_t options[] = {
101 {"R:", &R_flag, &R_opt},
102 {NULL, NULL, NULL}
103};
104
105static void overcommit_memory_test(void);
106static int heavy_malloc(long size);
107static void alloc_and_check(long size, int expect_result);
108static void usage(void);
109static void update_mem(void);
110
111int main(int argc, char *argv[])
112{
Cyril Hrubis0b9589f2014-05-27 17:40:33 +0200113 const char *msg;
Zhouping Liuc9f2fd52012-02-13 20:07:08 +0800114 int lc;
115
116 msg = parse_opts(argc, argv, options, &usage);
117 if (msg != NULL)
118 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
119
120#if __WORDSIZE == 32
121 tst_brkm(TCONF, NULL, "test is not designed for 32-bit system.");
122#endif
123
124 if (R_flag)
125 overcommit_ratio = SAFE_STRTOL(NULL, R_opt, 0, LONG_MAX);
126 else
127 overcommit_ratio = DEFAULT_OVER_RATIO;
128
129 setup();
130
131 for (lc = 0; TEST_LOOPING(lc); lc++) {
Caspar Zhangd59a6592013-03-07 14:59:12 +0800132 tst_count = 0;
Zhouping Liuc9f2fd52012-02-13 20:07:08 +0800133
134 overcommit_memory_test();
135 }
136
137 cleanup();
138
139 tst_exit();
140}
141
142void setup(void)
143{
144 long mem_total, swap_total;
145
146 tst_require_root(NULL);
147
148 tst_sig(NOFORK, DEF_HANDLER, cleanup);
149
150 TEST_PAUSE;
151
152 if (access(PATH_SYSVM "overcommit_memory", F_OK) == -1 ||
153 access(PATH_SYSVM "overcommit_ratio", F_OK) == -1)
154 tst_brkm(TCONF, NULL, "The system "
155 "can't support to test %s", TCID);
156
157 old_overcommit_memory = get_sys_tune("overcommit_memory");
158 old_overcommit_ratio = get_sys_tune("overcommit_ratio");
159
160 set_sys_tune("overcommit_ratio", overcommit_ratio, 1);
161
162 mem_total = read_meminfo("MemTotal:");
163 tst_resm(TINFO, "MemTotal is %ld kB", mem_total);
164 swap_total = read_meminfo("SwapTotal:");
165 tst_resm(TINFO, "SwapTotal is %ld kB", swap_total);
166 sum_total = mem_total + swap_total;
167
168 commit_limit = read_meminfo("CommitLimit:");
169 tst_resm(TINFO, "CommitLimit is %ld kB", commit_limit);
170}
171
172void cleanup(void)
173{
174 set_sys_tune("overcommit_memory", old_overcommit_memory, 0);
175 set_sys_tune("overcommit_ratio", old_overcommit_ratio, 0);
Zhouping Liuc9f2fd52012-02-13 20:07:08 +0800176}
177
178static void usage(void)
179{
180 printf(" -R n Percentage of overcommitting memory\n");
181}
182
183static void overcommit_memory_test(void)
184{
Wanlong Gao52a8a6d2012-02-21 11:43:33 +0800185 /* start to test overcommit_memory=2 */
186 set_sys_tune("overcommit_memory", 2, 1);
187
188 update_mem();
189 alloc_and_check(commit_left * 2, EXPECT_FAIL);
190 alloc_and_check(commit_limit, EXPECT_FAIL);
191 update_mem();
192 alloc_and_check(commit_left / 2, EXPECT_PASS);
193
Zhouping Liuc9f2fd52012-02-13 20:07:08 +0800194 /* start to test overcommit_memory=0 */
195 set_sys_tune("overcommit_memory", 0, 1);
196
197 update_mem();
198 alloc_and_check(free_total / 2, EXPECT_PASS);
199 update_mem();
200 alloc_and_check(free_total * 2, EXPECT_FAIL);
201 alloc_and_check(sum_total, EXPECT_FAIL);
202
203 /* start to test overcommit_memory=1 */
204 set_sys_tune("overcommit_memory", 1, 1);
205
206 alloc_and_check(sum_total / 2, EXPECT_PASS);
207 alloc_and_check(sum_total, EXPECT_PASS);
208 alloc_and_check(sum_total * 2, EXPECT_PASS);
209
Zhouping Liuc9f2fd52012-02-13 20:07:08 +0800210}
211
212static int heavy_malloc(long size)
213{
214 char *p;
215
216 p = malloc(size * KB);
217 if (p != NULL) {
218 tst_resm(TINFO, "malloc %ld kB successfully", size);
219 free(p);
220 return 0;
221 } else {
222 tst_resm(TINFO, "malloc %ld kB failed", size);
223 return 1;
224 }
225}
226
227static void alloc_and_check(long size, int expect_result)
228{
229 int result;
230
231 /* try to alloc size kB memory */
232 result = heavy_malloc(size);
233
234 switch (expect_result) {
235 case EXPECT_PASS:
236 if (result == 0)
237 tst_resm(TPASS, "alloc passed as expected");
238 else
239 tst_resm(TFAIL, "alloc failed, expected to pass");
240 break;
241 case EXPECT_FAIL:
242 if (result != 0)
243 tst_resm(TPASS, "alloc failed as expected");
244 else
245 tst_resm(TFAIL, "alloc passed, expected to fail");
246 break;
247 default:
248 tst_brkm(TBROK, cleanup, "Invaild numbler parameter: %d",
249 expect_result);
250 }
251}
252
253static void update_mem(void)
254{
255 long mem_free, swap_free;
256 long committed;
257
258 mem_free = read_meminfo("MemFree:");
259 swap_free = read_meminfo("SwapFree:");
260 free_total = mem_free + swap_free;
Wanlong Gao52a8a6d2012-02-21 11:43:33 +0800261 commit_limit = read_meminfo("CommitLimit:");
Zhouping Liuc9f2fd52012-02-13 20:07:08 +0800262
263 if (get_sys_tune("overcommit_memory") == 2) {
264 committed = read_meminfo("Committed_AS:");
265 commit_left = commit_limit - committed;
266
267 if (commit_left < 0) {
268 tst_resm(TINFO, "CommmitLimit is %ld, Committed_AS"
269 " is %ld", commit_limit, committed);
270 tst_brkm(TBROK, cleanup, "Unexpected error: "
271 "CommitLimit < Committed_AS");
272 }
273 }
274}