Home | History | Annotate | Download | only in disktest
      1 /*
      2 * Disktest
      3 * Copyright (c) International Business Machines Corp., 2001
      4 *
      5 *
      6 * This program is free software; you can redistribute it and/or modify
      7 * it under the terms of the GNU General Public License as published by
      8 * the Free Software Foundation; either version 2 of the License, or
      9 * (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, write to the Free Software
     18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     19 *
     20 *  Please send e-mail to yardleyb (at) us.ibm.com if you have
     21 *  questions or comments.
     22 *
     23 *  Project Website:  TBD
     24 *
     25 * $Id: main.c,v 1.11 2009/02/26 12:14:53 subrata_modak Exp $
     26 *
     27 */
     28 #include <stdio.h>
     29 #ifdef WINDOWS
     30 #include <windows.h>
     31 #include <winioctl.h>
     32 #include <io.h>
     33 #include <process.h>
     34 #include <sys/stat.h>
     35 #include "getopt.h"
     36 #else
     37 #include <pthread.h>
     38 #include <sys/types.h>
     39 #include <unistd.h>
     40 #endif
     41 #include <stdlib.h>
     42 #include <stdarg.h>
     43 #include <stdint.h>
     44 #include <signal.h>
     45 #include <time.h>
     46 #include <errno.h>
     47 #include <fcntl.h>
     48 #include <string.h>
     49 #include <ctype.h>
     50 
     51 #include "defs.h"
     52 #include "globals.h"
     53 #include "main.h"
     54 #include "usage.h"
     55 #include "sfunc.h"
     56 #include "parse.h"
     57 #include "childmain.h"
     58 #include "threading.h"
     59 #include "dump.h"
     60 #include "timer.h"
     61 #include "stats.h"
     62 #include "signals.h"
     63 
     64 /* global */
     65 child_args_t cleanArgs;
     66 test_env_t cleanEnv;
     67 char hostname[HOSTNAME_SIZE];	/* global system hostname */
     68 
     69 void linear_read_write_test(test_ll_t * test)
     70 {
     71 	OFF_T *pVal1 = (OFF_T *) test->env->shared_mem;
     72 	int i;
     73 
     74 	if (test->args->flags & CLD_FLG_W) {
     75 		test->env->bContinue = TRUE;
     76 		*(pVal1 + OFF_WLBA) = test->args->start_lba;
     77 		test->args->test_state = DIRCT_INC(test->args->test_state);
     78 		test->env->lastAction.oper = WRITER;
     79 		test->args->test_state = SET_OPER_W(test->args->test_state);
     80 		test->args->test_state = SET_wFST_TIME(test->args->test_state);
     81 //              srand(test->args->seed);        /* reseed so we can re create the same random transfers */
     82 		memset(test->env->action_list, 0,
     83 		       sizeof(action_t) * test->args->t_kids);
     84 		test->env->action_list_entry = 0;
     85 		test->env->wcount = 0;
     86 		test->env->rcount = 0;
     87 		if (test->args->flags & CLD_FLG_CYC)
     88 			if (test->args->cycles == 0) {
     89 				pMsg(INFO, test->args,
     90 				     "Starting write pass, cycle %lu\n",
     91 				     (unsigned long)test->env->pass_count);
     92 			} else {
     93 				pMsg(INFO, test->args,
     94 				     "Starting write pass, cycle %lu of %lu\n",
     95 				     (unsigned long)test->env->pass_count,
     96 				     test->args->cycles);
     97 		} else {
     98 			pMsg(INFO, test->args, "Starting write pass\n");
     99 		}
    100 		CreateTestChild(ChildTimer, test);
    101 		for (i = 0; i < test->args->t_kids; i++) {
    102 			CreateTestChild(ChildMain, test);
    103 		}
    104 		/* Wait for the writers to finish */
    105 		cleanUpTestChildren(test);
    106 	}
    107 
    108 	/* If the write test failed don't start the read test */
    109 	if (!(TST_STS(test->args->test_state))) {
    110 		return;
    111 	}
    112 
    113 	if (test->args->flags & CLD_FLG_R) {
    114 		test->env->bContinue = TRUE;
    115 		*(pVal1 + OFF_RLBA) = test->args->start_lba;
    116 		test->args->test_state = DIRCT_INC(test->args->test_state);
    117 		test->env->lastAction.oper = READER;
    118 		test->args->test_state = SET_OPER_R(test->args->test_state);
    119 		test->args->test_state = SET_rFST_TIME(test->args->test_state);
    120 //              srand(test->args->seed);        /* reseed so we can re create the same random transfers */
    121 		memset(test->env->action_list, 0,
    122 		       sizeof(action_t) * test->args->t_kids);
    123 		test->env->action_list_entry = 0;
    124 		test->env->wcount = 0;
    125 		test->env->rcount = 0;
    126 		if (test->args->flags & CLD_FLG_CYC)
    127 			if (test->args->cycles == 0) {
    128 				pMsg(INFO, test->args,
    129 				     "Starting read pass, cycle %lu\n",
    130 				     (unsigned long)test->env->pass_count);
    131 			} else {
    132 				pMsg(INFO, test->args,
    133 				     "Starting read pass, cycle %lu of %lu\n",
    134 				     (unsigned long)test->env->pass_count,
    135 				     test->args->cycles);
    136 		} else {
    137 			pMsg(INFO, test->args, "Starting read pass\n");
    138 		}
    139 		CreateTestChild(ChildTimer, test);
    140 		for (i = 0; i < test->args->t_kids; i++) {
    141 			CreateTestChild(ChildMain, test);
    142 		}
    143 		/* Wait for the readers to finish */
    144 		cleanUpTestChildren(test);
    145 	}
    146 }
    147 
    148 unsigned long init_data(test_ll_t * test, unsigned char **data_buffer_unaligned)
    149 {
    150 	int i;
    151 	OFF_T *pVal1;
    152 
    153 	unsigned long data_buffer_size;
    154 
    155 #ifdef WINDOWS
    156 	if (CreateMutex(NULL, FALSE, "gbl") == NULL) {
    157 		pMsg(ERR, test->args,
    158 		     "Failed to create semaphore, error = %u\n",
    159 		     GetLastError());
    160 		return (GetLastError());
    161 	}
    162 	if ((test->env->mutexs.MutexACTION =
    163 	     CreateMutex(NULL, FALSE, NULL)) == NULL) {
    164 		pMsg(ERR, test->args,
    165 		     "Failed to create semaphore, error = %u\n",
    166 		     GetLastError());
    167 		return (GetLastError());
    168 	}
    169 	if ((test->env->mutexs.MutexIO =
    170 	     CreateMutex(NULL, FALSE, NULL)) == NULL) {
    171 		pMsg(ERR, test->args,
    172 		     "Failed to create semaphore, error = %u\n",
    173 		     GetLastError());
    174 		return (GetLastError());
    175 	}
    176 #else
    177 
    178 	mutexs_t mutexs =
    179 	    { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER };
    180 	test->env->mutexs = mutexs;
    181 
    182 #endif
    183 
    184 	if (test->args->seed == 0)
    185 		test->args->seed = test->args->pid;
    186 	srand(test->args->seed);
    187 
    188 	/* create bitmap to hold write/read context: each bit is an LBA */
    189 	/* the stuff before BMP_OFFSET is the data for child/thread shared context */
    190 	test->env->bmp_siz =
    191 	    (((((size_t) test->args->vsiz)) / 8) ==
    192 	     0) ? 1 : ((((size_t) test->args->vsiz)) / 8);
    193 	if ((test->args->vsiz / 8) != 0)
    194 		test->env->bmp_siz += 1;	/* account for rounding error */
    195 
    196 	/* We use that same data buffer for static data, so alloc here. */
    197 	data_buffer_size = ((test->args->htrsiz * BLK_SIZE) * 2);
    198 	if ((*data_buffer_unaligned =
    199 	     (unsigned char *)ALLOC(data_buffer_size + ALIGNSIZE)) == NULL) {
    200 		pMsg(ERR, test->args,
    201 		     "Failed to allocate static data buffer memory.\n");
    202 		return (-1);
    203 	}
    204 	/* create list to hold lbas currently be written */
    205 	if ((test->env->action_list =
    206 	     (action_t *) ALLOC(sizeof(action_t) * test->args->t_kids)) ==
    207 	    NULL) {
    208 		pMsg(ERR, test->args,
    209 		     "Failed to allocate static data buffer memory.\n");
    210 		return (-1);
    211 	}
    212 
    213 	test->env->data_buffer =
    214 	    (unsigned char *)BUFALIGN(*data_buffer_unaligned);
    215 
    216 	if ((test->env->shared_mem =
    217 	     (void *)ALLOC(test->env->bmp_siz + BMP_OFFSET)) == NULL) {
    218 		pMsg(ERR, test->args, "Failed to allocate bitmap memory\n");
    219 		return (-1);
    220 	}
    221 
    222 	memset(test->env->shared_mem, 0, test->env->bmp_siz + BMP_OFFSET);
    223 	memset(test->env->data_buffer, 0, data_buffer_size);
    224 	memset(test->env->action_list, 0,
    225 	       sizeof(action_t) * test->args->t_kids);
    226 	test->env->action_list_entry = 0;
    227 
    228 	pVal1 = (OFF_T *) test->env->shared_mem;
    229 	*(pVal1 + OFF_WLBA) = test->args->start_lba;
    230 	*(pVal1 + OFF_RLBA) = test->args->start_lba;
    231 	test->args->test_state = SET_STS_PASS(test->args->test_state);
    232 	test->args->test_state = SET_wFST_TIME(test->args->test_state);
    233 	test->args->test_state = SET_rFST_TIME(test->args->test_state);
    234 	test->args->test_state = DIRCT_INC(test->args->test_state);
    235 	if (test->args->flags & CLD_FLG_W) {
    236 		test->env->lastAction.oper = WRITER;
    237 		test->args->test_state = SET_OPER_W(test->args->test_state);
    238 	} else {
    239 		test->env->lastAction.oper = READER;
    240 		test->args->test_state = SET_OPER_R(test->args->test_state);
    241 	}
    242 
    243 	/* prefill the data buffer with data for compares and writes */
    244 	switch (test->args->flags & CLD_FLG_PTYPS) {
    245 	case CLD_FLG_FPTYPE:
    246 		for (i = 0; i < sizeof(test->args->pattern); i++) {
    247 			if ((test->args->
    248 			     pattern & (((OFF_T) 0xff) <<
    249 					(((sizeof(test->args->pattern) - 1) -
    250 					  i) * 8))) != 0)
    251 				break;
    252 		}
    253 		/* special case for pattern = 0 */
    254 		if (i == sizeof(test->args->pattern))
    255 			i = 0;
    256 		fill_buffer(test->env->data_buffer, data_buffer_size,
    257 			    &test->args->pattern,
    258 			    sizeof(test->args->pattern) - i, CLD_FLG_FPTYPE);
    259 		break;
    260 	case CLD_FLG_RPTYPE:
    261 		fill_buffer(test->env->data_buffer, data_buffer_size, NULL, 0,
    262 			    CLD_FLG_RPTYPE);
    263 		break;
    264 	case CLD_FLG_CPTYPE:
    265 		fill_buffer(test->env->data_buffer, data_buffer_size, 0, 0,
    266 			    CLD_FLG_CPTYPE);
    267 	case CLD_FLG_LPTYPE:
    268 		break;
    269 	default:
    270 		pMsg(WARN, test->args, "Unknown fill pattern\n");
    271 		return (-1);
    272 	}
    273 
    274 	return 0;
    275 }
    276 
    277 #ifdef WINDOWS
    278 DWORD WINAPI threadedMain(test_ll_t * test)
    279 #else
    280 void *threadedMain(void *vtest)
    281 #endif
    282 {
    283 #ifndef WINDOWS
    284 	test_ll_t *test = (test_ll_t *) vtest;
    285 #endif
    286 
    287 	OFF_T *pVal1;
    288 	unsigned char *data_buffer_unaligned = NULL;
    289 	unsigned long ulRV;
    290 	int i;
    291 	unsigned char *sharedMem;
    292 
    293 	extern unsigned short glb_run;
    294 	extern int signal_action;
    295 
    296 	test->args->pid = GETPID();
    297 
    298 	init_gbl_data(test->env);
    299 
    300 	if (make_assumptions(test->args) < 0) {
    301 		TEXIT((uintptr_t) GETLASTERROR());
    302 	}
    303 	if (check_conclusions(test->args) < 0) {
    304 		TEXIT((uintptr_t) GETLASTERROR());
    305 	}
    306 	if (test->args->flags & CLD_FLG_DUMP) {
    307 		/*
    308 		 * All we are doing is dumping filespec data to STDOUT, so
    309 		 * we will do this here and be done.
    310 		 */
    311 		do_dump(test->args);
    312 		TEXIT((uintptr_t) GETLASTERROR());
    313 	} else {
    314 		ulRV = init_data(test, &data_buffer_unaligned);
    315 		if (ulRV != 0) {
    316 			TEXIT(ulRV);
    317 		}
    318 		pVal1 = (OFF_T *) test->env->shared_mem;
    319 	}
    320 
    321 	pMsg(START, test->args, "Start args: %s\n", test->args->argstr);
    322 
    323 	/*
    324 	 * This loop takes care of passes
    325 	 */
    326 	do {
    327 		test->env->pass_count++;
    328 		test->env->start_time = time(NULL);
    329 		if (test->args->flags & CLD_FLG_RPTYPE) {	/* force random data to be different each cycle */
    330 			fill_buffer(test->env->data_buffer,
    331 				    ((test->args->htrsiz * BLK_SIZE) * 2), NULL,
    332 				    0, CLD_FLG_RPTYPE);
    333 		}
    334 		sharedMem = test->env->shared_mem;
    335 		memset(sharedMem + BMP_OFFSET, 0, test->env->bmp_siz);
    336 		if ((test->args->flags & CLD_FLG_LINEAR)
    337 		    && !(test->args->flags & CLD_FLG_NTRLVD)) {
    338 			linear_read_write_test(test);
    339 		} else {
    340 			/* we only reset the end time if not running a linear read / write test */
    341 			test->env->end_time =
    342 			    test->env->start_time + test->args->run_time;
    343 			test->env->bContinue = TRUE;
    344 			*(pVal1 + OFF_WLBA) = test->args->start_lba;
    345 			test->args->test_state =
    346 			    DIRCT_INC(test->args->test_state);
    347 			test->args->test_state =
    348 			    SET_wFST_TIME(test->args->test_state);
    349 			test->args->test_state =
    350 			    SET_rFST_TIME(test->args->test_state);
    351 			if (test->args->flags & CLD_FLG_W) {
    352 				test->env->lastAction.oper = WRITER;
    353 				test->args->test_state =
    354 				    SET_OPER_W(test->args->test_state);
    355 			} else {
    356 				test->env->lastAction.oper = READER;
    357 				test->args->test_state =
    358 				    SET_OPER_R(test->args->test_state);
    359 			}
    360 			memset(test->env->action_list, 0,
    361 			       sizeof(action_t) * test->args->t_kids);
    362 			test->env->action_list_entry = 0;
    363 			test->env->wcount = 0;
    364 			test->env->rcount = 0;
    365 
    366 			if (test->args->flags & CLD_FLG_CYC)
    367 				if (test->args->cycles == 0) {
    368 					pMsg(INFO, test->args,
    369 					     "Starting pass %lu\n",
    370 					     (unsigned long)test->env->
    371 					     pass_count);
    372 				} else {
    373 					pMsg(INFO, test->args,
    374 					     "Starting pass %lu of %lu\n",
    375 					     (unsigned long)test->env->
    376 					     pass_count, test->args->cycles);
    377 			} else {
    378 				pMsg(INFO, test->args, "Starting pass\n");
    379 			}
    380 
    381 			CreateTestChild(ChildTimer, test);
    382 			for (i = 0; i < test->args->t_kids; i++) {
    383 				CreateTestChild(ChildMain, test);
    384 			}
    385 			/* Wait for the children to finish */
    386 			cleanUpTestChildren(test);
    387 		}
    388 
    389 		update_cyc_stats(test->env);
    390 		if ((test->args->flags & CLD_FLG_CYC)
    391 		    && (test->args->flags & CLD_FLG_PCYC)) {
    392 			print_stats(test->args, test->env, CYCLE);
    393 		}
    394 		update_gbl_stats(test->env);
    395 
    396 		if (signal_action & SIGNAL_STOP) {
    397 			break;
    398 		}		/* user request to stop */
    399 		if ((glb_run == 0)) {
    400 			break;
    401 		}
    402 		/* global request to stop */
    403 		if (!(test->args->flags & CLD_FLG_CYC)) {
    404 			break;	/* leave, unless cycle testing */
    405 		} else {
    406 			if ((test->args->cycles > 0)
    407 			    && (test->env->pass_count >= test->args->cycles)) {
    408 				break;	/* leave, cycle testing complete */
    409 			}
    410 		}
    411 	} while (TST_STS(test->args->test_state));
    412 	print_stats(test->args, test->env, TOTAL);
    413 
    414 	FREE(data_buffer_unaligned);
    415 	FREE(test->env->shared_mem);
    416 #ifdef WINDOWS
    417 	CloseHandle(OpenMutex(SYNCHRONIZE, TRUE, "gbl"));
    418 	CloseHandle(OpenMutex(SYNCHRONIZE, TRUE, "data"));
    419 #endif
    420 
    421 	if (TST_STS(test->args->test_state)) {
    422 		if (signal_action & SIGNAL_STOP) {
    423 			pMsg(END, test->args,
    424 			     "User Interrupt: Test Done (Passed)\n");
    425 		} else {
    426 			pMsg(END, test->args, "Test Done (Passed)\n");
    427 		}
    428 	} else {
    429 		if (signal_action & SIGNAL_STOP) {
    430 			pMsg(END, test->args,
    431 			     "User Interrupt: Test Done (Failed)\n");
    432 		} else {
    433 			pMsg(END, test->args, "Test Done (Failed)\n");
    434 		}
    435 	}
    436 	TEXIT((uintptr_t) GETLASTERROR());
    437 }
    438 
    439 /*
    440  * Creates a new test structure and adds it to the list of
    441  * test structures already available.  Allocate all memory
    442  * needed by the new test.
    443  *
    444  * Returns the newly created test structure
    445  */
    446 test_ll_t *getNewTest(test_ll_t * testList)
    447 {
    448 	test_ll_t *pNewTest;
    449 
    450 	if ((pNewTest = (test_ll_t *) ALLOC(sizeof(test_ll_t))) == NULL) {
    451 		pMsg(ERR, &cleanArgs,
    452 		     "%d : Could not allocate memory for new test.\n",
    453 		     GETLASTERROR());
    454 		return NULL;
    455 	}
    456 
    457 	memset(pNewTest, 0, sizeof(test_ll_t));
    458 
    459 	if ((pNewTest->args =
    460 	     (child_args_t *) ALLOC(sizeof(child_args_t))) == NULL) {
    461 		pMsg(ERR, &cleanArgs,
    462 		     "%d : Could not allocate memory for new test.\n",
    463 		     GETLASTERROR());
    464 		FREE(pNewTest);
    465 		return NULL;
    466 	}
    467 	if ((pNewTest->env = (test_env_t *) ALLOC(sizeof(test_env_t))) == NULL) {
    468 		pMsg(ERR, &cleanArgs,
    469 		     "%d : Could not allocate memory for new test.\n",
    470 		     GETLASTERROR());
    471 		FREE(pNewTest->args);
    472 		FREE(pNewTest);
    473 		return NULL;
    474 	}
    475 	memcpy(pNewTest->args, &cleanArgs, sizeof(child_args_t));
    476 	memcpy(pNewTest->env, &cleanEnv, sizeof(test_env_t));
    477 
    478 	pNewTest->next = testList;
    479 	testList = pNewTest;
    480 	return pNewTest;
    481 }
    482 
    483 test_ll_t *run()
    484 {
    485 	test_ll_t *newTest = NULL, *lastTest = NULL;
    486 
    487 	if (cleanArgs.flags & CLD_FLG_FSLIST) {
    488 		char *filespec = cleanArgs.device;
    489 		char *aFilespec = NULL;
    490 		FILE *file = NULL;
    491 
    492 		if ((aFilespec = (char *)ALLOC(80)) == NULL) {
    493 			pMsg(ERR, &cleanArgs,
    494 			     "Could not allocate memory to read file");
    495 			return newTest;
    496 		}
    497 
    498 		file = fopen(filespec, "r");
    499 		if (file == NULL) {
    500 			pMsg(ERR,
    501 			     &cleanArgs,
    502 			     "%s is not a regular file, could not be opened for reading, or was not found.",
    503 			     filespec);
    504 			FREE(aFilespec);
    505 
    506 			return newTest;
    507 		}
    508 
    509 		while (!feof(file)) {
    510 			memset(aFilespec, 0, 80);
    511 			fscanf(file, "%79s", aFilespec);
    512 			if (aFilespec[0] != 0) {	/* if we read something useful */
    513 				lastTest = newTest;
    514 				newTest = getNewTest(lastTest);
    515 				if (newTest != lastTest) {
    516 					memset(newTest->args->device, 0,
    517 					       DEV_NAME_LEN);
    518 					strncpy(newTest->args->device,
    519 						aFilespec, strlen(aFilespec));
    520 					createChild(threadedMain, newTest);
    521 				} else {
    522 					newTest = lastTest;
    523 					break;
    524 				}
    525 			}
    526 		}
    527 
    528 		fclose(file);
    529 		FREE(aFilespec);
    530 	} else {
    531 		newTest = getNewTest(newTest);
    532 		if (newTest != NULL) {
    533 			createChild(threadedMain, newTest);
    534 		}
    535 	}
    536 
    537 	return newTest;
    538 }
    539 
    540 int main(int argc, char **argv)
    541 {
    542 	extern time_t global_start_time;
    543 	extern unsigned long glb_flags;	/* global flags GLB_FLG_xxx */
    544 	int i;
    545 
    546 #ifdef WINDOWS
    547 	WORD wVersionRequested;
    548 	WSADATA wsaData;
    549 	int err;
    550 
    551 	wVersionRequested = MAKEWORD(2, 2);
    552 
    553 	err = WSAStartup(wVersionRequested, &wsaData);
    554 	if (err != 0) {
    555 		pMsg(WARN, &cleanArgs,
    556 		     "Windows setup of Winsock failed, can't retrieve host name, continuing");
    557 	}
    558 #endif
    559 
    560 	setup_sig_mask();
    561 
    562 	memset(hostname, 0, HOSTNAME_SIZE);
    563 	gethostname(hostname, HOSTNAME_SIZE);
    564 
    565 	setbuf(stdout, NULL);
    566 
    567 	glb_flags = 0;
    568 	global_start_time = time(NULL);
    569 
    570 	strncpy(cleanArgs.device, "No filespec", strlen("No filespec"));
    571 	cleanArgs.stop_lba = -1;
    572 	cleanArgs.stop_blk = -1;
    573 	cleanArgs.ioTimeout = DEFAULT_IO_TIMEOUT;
    574 	cleanArgs.flags |= CLD_FLG_ALLDIE;
    575 	cleanArgs.flags |= CLD_FLG_ERR_REREAD;
    576 	cleanArgs.flags |= CLD_FLG_LBA_SYNC;
    577 
    578 	for (i = 1; i < argc - 1; i++) {
    579 		strncat(cleanArgs.argstr, argv[i],
    580 			(MAX_ARG_LEN - 1) - strlen(cleanArgs.argstr));
    581 		strncat(cleanArgs.argstr, " ",
    582 			(MAX_ARG_LEN - 1) - strlen(cleanArgs.argstr));
    583 	}
    584 
    585 	if (fill_cld_args(argc, argv, &cleanArgs) < 0)
    586 		exit(1);
    587 
    588 	cleanUp(run());
    589 
    590 #ifdef WINDOWS
    591 	WSACleanup();
    592 #endif
    593 
    594 	return 0;
    595 }
    596