Home | History | Annotate | Download | only in mtest01
      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