Home | History | Annotate | Download | only in vmtests
      1 /*
      2  *
      3  *   Copyright (c) International Business Machines  Corp., 2002
      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 /* 11/18/2002	Port to LTP	robbiew (at) us.ibm.com */
     21 /* 06/30/2001	Port to Linux	nsharoff (at) us.ibm.com */
     22 
     23 /*
     24  * NAME
     25  *	data_space.c -- test data space
     26  *
     27  * CALLS
     28  *	malloc (3)
     29  *
     30  * ALGORITHM
     31  *	Test VM for set of data-space intensive programs
     32  *
     33  */
     34 
     35 #define _XOPEN_SOURCE 500
     36 #include <stdio.h>
     37 #include <signal.h>
     38 #include <sys/types.h>
     39 #include <errno.h>
     40 #include <sys/wait.h>
     41 #include <stdlib.h>
     42 #include <unistd.h>
     43 #include <string.h>
     44 //void (*sigset(int, void(*)(int)))(int);
     45 
     46 /** LTP Port **/
     47 #include "test.h"
     48 
     49 #define FAILED 0
     50 #define PASSED 1
     51 
     52 int local_flag = PASSED;
     53 int block_number;
     54 
     55 char *TCID = "data_space";	/* Test program identifier.    */
     56 int TST_TOTAL = 1;		/* Total number of test cases. */
     57 /**************/
     58 
     59 #define MAXCHILD	100	/* max number of children to allow */
     60 int allchild[MAXCHILD + 1];
     61 #define K_1		1024
     62 #define K_2		2048
     63 #define K_4		4096
     64 
     65 #define bd_arg(str) \
     66 	tst_brkm(TCONF, NULL, \
     67 	    "bad argument - %s - could not parse as number.", str)
     68 
     69 int nchild;			/* # kids */
     70 int csize;			/* chunk size */
     71 int iterations;			/* # total iterations */
     72 int rep_freq;			/* report frequency */
     73 int max_size;			/* max file size */
     74 int parent_pid;
     75 
     76 int usage(char *);
     77 int runtest();
     78 int dotest(int, int);
     79 void bfill(char *, char, int);
     80 int dumpbuf(char *);
     81 void dumpbits(char *, int);
     82 int massmurder();
     83 int okexit(int);
     84 
     85 char *prog;			/* invoked name */
     86 int chld_flag = 0;
     87 
     88 void cleanup(void)
     89 {
     90 	tst_rmdir();
     91 }
     92 
     93 int usage(prog)
     94 char *prog;
     95 {
     96 	tst_resm(TCONF, "Usage: %s <nchild> <size> <chunk_size> <iterations>",
     97 		 prog);
     98 	tst_brkm(TCONF, NULL, "DEFAULTS: 10 1024*1024 4096 25");
     99 }
    100 
    101 int main(argc, argv)
    102 int argc;
    103 char *argv[];
    104 {
    105 	int i = 1;
    106 	int term();
    107 	int chld();
    108 
    109 	prog = argv[0];
    110 
    111 	if (argc == 1) {
    112 		nchild = 10;
    113 		max_size = K_1 * K_1;
    114 		csize = K_4;
    115 		iterations = 25;
    116 	} else if (argc == 5) {
    117 		if (sscanf(argv[i++], "%d", &nchild) != 1)
    118 			bd_arg(argv[i - 1]);
    119 		if (sscanf(argv[i++], "%d", &max_size) != 1)
    120 			bd_arg(argv[i - 1]);
    121 		if (sscanf(argv[i++], "%d", &csize) != 1)
    122 			bd_arg(argv[i - 1]);
    123 		if (sscanf(argv[i++], "%d", &iterations) != 1)
    124 			bd_arg(argv[i - 1]);
    125 		if (nchild > MAXCHILD) {
    126 			tst_brkm(TBROK, NULL,
    127 				 "FAILURE, %d children exceeded maximum allowed",
    128 				 nchild);
    129 		}
    130 	} else
    131 		usage(prog);
    132 
    133 	tst_tmpdir();
    134 
    135 	parent_pid = getpid();
    136 
    137 	if (sigset(SIGTERM, (void (*)())term) == SIG_ERR) {
    138 		tst_brkm(TBROK, NULL, "first sigset failed");
    139 	}
    140 	if (sigset(SIGUSR1, (void (*)())chld) == SIG_ERR) {
    141 		tst_brkm(TBROK, NULL, "sigset shichld");
    142 	}
    143 
    144 	runtest();
    145 	tst_exit();
    146 }
    147 
    148 int runtest()
    149 {
    150 	register int i;
    151 	int child;
    152 	int status;
    153 	int count;
    154 
    155 	for (i = 0; i < nchild; i++) {
    156 		chld_flag = 0;
    157 		switch (child = fork()) {
    158 		case -1:
    159 			tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
    160 		case 0:
    161 			dotest(nchild, i);
    162 			exit(0);
    163 		}
    164 		allchild[i] = child;
    165 		while (!chld_flag)
    166 			sleep(1);
    167 	}
    168 
    169 	/*
    170 	 * Wait for children to finish.
    171 	 */
    172 
    173 	count = 0;
    174 	while ((child = wait(&status)) > 0) {
    175 #ifdef DEBUG
    176 		tst_resm(TINFO, "\t%s[%d] exited status = 0x%x\n", prog, child,
    177 			 status);
    178 #endif
    179 		if (status) {
    180 			tst_resm(TFAIL, "\tTest failed, expected 0 exit.\n");
    181 			local_flag = FAILED;
    182 		}
    183 		++count;
    184 	}
    185 
    186 	/*
    187 	 * Should have collected all children.
    188 	 */
    189 
    190 	if (count != nchild) {
    191 		tst_resm(TFAIL, "\tWrong # children waited on, count = %d\n",
    192 			 count);
    193 		local_flag = FAILED;
    194 	}
    195 
    196 	if (local_flag == FAILED)
    197 		tst_resm(TFAIL, "Test failed");
    198 	else
    199 		tst_resm(TPASS, "Test passed");
    200 	sync();			/* safeness */
    201 
    202 	return 0;
    203 }
    204 
    205 /*
    206  * dotest()
    207  *	Children execute this.
    208  *
    209  * Randomly read/mod/write chunks with known pattern and check.
    210  * When fill sectors, iterate.
    211  *
    212  */
    213 
    214 int nchunks;
    215 
    216 #define	CHUNK(i)	((i) * csize)
    217 
    218 int dotest(testers, me)
    219 int testers;
    220 int me;
    221 {
    222 	char *bits;
    223 	char *mondobuf;
    224 	char *val_buf;
    225 	char *zero_buf;
    226 	char *buf;
    227 	int count;
    228 	int collide;
    229 	char val;
    230 	int chunk;
    231 
    232 	/*
    233 	 * Do the mondo-test.
    234 	 *
    235 	 * NOTE: If we run this with a lot of children, the last child
    236 	 *       processes may not have enough swap space to do these
    237 	 *       malloc's  (mainly mondobuf).  So if the malloc's don't
    238 	 *       work we just exit with zero status as long as we are
    239 	 *       not the first child.
    240 	 */
    241 
    242 	nchunks = max_size / csize;
    243 	bits = malloc((nchunks + 7) / 8);
    244 	if (bits == 0)
    245 		okexit(me);
    246 	val_buf = (char *)(malloc(csize));
    247 	if (val_buf == 0)
    248 		okexit(me);
    249 	zero_buf = (char *)(malloc(csize));
    250 	if (zero_buf == 0)
    251 		okexit(me);
    252 	mondobuf = malloc(max_size);
    253 	if (mondobuf == 0)
    254 		okexit(me);
    255 
    256 	kill(parent_pid, SIGUSR1);
    257 
    258 	/*
    259 	 * No init sectors; allow file to be sparse.
    260 	 */
    261 
    262 	val = (64 / testers) * me + 1;
    263 
    264 	/*
    265 	 * For each iteration:
    266 	 *      zap bits array
    267 	 *      loop:
    268 	 *              pick random chunk.
    269 	 *              if corresponding bit off {
    270 	 *                      verify == 0. (sparse file)
    271 	 *                      ++count;
    272 	 *              } else
    273 	 *                      verify == val.
    274 	 *              write "val" on it.
    275 	 *              repeat until count = nchunks.
    276 	 *      ++val.
    277 	 *      Fill-in those chunks not yet seen.
    278 	 */
    279 
    280 	bfill(zero_buf, 0, csize);
    281 	bfill(mondobuf, 0, max_size);
    282 
    283 	srand(getpid());
    284 	while (iterations-- > 0) {
    285 		bfill(bits, 0, (nchunks + 7) / 8);
    286 		bfill(val_buf, val, csize);
    287 		count = 0;
    288 		collide = 0;
    289 		while (count < nchunks) {
    290 			chunk = rand() % nchunks;
    291 			buf = mondobuf + CHUNK(chunk);
    292 
    293 			/*
    294 			 * If bit off, haven't seen it yet.
    295 			 * Else, have.  Verify values.
    296 			 */
    297 
    298 			if ((bits[chunk / 8] & (1 << (chunk % 8))) == 0) {
    299 				if (memcmp(buf, zero_buf, csize)) {
    300 					tst_resm(TFAIL,
    301 						 "\t%s[%d] bad verify @ %d (%p) for val %d count %d, should be 0x%x.\n",
    302 						 prog, me, chunk, buf, val,
    303 						 count, val - 1);
    304 					tst_resm(TINFO, "\tPrev ");
    305 					dumpbuf(buf - csize);
    306 					dumpbuf(buf);
    307 					tst_resm(TINFO, "\tNext ");
    308 					dumpbuf(buf + csize);
    309 					dumpbits(bits, (nchunks + 7) / 8);
    310 					tst_exit();
    311 				}
    312 				bits[chunk / 8] |= (1 << (chunk % 8));
    313 				++count;
    314 			} else {
    315 				++collide;
    316 				if (memcmp(buf, val_buf, csize)) {
    317 					tst_resm(TFAIL,
    318 						 "\t%s[%d] bad verify @ %d (%p) for val %d count %d.\n",
    319 						 prog, me, chunk, buf, val,
    320 						 count);
    321 					tst_resm(TINFO, "\tPrev ");
    322 					dumpbuf(buf - csize);
    323 					dumpbuf(buf);
    324 					tst_resm(TINFO, "\tNext ");
    325 					dumpbuf(buf + csize);
    326 					dumpbits(bits, (nchunks + 7) / 8);
    327 					tst_exit();
    328 				}
    329 			}
    330 
    331 			/*
    332 			 * Write it.
    333 			 */
    334 
    335 			bfill(buf, val, csize);
    336 
    337 			if (count + collide > 2 * nchunks)
    338 				break;
    339 		}
    340 
    341 		/*
    342 		 * End of iteration, maybe before doing all chunks.
    343 		 */
    344 #ifdef DEBUG
    345 		tst_resm(TINFO,
    346 			 "\t%s[%d] val %d done, count = %d, collide = %d.\n",
    347 			 prog, me, val, count, collide);
    348 #endif
    349 		for (chunk = 0; chunk < nchunks; chunk++) {
    350 			if ((bits[chunk / 8] & (1 << (chunk % 8))) == 0)
    351 				bfill(mondobuf + CHUNK(chunk), val, csize);
    352 		}
    353 		bfill(zero_buf, val, csize);
    354 		++val;
    355 	}
    356 
    357 	return 0;
    358 }
    359 
    360 void bfill(buf, val, size)
    361 register char *buf;
    362 char val;
    363 register int size;
    364 {
    365 	register int i;
    366 
    367 	for (i = 0; i < size; i++)
    368 		buf[i] = val;
    369 }
    370 
    371 /*
    372  * dumpbuf
    373  *	Dump the buffer.
    374  */
    375 
    376 int dumpbuf(buf)
    377 register char *buf;
    378 {
    379 	register int i;
    380 	char val;
    381 	int idx;
    382 	int nout;
    383 
    384 #ifdef DEBUG
    385 	tst_resm(TINFO, "Buf: ... ");
    386 	for (i = -10; i < 0; i++)
    387 		tst_resm(TINFO, "%x, ", buf[i]);
    388 	tst_resm(TINFO, "\n");
    389 #endif
    390 
    391 	nout = 0;
    392 	idx = 0;
    393 	val = buf[0];
    394 	for (i = 0; i < csize; i++) {
    395 		if (buf[i] != val) {
    396 #ifdef DEBUG
    397 			if (i == idx + 1)
    398 				tst_resm(TINFO, "%x, ", buf[idx] & 0xff);
    399 			else
    400 				tst_resm(TINFO, "%d*%x, ", i - idx,
    401 					 buf[idx] & 0xff);
    402 #endif
    403 			idx = i;
    404 			val = buf[i];
    405 			++nout;
    406 		}
    407 		if (nout > 10) {
    408 #ifdef DEBUG
    409 			tst_resm(TINFO, " ... more\n");
    410 #endif
    411 			return 0;
    412 		}
    413 	}
    414 #ifdef DEBUG
    415 	if (i == idx + 1)
    416 		tst_resm(TINFO, "%x\n", buf[idx] & 0xff);
    417 	else
    418 		tst_resm(TINFO, "%d*%x\n", i - idx, buf[idx]);
    419 #endif
    420 	return 0;
    421 }
    422 
    423 /*
    424  * dumpbits
    425  *	Dump the bit-map.
    426  */
    427 
    428 void dumpbits(bits, size)
    429 char *bits;
    430 register int size;
    431 {
    432 #ifdef DEBUG
    433 	register char *buf;
    434 
    435 	tst_resm(TINFO, "Bits array:");
    436 	for (buf = bits; size > 0; --size, ++buf) {
    437 		if ((buf - bits) % 16 == 0)
    438 			tst_resm(TINFO, "\n%04x:\t", 8 * (buf - bits));
    439 		tst_resm(TINFO, "%02x ", (int)*buf & 0xff);
    440 	}
    441 	tst_resm(TINFO, "\n");
    442 #endif
    443 }
    444 
    445 /* term()
    446  *
    447  *	Parent - kill kids and return when signal arrives.
    448  *	Child - exit.
    449  */
    450 int term()
    451 {
    452 #ifdef DEBUG
    453 	tst_resm(TINFO, "\tterm -[%d]- got sig term.\n", getpid());
    454 #endif
    455 
    456 	if (parent_pid == getpid()) {
    457 		massmurder();
    458 		return 0;
    459 	}
    460 
    461 	exit(0);
    462 }
    463 
    464 int chld()
    465 {
    466 	if (sigset(SIGUSR1, (void (*)())chld) == SIG_ERR) {
    467 		tst_resm(TBROK, "sigset shichld");
    468 		exit(1);
    469 	}
    470 	chld_flag++;
    471 	return 0;
    472 }
    473 
    474 int massmurder()
    475 {
    476 	int i;
    477 	for (i = 0; i < MAXCHILD; i++) {
    478 		if (allchild[i]) {
    479 			kill(allchild[i], SIGTERM);
    480 		}
    481 	}
    482 	return 0;
    483 }
    484 
    485 int okexit(me)
    486 int me;
    487 {
    488 	kill(parent_pid, SIGUSR1);
    489 	tst_resm(TINFO, "\tChild [%d] - cannot malloc buffer - exiting.\n", me);
    490 	if (me) {
    491 		tst_resm(TINFO, "\tThis is ok - probably swap space limit.\n");
    492 		tst_exit();
    493 	} else {
    494 		tst_brkm(TBROK,
    495 			 NULL,
    496 			 "\tThis is not ok for first child - check parameters.\n");
    497 	}
    498 
    499 	return 0;
    500 }
    501