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 (at) us.ibm.com) 25 * written 26 * 11/09/2001 Manoj Iyer (manjo (at) 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 (at) 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 57 static void handler(int signo) 58 { 59 if (signo == SIGCHLD) 60 sigchld_count++; 61 pid_count++; 62 } 63 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 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