• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * mem01.c - Basic memory and swapper stress test
3  *
4  * Copyright (C) 2001 Stephane Fillod <f4cfe@free.fr>
5  * Original idea from Rene Cougnenc
6  *
7  * Copyright (C) 2012 Cyril Hrubis <chrubis@suse.cz>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of version 2 of the GNU General Public License as
11  * published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it would be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  * Further, this software is distributed without any warranty that it is
18  * free of the rightful claim of any third person regarding infringement
19  * or the like.  Any license provided herein, whether implied or
20  * otherwise, applies only to this software file.  Patent licenses, if
21  * any, provided herein do not apply to combinations of this program with
22  * other software, or any other product whatsoever.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, write the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  *
28  */
29 
30 #include <unistd.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <sys/types.h>
35 #include <sys/sysinfo.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <sys/user.h>
39 #include <time.h>
40 #include <limits.h>
41 
42 #include "lapi/abisize.h"
43 #include "test.h"
44 
45 /* in KB */
46 #define PROGRESS_LEAP 100
47 
48 /*
49  * TODO:
50  *  - add option for growing direction, when doing linear touching
51  *  - add option for touch running time (or infinite loop?)
52  *  - make it multithreaded with random access to test r/w mm_sem
53  */
54 
55 char *TCID = "mem01";
56 int TST_TOTAL = 1;
57 
58 static int m_opt = 0;		/* memsize */
59 static char *m_copt;
60 
61 static int r_opt = 0;		/* random access versus linear */
62 static int v_opt = 0;		/* verbose progress indication */
63 
cleanup(void)64 static void cleanup(void)
65 {
66 	tst_rmdir();
67 	tst_exit();
68 }
69 
setup(void)70 static void setup(void)
71 {
72 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
73 
74 	TEST_PAUSE;
75 
76 	tst_tmpdir();
77 }
78 
help(void)79 static void help(void)
80 {
81 	printf("  -m x    size of malloc in MB (default from /proc/meminfo)\n");
82 	printf("  -r      random touching versus linear\n");
83 	printf("  -v      verbose progress indication\n");
84 }
85 
86 /*
87  * return MemFree+SwapFree, from /proc/meminfo
88  * returned value is in bytes.
89  */
get_memsize(void)90 size_t get_memsize(void)
91 {
92 	struct sysinfo info;
93 	unsigned long long res;
94 	unsigned long long freeswap;
95 	unsigned long long freeram;
96 	int ret;
97 
98 	ret = sysinfo(&info);
99 	if (ret != 0) {
100 		tst_resm(TFAIL,
101 			 "Could not retrieve memory information using sysinfo()");
102 		cleanup();
103 	}
104 
105 	freeram =
106 	    (unsigned long long)info.freeram *
107 	    (unsigned long long)info.mem_unit;
108 	tst_resm(TINFO, "Free Mem:\t%llu Mb", freeram / 1024 / 1024);
109 	res = freeram;
110 
111 	freeswap =
112 	    (unsigned long long)info.freeswap *
113 	    (unsigned long long)info.mem_unit;
114 	tst_resm(TINFO, "Free Swap:\t%llu Mb", freeswap / 1024 / 1024);
115 	res = res + freeswap;
116 
117 	tst_resm(TINFO, "Total Free:\t%llu Mb", res / 1024 / 1024);
118 #if defined(__s390__)
119 	if (res > 1 * 1024 * 1024 * 1024)
120 		res = 500 * 1024 * 1024;	/* s390's unique 31bit architecture needs smaller default */
121 #elif defined(TST_ABI32)
122 	if (res > 1 * 1024 * 1024 * 1024)
123 		res = 1 * 1024 * 1024 * 1024;
124 #elif defined(TST_ABI64)
125 	if (res > (unsigned long long)3 * 1024 * 1024 * 1024)
126 		res = (unsigned long long)3 *1024 * 1024 * 1024;
127 #endif
128 
129 	/* Always reserve 16MB memory to avoid OOM Killer. */
130 	res -= 16 * 1024 * 1024;
131 	tst_resm(TINFO, "Total Tested:\t%llu Mb", res / 1024 / 1024);
132 	return (size_t) res;
133 }
134 
135 /*
136  * add the -m option whose parameter is the
137  * memory size (MB) to allocate.
138  */
139 option_t options[] = {
140 	{"m:", &m_opt, &m_copt}
141 	,
142 	{"r", &r_opt, NULL}
143 	,
144 	{"v", &v_opt, NULL}
145 	,
146 	{NULL, NULL, NULL}
147 };
148 
main(int argc,char * argv[])149 int main(int argc, char *argv[])
150 {
151 	size_t memsize = 0;	/* at first in MB, limited to 4Gb on 32 bits */
152 	int pagesize;
153 
154 	int i;
155 	int lc;
156 	char *p, *bigmalloc;
157 	int loop_count;		/* limited to 16Go on 32 bits systems */
158 
159 	pagesize = sysconf(_SC_PAGESIZE);
160 
161 	tst_parse_opts(argc, argv, options, help);
162 
163 	if (m_opt) {
164 		memsize = (size_t) atoi(m_copt) * 1024 * 1024;
165 
166 		if (memsize < 1) {
167 			tst_brkm(TBROK, cleanup, "Invalid arg for -m: %s",
168 				 m_copt);
169 		}
170 	}
171 
172 	if (r_opt)
173 		srand(time(NULL));
174 
175 	setup();
176 
177 	for (lc = 0; TEST_LOOPING(lc); lc++) {
178 
179 		tst_count = 0;
180 
181 		if (!m_opt) {
182 			/* find out by ourselves! */
183 			memsize = get_memsize();
184 			if (memsize < 1) {
185 				tst_brkm(TBROK, cleanup,
186 					 "Unable to guess maxmemsize from /proc/meminfo");
187 			}
188 		}
189 
190 		/* Allocate (virtual) memory */
191 		bigmalloc = p = malloc(memsize);
192 
193 		if (!p) {
194 			tst_resm(TFAIL, "malloc - alloc of %zuMB failed",
195 				 memsize / 1024 / 1024);
196 			cleanup();
197 		}
198 
199 		/*
200 		 * Dirty all the pages, to force physical RAM allocation
201 		 * and exercise eventually the swapper
202 		 */
203 		tst_resm(TINFO, "touching %zuMB of malloc'ed memory (%s)",
204 			 memsize / 1024 / 1024, r_opt ? "random" : "linear");
205 
206 		loop_count = memsize / pagesize;
207 
208 		for (i = 0; i < loop_count; i++) {
209 			if (v_opt
210 			    && (i % (PROGRESS_LEAP * 1024 / pagesize) == 0)) {
211 				printf(".");
212 				fflush(stdout);
213 			}
214 			/*
215 			 * Make the page dirty,
216 			 * and make sure compiler won't optimize it away
217 			 * Touching more than one word per page is useless
218 			 * because of cache.
219 			 */
220 			*(int *)p = 0xdeadbeef ^ i;
221 
222 			if (r_opt) {
223 				p = bigmalloc +
224 				    (size_t) ((double)(memsize - sizeof(int)) *
225 					      rand() / (RAND_MAX + 1.0));
226 			} else {
227 				p += pagesize;
228 			}
229 		}
230 
231 		if (v_opt)
232 			printf("\n");
233 
234 		/* This is not mandatory (except in a loop), but it exercise mm again */
235 		free(bigmalloc);
236 
237 		/*
238 		 * seems that if the malloc'ed area was bad, we'd get SEGV (or kicked
239 		 * somehow by the OOM killer?), hence we can indicate a PASS.
240 		 */
241 		tst_resm(TPASS, "malloc - alloc of %zuMB succeeded",
242 			 memsize / 1024 / 1024);
243 
244 	}
245 
246 	cleanup();
247 
248 	return 0;
249 }
250