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