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 / (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