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