void *threadedMain(void *vtest) #endif { #ifndef WINDOWS test_ll_t *test = (test_ll_t *) vtest; #endif OFF_T *pVal1; unsigned char *data_buffer_unaligned = NULL; unsigned long ulRV; int i; unsigned char *sharedMem; extern unsigned short glb_run; extern int signal_action; test->args->pid = GETPID(); init_gbl_data(test->env); if (make_assumptions(test->args) < 0) { TEXIT((uintptr_t) GETLASTERROR()); } if (check_conclusions(test->args) < 0) { TEXIT((uintptr_t) GETLASTERROR()); } if (test->args->flags & CLD_FLG_DUMP) { /* * All we are doing is dumping filespec data to STDOUT, so * we will do this here and be done. */ do_dump(test->args); TEXIT((uintptr_t) GETLASTERROR()); } else { ulRV = init_data(test, &data_buffer_unaligned); if (ulRV != 0) { TEXIT(ulRV); } pVal1 = (OFF_T *) test->env->shared_mem; } pMsg(START, test->args, "Start args: %s\n", test->args->argstr); /* * This loop takes care of passes */ do { test->env->pass_count++; test->env->start_time = time(NULL); if (test->args->flags & CLD_FLG_RPTYPE) { /* force random data to be different each cycle */ fill_buffer(test->env->data_buffer, ((test->args->htrsiz * BLK_SIZE) * 2), NULL, 0, CLD_FLG_RPTYPE); } sharedMem = test->env->shared_mem; memset(sharedMem + BMP_OFFSET, 0, test->env->bmp_siz); if ((test->args->flags & CLD_FLG_LINEAR) && !(test->args->flags & CLD_FLG_NTRLVD)) { linear_read_write_test(test); } else { /* we only reset the end time if not running a linear read / write test */ test->env->end_time = test->env->start_time + test->args->run_time; test->env->bContinue = TRUE; *(pVal1 + OFF_WLBA) = test->args->start_lba; test->args->test_state = DIRCT_INC(test->args->test_state); test->args->test_state = SET_wFST_TIME(test->args->test_state); test->args->test_state = SET_rFST_TIME(test->args->test_state); if (test->args->flags & CLD_FLG_W) { test->env->lastAction.oper = WRITER; test->args->test_state = SET_OPER_W(test->args->test_state); } else { test->env->lastAction.oper = READER; test->args->test_state = SET_OPER_R(test->args->test_state); } memset(test->env->action_list, 0, sizeof(action_t) * test->args->t_kids); test->env->action_list_entry = 0; test->env->wcount = 0; test->env->rcount = 0; if (test->args->flags & CLD_FLG_CYC) if (test->args->cycles == 0) { pMsg(INFO, test->args, "Starting pass %lu\n", (unsigned long)test->env-> pass_count); } else { pMsg(INFO, test->args, "Starting pass %lu of %lu\n", (unsigned long)test->env-> pass_count, test->args->cycles); } else { pMsg(INFO, test->args, "Starting pass\n"); } CreateTestChild(ChildTimer, test); for (i = 0; i < test->args->t_kids; i++) { CreateTestChild(ChildMain, test); } /* Wait for the children to finish */ cleanUpTestChildren(test); } update_cyc_stats(test->env); if ((test->args->flags & CLD_FLG_CYC) && (test->args->flags & CLD_FLG_PCYC)) { print_stats(test->args, test->env, CYCLE); } update_gbl_stats(test->env); if (signal_action & SIGNAL_STOP) { break; } /* user request to stop */ if ((glb_run == 0)) { break; } /* global request to stop */ if (!(test->args->flags & CLD_FLG_CYC)) { break; /* leave, unless cycle testing */ } else { if ((test->args->cycles > 0) && (test->env->pass_count >= test->args->cycles)) { break; /* leave, cycle testing complete */ } } } while (TST_STS(test->args->test_state)); print_stats(test->args, test->env, TOTAL); FREE(data_buffer_unaligned); FREE(test->env->shared_mem); #ifdef WINDOWS CloseHandle(OpenMutex(SYNCHRONIZE, TRUE, "gbl")); CloseHandle(OpenMutex(SYNCHRONIZE, TRUE, "data")); #endif if (TST_STS(test->args->test_state)) { if (signal_action & SIGNAL_STOP) { pMsg(END, test->args, "User Interrupt: Test Done (Passed)\n"); } else { pMsg(END, test->args, "Test Done (Passed)\n"); } } else { if (signal_action & SIGNAL_STOP) { pMsg(END, test->args, "User Interrupt: Test Done (Failed)\n"); } else { pMsg(END, test->args, "Test Done (Failed)\n"); } } TEXIT((uintptr_t) GETLASTERROR()); }
/* * checks validity of data after parsing * args and make assumtions. returns 0 on * success and -1 on failure. */ int check_conclusions(child_args_t * args) { extern unsigned long glb_flags; struct stat stat_buf; int rv; if ((args->flags & CLD_FLG_DUTY) && ((args->flags & CLD_FLG_LINEAR) || (args->flags & CLD_FLG_NTRLVD))) { pMsg(WARN, args, "Duty cycle testing is supported for random (-pR) tests only.\n"); return (-1); } if ((args->flags & CLD_FLG_BLK_RNG) && (args->flags & CLD_FLG_RTRSIZ)) { pMsg(WARN, args, "Can't have unfixed block sizes and specify seek range in terms of blocks.\n"); return (-1); } if ((args->vsiz < 0) || (args->ltrsiz < 1) || (args->htrsiz < 1)) { pMsg(WARN, args, "Bounds exceeded for transfer size and/or volume size.\n"); pMsg(WARN, args, MAXTRSIZ, (args->htrsiz * BLK_SIZE), args->vsiz); return (-1); } if (args->htrsiz < args->ltrsiz) { pMsg(ERR, args, "Min transfer size, %lu, greater then Max transfer size, %lu.\n", args->ltrsiz, args->htrsiz); return (-1); } if (args->vsiz < (args->stop_lba - args->start_lba + 1)) { pMsg(ERR, args, "Volume stop block/lba exceeds volume size.\n"); return (-1); } if (args->vsiz < args->htrsiz) { pMsg(WARN, args, VSIZETS, args->vsiz, args->htrsiz); return (-1); } if ((args->flags & CLD_FLG_TMD) == 0 && (args->seeks <= 0)) { pMsg(WARN, args, TSEEK, args->seeks); return (-1); } if ((args->flags & CLD_FLG_SKS) && (args->t_kids > args->seeks)) { pMsg(WARN, args, "Can't have more children then max number of seeks, use -K/-L to adjust.\n"); return (-1); } if ((args->start_blk > args->vsiz) && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) { pMsg(WARN, args, STBGTTLBA, args->start_blk, (args->vsiz / args->htrsiz)); return (-1); } if ((args->stop_blk > args->vsiz) && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) { pMsg(WARN, args, SBGTTLBA, args->stop_blk, (args->vsiz / args->htrsiz)); return (-1); } if ((args->start_lba > args->vsiz) && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) { pMsg(WARN, args, STLBAGTLBA, args->start_lba, args->vsiz); return (-1); } if ((args->stop_lba > args->vsiz) && !(args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG))) { pMsg(WARN, args, SLBAGTLBA, args->stop_lba, args->vsiz); return (-1); } if (args->start_blk > args->stop_blk) { pMsg(WARN, args, SBRSB, args->stop_blk, args->start_blk); return (-1); } if (args->start_lba > args->stop_lba) { pMsg(ERR, args, SLBARSLBA, args->stop_lba, args->start_lba); return (-1); } if ((args->flags & CLD_FLG_LBA_RNG) && (args->flags & CLD_FLG_BLK_RNG)) { pMsg(ERR, args, "Can't specify range in both block and LBA, use -s or -S.\n"); return (-1); } /* use stat to get file properties, and test then agains specified -I */ rv = stat(args->device, &stat_buf); if (0 == rv) { /* no error on call to stat, compare against -I option */ /* files are usually file type */ if ((args->flags & CLD_FLG_FILE) && !IS_FILE(stat_buf.st_mode)) { pMsg(ERR, args, "Can't open non-file filespec with file device type, -If.\n"); return (-1); } /* block devices, are usually block type */ if ((args->flags & CLD_FLG_BLK) && !IS_BLK(stat_buf.st_mode)) { pMsg(ERR, args, "Can't open non-block filespec with block device type, -Ib.\n"); return (-1); } #ifndef WINDOWS /* raw devices, are usually character type */ if ((args->flags & CLD_FLG_RAW) && !S_ISCHR(stat_buf.st_mode)) { pMsg(ERR, args, "Can't open non-raw filespec with raw device type, -Ir.\n"); return (-1); } #else if (args->flags & CLD_FLG_RAW) { pMsg(ERR, args, "RAW IO type not supported in Windows, use direct IO instead.\n"); return (-1); } #endif #ifdef _DEBUG } else { PDBG1(DBUG, args, "Can't get status on %s, assuming a new file, errno = %d\n", args->device, GETLASTERROR()); #endif } if ((args->hbeat > 0) && (args->flags & CLD_FLG_TMD) && (args->hbeat > args->run_time)) { pMsg(ERR, args, "Heartbeat should be at least equal to runtime, use -h/-T to adjust.\n"); return (-1); } if ((args->hbeat > 0) && !(args->flags & CLD_FLG_PRFTYPS)) { pMsg(ERR, args, "At least one performance option, -P, must be specified when using -h.\n"); return (-1); } if ((args->flags & CLD_FLG_W) && !(args->flags & CLD_FLG_R) && (args->flags & CLD_FLG_CMPR)) { pMsg(ERR, args, "Write only, ignoring option -E.\n"); } if ((args->flags & CLD_FLG_TMD) && (args->flags & CLD_FLG_SKS)) { pMsg(ERR, args, "Can't specify both -L and -T they are mutually exclusive.\n"); return (-1); } if (((args->flags & CLD_FLG_R) && !(args->flags & CLD_FLG_W)) && (args->flags & CLD_FLG_ERR_MARK)) { pMsg(ERR, args, "Can't specify mark on error, -Am, in read only mode.\n"); return (-1); } if (!(args->flags & CLD_FLG_ALLDIE) && (args->flags & CLD_FLG_ERR_MARK)) { pMsg(ERR, args, "Can't specify mark on error, -Am, when continue on error is set.\n"); return (-1); } if ((glb_flags & GLB_FLG_KILL) && !(args->flags & CLD_FLG_ALLDIE)) { pMsg(ERR, args, "Can't specify global kill, -Ag, when continue on error is set, -Ac.\n"); return (-1); } if ((args->flags & CLD_FLG_LINEAR) && !(args->flags & CLD_FLG_NTRLVD) && (args->flags & CLD_FLG_TMD)) { pMsg(ERR, args, "Linear read / write test can not be timed.\n"); return (-1); } if ((args->flags & CLD_FLG_CMPR) && (args->cmp_lng > (args->ltrsiz * BLK_SIZE))) { pMsg(ERR, args, "Compare length, %lu, is greater then transfer size, %lu\n", args->cmp_lng, args->ltrsiz * BLK_SIZE); return (-1); } if ((args->flags & CLD_FLG_OFFSET) && (args->offset > args->stop_lba)) { pMsg(ERR, args, LBAOFFGSLBA, args->offset, args->stop_lba); return (-1); } if ((args->flags & CLD_FLG_OFFSET) && ((args->offset + args->ltrsiz - 1) > args->stop_lba)) { pMsg(ERR, args, LBAOTSGSLBA, args->offset, args->ltrsiz, args->stop_lba); return (-1); } return 0; }
void *ChildTimer(void *vtest) #endif { #ifndef WINDOWS test_ll_t *test = (test_ll_t *) vtest; #endif time_t ioTimeoutCount = 0; time_t total_time = 0; OFF_T cur_total_io_count = 0; OFF_T last_total_io_count = 0; OFF_T tmp_io_count = 0; time_t run_time = 0; lvl_t msg_level = WARN; child_args_t *args = test->args; test_env_t *env = test->env; extern int signal_action; extern unsigned short glb_run; #ifdef _DEBUG PDBG3(DBUG, args, "In timer %lu, %d\n", time(NULL), env->bContinue); #endif do { Sleep(1000); run_time++; #ifdef _DEBUG PDBG3(DBUG, args, "Continue timing %lu, %lu, %d\n", time(NULL), run_time, env->bContinue); #endif if (args->flags & CLD_FLG_W) { if ((args->flags & CLD_FLG_LINEAR) && !(args->flags & CLD_FLG_NTRLVD)) { if (TST_OPER(args->test_state) == WRITER) { env->hbeat_stats.wtime++; } } else { env->hbeat_stats.wtime++; } } if (args->flags & CLD_FLG_R) { if ((args->flags & CLD_FLG_LINEAR) && !(args->flags & CLD_FLG_NTRLVD)) { if (TST_OPER(args->test_state) == READER) { env->hbeat_stats.rtime++; } } else { env->hbeat_stats.rtime++; } } /* * Check to see if we have made any IO progress in the last interval, * if not incremment the ioTimeout timer, otherwise, clear it */ cur_total_io_count = env->global_stats.wcount + env->cycle_stats.wcount + env->hbeat_stats.wcount + env->global_stats.rcount + env->cycle_stats.rcount + env->hbeat_stats.rcount; if (cur_total_io_count == 0) { tmp_io_count = 1; } else { tmp_io_count = cur_total_io_count; } total_time = env->global_stats.rtime + env->cycle_stats.rtime + env->hbeat_stats.rtime + env->global_stats.wtime + env->cycle_stats.wtime + env->hbeat_stats.wtime; #ifdef _DEBUG PDBG3(DBUG, args, "average number of seconds per IO: %0.8lf\n", ((double)(total_time) / (double)(tmp_io_count))); #endif if (cur_total_io_count == last_total_io_count) { /* no IOs completed in interval */ if (0 == (++ioTimeoutCount % args->ioTimeout)) { /* no progress after modulo ioTimeout interval */ if (args->flags & CLD_FLG_TMO_ERROR) { args->test_state = SET_STS_FAIL(args->test_state); env->bContinue = FALSE; msg_level = ERR; } pMsg(msg_level, args, "Possible IO hang condition, IO timeout reached, %lu seconds\n", args->ioTimeout); } #ifdef _DEBUG PDBG3(DBUG, args, "io timeout count: %lu\n", ioTimeoutCount); #endif } else { ioTimeoutCount = 0; last_total_io_count = cur_total_io_count; #ifdef _DEBUG PDBG3(DBUG, args, "io timeout reset\n"); #endif } if (((args->hbeat > 0) && ((run_time % args->hbeat) == 0)) || (signal_action & SIGNAL_STAT)) { print_stats(args, env, HBEAT); update_cyc_stats(env); clear_stat_signal(); } if (glb_run == 0) { break; } /* global run flag cleared */ if (signal_action & SIGNAL_STOP) { break; } /* 超过设定的时间 */ /* user request to stop */ if (args->flags & CLD_FLG_TMD) { /* if timing */ if (run_time >= args->run_time) { /* and run time exceeded */ break; } } else { /* if not timing */ if (env->kids <= 1) { /* and the timer is the only child */ break; } } } while (TRUE); #ifdef _DEBUG PDBG3(DBUG, args, "Out of timer %lu, %lu, %d, %d\n", time(NULL), run_time, env->bContinue, env->kids); #endif if (args->flags & CLD_FLG_TMD) { /* timed test, timer exit needs to stop io threads */ #ifdef _DEBUG PDBG3(DBUG, args, "Setting bContinue to FALSE, timed test & timer exit\n"); #endif /* 设置此值,使工作线程不工作 */ env->bContinue = FALSE; } TEXIT((uintptr_t) GETLASTERROR()); }
int make_assumptions(child_args_t * args) { char TmpStr[80]; struct stat stat_buf; int rv; if (!(args->flags & CLD_FLG_IOTYPS)) { /* use stat to get file properties, and use to set -I */ rv = stat(args->device, &stat_buf); if (0 == rv) { if (IS_FILE(stat_buf.st_mode)) { strncat(args->argstr, "(-I f) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_FILE; } else if (IS_BLK(stat_buf.st_mode)) { strncat(args->argstr, "(-I b) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_BLK; #ifndef WINDOWS } else if (S_ISCHR(stat_buf.st_mode)) { strncat(args->argstr, "(-I r) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_RAW; #endif } } else { pMsg(WARN, args, "Can't get status on %s, defaulting to file, errno = %d\n", args->device, GETLASTERROR()); strncat(args->argstr, "(-I f) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_FILE; } } if ((args->flags & CLD_FLG_WFSYNC) && (0 == args->sync_interval)) { pMsg(INFO, args, "Sync interval set to zero, assuming interval of 1.\n"); args->sync_interval = 1; } if (args->ltrsiz <= 0) { sprintf(TmpStr, "(-B %d) ", TRSIZ * BLK_SIZE); strncat(args->argstr, TmpStr, (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->ltrsiz = TRSIZ; args->htrsiz = TRSIZ; } if (args->flags & CLD_FLG_LBA_RNG) { args->start_blk = args->start_lba / args->htrsiz; if (!(args->stop_lba < 0)) args->stop_blk = args->stop_lba / args->htrsiz; } if (args->flags & CLD_FLG_BLK_RNG) { args->start_lba = args->start_blk * args->htrsiz; if (!(args->stop_blk < 0)) args->stop_lba = (args->stop_blk * args->htrsiz) + (args->htrsiz - 1); } /* if vsiz is still not set, try and get it from the file */ if ((args->vsiz <= 0) && (args->flags & CLD_FLG_FILE)) { if (0 != get_file_size(args->device)) { /* file size retrieved */ args->vsiz = get_file_size(args->device); } } /* if vsiz is still not set, try and get it from the device */ if ((args->vsiz <= 0) && !(args->flags & CLD_FLG_FILE)) { args->vsiz = get_vsiz(args->device); } /* if vsiz is still not set, set based on given range */ if ((args->vsiz <= 0) && (args->flags & (CLD_FLG_LBA_RNG | CLD_FLG_BLK_RNG))) { if (!(args->stop_lba < 0)) args->vsiz = args->stop_lba + 1; else args->vsiz = args->start_lba + 1; } /* if vsiz is still not set, then set it to the default size */ if (args->vsiz <= 0) { args->vsiz = VSIZ; } if (!(args->flags & CLD_FLG_VSIZ)) { sprintf(TmpStr, N_ASSUME, args->vsiz); strncat(args->argstr, TmpStr, (MAX_ARG_LEN - 1) - strlen(args->argstr)); } if (args->stop_lba == -1) { args->stop_lba = args->vsiz - 1; } if (args->stop_blk == -1) { args->stop_blk = (args->stop_lba / (OFF_T) args->htrsiz); } if (args->t_kids == 0) { sprintf(TmpStr, "(-K %d) ", KIDS); strncat(args->argstr, TmpStr, (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->t_kids = KIDS; } if ((args->flags & (CLD_FLG_W | CLD_FLG_R)) == 0) { if (args->flags & CLD_FLG_DUTY) { /* no read/write but duty cycle specified */ if (args->rperc > 0) { args->flags |= CLD_FLG_R; strncat(args->argstr, "(-r) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); } if (args->wperc > 0) { args->flags |= CLD_FLG_W; strncat(args->argstr, "(-w) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); } } else { strncat(args->argstr, "(-r) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_R; } } if (!(args->flags & CLD_FLG_PTYPS)) { strncat(args->argstr, "(-c) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_CPTYPE; } if (!(args->flags & CLD_FLG_SKTYPS)) { strncat(args->argstr, "(-p R) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_RANDOM; } if (!(args->flags & CLD_FLG_SKS)) { if (args->start_blk == args->stop_blk) { /* diskcache test, w/ no seek count set */ args->seeks = SEEKS; } else if (args->flags & (CLD_FLG_BLK_RNG | CLD_FLG_LBA_RNG)) { /* range set, w/ no seek count */ args->seeks = args->stop_blk - args->start_blk + 1; } else { /* if vsiz is available, calculated seeks are in terms of the largest transfer size */ args->seeks = (args->vsiz > 0) ? (args->vsiz / args->htrsiz) : SEEKS; } if ((args->flags & CLD_FLG_LINEAR) && (args->flags & CLD_FLG_R) && (args->flags & CLD_FLG_W)) { args->seeks *= 2; } if (!(args->flags & CLD_FLG_TMD)) { sprintf(TmpStr, L_ASSUME, args->seeks); strncat(args->argstr, TmpStr, (MAX_ARG_LEN - 1) - strlen(args->argstr)); } } if (!(args->flags & (CLD_FLG_SKS | CLD_FLG_TMD)) || ((args->flags & CLD_FLG_CYC) && !(args->flags & (CLD_FLG_SKS | CLD_FLG_TMD)))) { args->flags |= CLD_FLG_SKS; } if (args->flags & (CLD_FLG_LINEAR)) { if (!(args->flags & (CLD_FLG_LUNU | CLD_FLG_LUND))) { strncat(args->argstr, "(-p u) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_LUNU; } } normalize_percs(args); if (!(args->flags & CLD_FLG_DUTY) && (args->flags & CLD_FLG_RANDOM) && !(args->flags & CLD_FLG_NTRLVD)) { sprintf(TmpStr, "(-D %d:%d) ", args->rperc, args->wperc); strncat(args->argstr, TmpStr, (MAX_ARG_LEN - 1) - strlen(args->argstr)); args->flags |= CLD_FLG_DUTY; } if ((args->delayTimeMin == 0) && (args->delayTimeMax == 0) && (args->ioTimeout == DEFAULT_IO_TIMEOUT)) { strncat(args->argstr, "(-t 0:2m) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); } if (!(args->flags & CLD_FLG_OFFSET)) { strncat(args->argstr, "(-o 0) ", (MAX_ARG_LEN - 1) - strlen(args->argstr)); } return 0; }