• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  *  FILE		: mtest01.c
22  *  DESCRIPTION : mallocs memory <chunksize> at a time until malloc fails.
23  *  HISTORY:
24  *	04/10/2001 Paul Larson (plars@us.ibm.com)
25  *	  written
26  *	11/09/2001 Manoj Iyer (manjo@austin.ibm.com)
27  *	  Modified.
28  *	  - Removed compile warnings.
29  *	  - Added header file #include <unistd.h> definition for getopt()
30  *	05/13/2003 Robbie Williamson (robbiew@us.ibm.com)
31  *	  Modified.
32  *	  - Rewrote the test to be able to execute on large memory machines.
33  *
34  */
35 
36 #include <sys/types.h>
37 #include <sys/sysinfo.h>
38 #include <sys/wait.h>
39 #include <limits.h>
40 #include <signal.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 
45 #include "test.h"
46 
47 #define FIVE_HUNDRED_MB (unsigned long long)(500*1024*1024)
48 #define ONE_GB	(unsigned long long)(1024*1024*1024)
49 #define THREE_GB (unsigned long long)(3*ONE_GB)
50 
51 char *TCID = "mtest01";
52 int TST_TOTAL = 1;
53 static sig_atomic_t pid_count;
54 static sig_atomic_t sigchld_count;
55 static pid_t *pid_list;
56 
handler(int signo)57 static void handler(int signo)
58 {
59 	if (signo == SIGCHLD)
60 		sigchld_count++;
61 	pid_count++;
62 }
63 
cleanup(void)64 static void cleanup(void)
65 {
66 	int i = 0;
67 
68 	while (pid_list[i] > 0) {
69 		kill(pid_list[i], SIGKILL);
70 		i++;
71 	}
72 
73 	free(pid_list);
74 }
75 
main(int argc,char * argv[])76 int main(int argc, char *argv[])
77 {
78 	int c;
79 	char *mem;
80 	float percent;
81 	unsigned int maxpercent = 0, dowrite = 0, verbose = 0, j;
82 	unsigned long bytecount, alloc_bytes, max_pids;
83 	unsigned long long original_maxbytes, maxbytes = 0;
84 	unsigned long long pre_mem = 0, post_mem = 0;
85 	unsigned long long total_ram, total_free, D, C;
86 	int chunksize = 1024 * 1024;	/* one meg at a time by default */
87 	struct sysinfo sstats;
88 	int i, pid_cntr;
89 	pid_t pid;
90 	struct sigaction act;
91 
92 	act.sa_handler = handler;
93 	act.sa_flags = 0;
94 	sigemptyset(&act.sa_mask);
95 	sigaction(SIGRTMIN, &act, 0);
96 	sigaction(SIGCHLD, &act, 0);
97 
98 	while ((c = getopt(argc, argv, "c:b:p:wvh")) != -1) {
99 		switch (c) {
100 		case 'c':
101 			chunksize = atoi(optarg);
102 			break;
103 		case 'b':
104 			if (maxpercent != 0)
105 				tst_brkm(TBROK, NULL,
106 					 "ERROR: -b option cannot be used with -p "
107 					 "option at the same time");
108 			maxbytes = atoll(optarg);
109 			break;
110 		case 'p':
111 			if (maxbytes != 0)
112 				tst_brkm(TBROK, NULL,
113 					 "ERROR: -p option cannot be used with -b "
114 					 "option at the same time");
115 			maxpercent = atoi(optarg);
116 			if (maxpercent <= 0)
117 				tst_brkm(TBROK, NULL,
118 					 "ERROR: -p option requires number greater "
119 					 "than 0");
120 			if (maxpercent > 99)
121 				tst_brkm(TBROK, NULL,
122 					 "ERROR: -p option cannot be greater than "
123 					 "99");
124 			break;
125 		case 'w':
126 			dowrite = 1;
127 			break;
128 		case 'v':
129 			verbose = 1;
130 			break;
131 		case 'h':
132 		default:
133 			printf
134 			    ("usage: %s [-c <bytes>] [-b <bytes>|-p <percent>] [-v]\n",
135 			     argv[0]);
136 			printf
137 			    ("\t-c <num>\tsize of chunk in bytes to malloc on each pass\n");
138 			printf
139 			    ("\t-b <bytes>\tmaximum number of bytes to allocate before stopping\n");
140 			printf
141 			    ("\t-p <bytes>\tpercent of total memory used at which the program stops\n");
142 			printf
143 			    ("\t-w\t\twrite to the memory after allocating\n");
144 			printf("\t-v\t\tverbose\n");
145 			printf("\t-h\t\tdisplay usage\n");
146 			exit(1);
147 		}
148 	}
149 
150 	sysinfo(&sstats);
151 	total_ram = sstats.totalram + sstats.totalswap;
152 	total_free = sstats.freeram + sstats.freeswap;
153 	/* Total Free Pre-Test RAM */
154 	pre_mem = sstats.mem_unit * total_free;
155 	max_pids = total_ram * sstats.mem_unit
156 		/ (unsigned long)FIVE_HUNDRED_MB + 10;
157 
158 	if ((pid_list = malloc(max_pids * sizeof(pid_t))) == NULL)
159 		tst_brkm(TBROK | TERRNO, NULL, "malloc failed.");
160 	memset(pid_list, 0, max_pids * sizeof(pid_t));
161 
162 	/* Currently used memory */
163 	C = sstats.mem_unit * (total_ram - total_free);
164 	tst_resm(TINFO, "Total memory already used on system = %llu kbytes",
165 		 C / 1024);
166 
167 	if (maxpercent) {
168 		percent = (float)maxpercent / 100.00;
169 
170 		/* Desired memory needed to reach maxpercent */
171 		D = percent * (sstats.mem_unit * total_ram);
172 		tst_resm(TINFO,
173 			 "Total memory used needed to reach maximum = %llu kbytes",
174 			 D / 1024);
175 
176 		/* Are we already using more than maxpercent? */
177 		if (C > D) {
178 			tst_resm(TFAIL,
179 				 "More memory than the maximum amount you specified "
180 				 " is already being used");
181 			free(pid_list);
182 			tst_exit();
183 		}
184 
185 		/* set maxbytes to the extra amount we want to allocate */
186 		maxbytes = D - C;
187 		tst_resm(TINFO, "Filling up %d%% of ram which is %llu kbytes",
188 			 maxpercent, maxbytes / 1024);
189 	}
190 	original_maxbytes = maxbytes;
191 	i = 0;
192 	pid_cntr = 0;
193 	pid = fork();
194 	if (pid < 0)
195 		tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
196 	if (pid != 0) {
197 		pid_cntr++;
198 		pid_list[i] = pid;
199 	}
200 
201 #if defined (_s390_)		/* s390's 31bit addressing requires smaller chunks */
202 	while (pid != 0 && maxbytes > FIVE_HUNDRED_MB) {
203 		i++;
204 		if (i >= max_pids)
205 			tst_brkm(TBROK, cleanup, "max_pids needs to be increased");
206 		maxbytes -= FIVE_HUNDRED_MB;
207 		pid = fork();
208 		if (pid < 0)
209 			tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
210 		if (pid != 0) {
211 			pid_cntr++;
212 			pid_list[i] = pid;
213 		}
214 	}
215 	if (maxbytes > FIVE_HUNDRED_MB)
216 		alloc_bytes = FIVE_HUNDRED_MB;
217 	else
218 		alloc_bytes = (unsigned long)maxbytes;
219 
220 #elif __WORDSIZE == 32
221 	while (pid != 0 && maxbytes > ONE_GB) {
222 		i++;
223 		if (i >= max_pids)
224 			tst_brkm(TBROK, cleanup, "max_pids needs to be increased");
225 		maxbytes -= ONE_GB;
226 		pid = fork();
227 		if (pid < 0)
228 		    tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
229 		if (pid != 0) {
230 			pid_cntr++;
231 			pid_list[i] = pid;
232 		}
233 	}
234 	if (maxbytes > ONE_GB)
235 		alloc_bytes = ONE_GB;
236 	else
237 		alloc_bytes = (unsigned long)maxbytes;
238 
239 #elif __WORDSIZE == 64
240 	while (pid != 0 && maxbytes > THREE_GB) {
241 		i++;
242 		if (i >= max_pids)
243 			tst_brkm(TBROK, cleanup, "max_pids needs to be increased");
244 		maxbytes -= THREE_GB;
245 		pid = fork();
246 		if (pid < 0)
247 			tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
248 		if (pid != 0) {
249 			pid_cntr++;
250 			pid_list[i] = pid;
251 		}
252 	}
253 	if (maxbytes > THREE_GB)
254 		alloc_bytes = THREE_GB;
255 	else
256 		alloc_bytes = maxbytes;
257 #endif
258 
259 	if (pid == 0) {
260 		bytecount = chunksize;
261 		while (1) {
262 			if ((mem = malloc(chunksize)) == NULL) {
263 				tst_resm(TBROK | TERRNO,
264 					 "stopped at %lu bytes", bytecount);
265 				free(pid_list);
266 				tst_exit();
267 			}
268 			if (dowrite)
269 				for (j = 0; j < chunksize; j++)
270 					*(mem + j) = 'a';
271 			if (verbose)
272 				tst_resm(TINFO,
273 					 "allocated %lu bytes chunksize is %d",
274 					 bytecount, chunksize);
275 			bytecount += chunksize;
276 			if (alloc_bytes && bytecount >= alloc_bytes)
277 				break;
278 		}
279 		if (dowrite)
280 			tst_resm(TINFO, "... %lu bytes allocated and used.",
281 				 bytecount);
282 		else
283 			tst_resm(TINFO, "... %lu bytes allocated only.",
284 				 bytecount);
285 		kill(getppid(), SIGRTMIN);
286 		while (1)
287 			sleep(1);
288 	} else {
289 		sysinfo(&sstats);
290 
291 		if (dowrite) {
292 			/* Total Free Post-Test RAM */
293 			post_mem =
294 			    (unsigned long long)sstats.mem_unit *
295 			    sstats.freeram;
296 			post_mem =
297 			    post_mem +
298 			    (unsigned long long)sstats.mem_unit *
299 			    sstats.freeswap;
300 
301 			while ((((unsigned long long)pre_mem - post_mem) <
302 				(unsigned long long)original_maxbytes) &&
303 			       pid_count < pid_cntr && !sigchld_count) {
304 				sleep(1);
305 				sysinfo(&sstats);
306 				post_mem =
307 				    (unsigned long long)sstats.mem_unit *
308 				    sstats.freeram;
309 				post_mem =
310 				    post_mem +
311 				    (unsigned long long)sstats.mem_unit *
312 				    sstats.freeswap;
313 			}
314 		}
315 
316 		if (sigchld_count) {
317 			tst_resm(TFAIL, "child process exited unexpectedly");
318 		} else if (dowrite) {
319 			tst_resm(TPASS, "%llu kbytes allocated and used.",
320 				 original_maxbytes / 1024);
321 		} else {
322 			tst_resm(TPASS, "%llu kbytes allocated only.",
323 				 original_maxbytes / 1024);
324 		}
325 
326 	}
327 	cleanup();
328 	tst_exit();
329 }
330