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 alloc_bytes = MIN(THREE_GB, maxbytes);
254 #endif
255
256 if (pid == 0) {
257 bytecount = chunksize;
258 while (1) {
259 if ((mem = malloc(chunksize)) == NULL) {
260 tst_resm(TBROK | TERRNO,
261 "stopped at %lu bytes", bytecount);
262 free(pid_list);
263 tst_exit();
264 }
265 if (dowrite)
266 for (j = 0; j < chunksize; j++)
267 *(mem + j) = 'a';
268 if (verbose)
269 tst_resm(TINFO,
270 "allocated %lu bytes chunksize is %d",
271 bytecount, chunksize);
272 bytecount += chunksize;
273 if (alloc_bytes && bytecount >= alloc_bytes)
274 break;
275 }
276 if (dowrite)
277 tst_resm(TINFO, "... %lu bytes allocated and used.",
278 bytecount);
279 else
280 tst_resm(TINFO, "... %lu bytes allocated only.",
281 bytecount);
282 kill(getppid(), SIGRTMIN);
283 while (1)
284 sleep(1);
285 } else {
286 sysinfo(&sstats);
287
288 if (dowrite) {
289 /* Total Free Post-Test RAM */
290 post_mem =
291 (unsigned long long)sstats.mem_unit *
292 sstats.freeram;
293 post_mem =
294 post_mem +
295 (unsigned long long)sstats.mem_unit *
296 sstats.freeswap;
297
298 while ((((unsigned long long)pre_mem - post_mem) <
299 (unsigned long long)original_maxbytes) &&
300 pid_count < pid_cntr && !sigchld_count) {
301 sleep(1);
302 sysinfo(&sstats);
303 post_mem =
304 (unsigned long long)sstats.mem_unit *
305 sstats.freeram;
306 post_mem =
307 post_mem +
308 (unsigned long long)sstats.mem_unit *
309 sstats.freeswap;
310 }
311 }
312
313 if (sigchld_count) {
314 tst_resm(TFAIL, "child process exited unexpectedly");
315 } else if (dowrite) {
316 tst_resm(TPASS, "%llu kbytes allocated and used.",
317 original_maxbytes / 1024);
318 } else {
319 tst_resm(TPASS, "%llu kbytes allocated only.",
320 original_maxbytes / 1024);
321 }
322
323 }
324 cleanup();
325 tst_exit();
326 }
327