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 / (unsigned long)FIVE_HUNDRED_MB + 1;
156
157 if ((pid_list = malloc(max_pids * sizeof(pid_t))) == NULL)
158 tst_brkm(TBROK | TERRNO, NULL, "malloc failed.");
159 memset(pid_list, 0, max_pids * sizeof(pid_t));
160
161 /* Currently used memory */
162 C = sstats.mem_unit * (total_ram - total_free);
163 tst_resm(TINFO, "Total memory already used on system = %llu kbytes",
164 C / 1024);
165
166 if (maxpercent) {
167 percent = (float)maxpercent / 100.00;
168
169 /* Desired memory needed to reach maxpercent */
170 D = percent * (sstats.mem_unit * total_ram);
171 tst_resm(TINFO,
172 "Total memory used needed to reach maximum = %llu kbytes",
173 D / 1024);
174
175 /* Are we already using more than maxpercent? */
176 if (C > D) {
177 tst_resm(TFAIL,
178 "More memory than the maximum amount you specified "
179 " is already being used");
180 free(pid_list);
181 tst_exit();
182 }
183
184 /* set maxbytes to the extra amount we want to allocate */
185 maxbytes = D - C;
186 tst_resm(TINFO, "Filling up %d%% of ram which is %llu kbytes",
187 maxpercent, maxbytes / 1024);
188 }
189 original_maxbytes = maxbytes;
190 i = 0;
191 pid_cntr = 0;
192 pid = fork();
193 if (pid < 0)
194 tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
195 if (pid != 0) {
196 pid_cntr++;
197 pid_list[i] = pid;
198 }
199
200 #if defined (_s390_) /* s390's 31bit addressing requires smaller chunks */
201 while (pid != 0 && maxbytes > FIVE_HUNDRED_MB) {
202 i++;
203 maxbytes -= FIVE_HUNDRED_MB;
204 pid = fork();
205 if (pid < 0)
206 tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
207 if (pid != 0) {
208 pid_cntr++;
209 pid_list[i] = pid;
210 }
211 }
212 if (maxbytes > FIVE_HUNDRED_MB)
213 alloc_bytes = FIVE_HUNDRED_MB;
214 else
215 alloc_bytes = (unsigned long)maxbytes;
216
217 #elif __WORDSIZE == 32
218 while (pid != 0 && maxbytes > ONE_GB) {
219 i++;
220 maxbytes -= ONE_GB;
221 pid = fork();
222 if (pid < 0)
223 tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
224 if (pid != 0) {
225 pid_cntr++;
226 pid_list[i] = pid;
227 }
228 }
229 if (maxbytes > ONE_GB)
230 alloc_bytes = ONE_GB;
231 else
232 alloc_bytes = (unsigned long)maxbytes;
233
234 #elif __WORDSIZE == 64
235 while (pid != 0 && maxbytes > THREE_GB) {
236 i++;
237 maxbytes -= THREE_GB;
238 pid = fork();
239 if (pid < 0)
240 tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
241 if (pid != 0) {
242 pid_cntr++;
243 pid_list[i] = pid;
244 }
245 }
246 if (maxbytes > THREE_GB)
247 alloc_bytes = THREE_GB;
248 else
249 alloc_bytes = maxbytes;
250 #endif
251
252 if (pid == 0) {
253 bytecount = chunksize;
254 while (1) {
255 if ((mem = malloc(chunksize)) == NULL) {
256 tst_resm(TBROK | TERRNO,
257 "stopped at %lu bytes", bytecount);
258 free(pid_list);
259 tst_exit();
260 }
261 if (dowrite)
262 for (j = 0; j < chunksize; j++)
263 *(mem + j) = 'a';
264 if (verbose)
265 tst_resm(TINFO,
266 "allocated %lu bytes chunksize is %d",
267 bytecount, chunksize);
268 bytecount += chunksize;
269 if (alloc_bytes && bytecount >= alloc_bytes)
270 break;
271 }
272 if (dowrite)
273 tst_resm(TINFO, "... %lu bytes allocated and used.",
274 bytecount);
275 else
276 tst_resm(TINFO, "... %lu bytes allocated only.",
277 bytecount);
278 kill(getppid(), SIGRTMIN);
279 while (1)
280 sleep(1);
281 } else {
282 sysinfo(&sstats);
283
284 if (dowrite) {
285 /* Total Free Post-Test RAM */
286 post_mem =
287 (unsigned long long)sstats.mem_unit *
288 sstats.freeram;
289 post_mem =
290 post_mem +
291 (unsigned long long)sstats.mem_unit *
292 sstats.freeswap;
293
294 while ((((unsigned long long)pre_mem - post_mem) <
295 (unsigned long long)original_maxbytes) &&
296 pid_count < pid_cntr && !sigchld_count) {
297 sleep(1);
298 sysinfo(&sstats);
299 post_mem =
300 (unsigned long long)sstats.mem_unit *
301 sstats.freeram;
302 post_mem =
303 post_mem +
304 (unsigned long long)sstats.mem_unit *
305 sstats.freeswap;
306 }
307 }
308
309 if (sigchld_count) {
310 tst_resm(TFAIL, "child process exited unexpectedly");
311 } else if (dowrite) {
312 tst_resm(TPASS, "%llu kbytes allocated and used.",
313 original_maxbytes / 1024);
314 } else {
315 tst_resm(TPASS, "%llu kbytes allocated only.",
316 original_maxbytes / 1024);
317 }
318
319 }
320 cleanup();
321 tst_exit();
322 }
323