static int flowop_create_runtime_flowops(threadflow_t *threadflow, flowop_t **ops_list_ptr) { flowop_t *flowop = *ops_list_ptr; char *name; while (flowop) { flowop_t *newflowop; if (flowop == *ops_list_ptr) *ops_list_ptr = NULL; newflowop = flowop_define_common(threadflow, flowop->fo_name, flowop, ops_list_ptr, 1, 0); if (newflowop == NULL) return (FILEBENCH_ERROR); /* check for fo_filename attribute, and resolve if present */ if (flowop->fo_filename) { name = avd_get_str(flowop->fo_filename); newflowop->fo_fileset = fileset_find(name); if (newflowop->fo_fileset == NULL) { filebench_log(LOG_ERROR, "flowop %s: file %s not found", newflowop->fo_name, name); filebench_shutdown(1); } } /* check for fo_possetname attribute, and resolve if present */ if (flowop->fo_possetname) { name = avd_get_str(flowop->fo_possetname); newflowop->fo_posset = posset_find(name); if (newflowop->fo_posset == NULL) { filebench_log(LOG_ERROR, "flowop %s: posset %s not found", newflowop->fo_name, name); filebench_shutdown(1); } } if (flowop_initflow(newflowop) < 0) { filebench_log(LOG_ERROR, "Flowop init of %s failed", newflowop->fo_name); } flowop = flowop->fo_exec_next; } return (FILEBENCH_OK); }
/* * Initialize mutex attributes for the various flavors of mutexes */ static void ipc_mutexattr_init(int mtx_type) { pthread_mutexattr_t *mtx_attrp; mtx_attrp = &(filebench_shm->shm_mutexattr[mtx_type]); (void) pthread_mutexattr_init(mtx_attrp); #ifdef USE_PROCESS_MODEL #ifdef HAVE_PROCSCOPE_PTHREADS if (pthread_mutexattr_setpshared(mtx_attrp, PTHREAD_PROCESS_SHARED) != 0) { filebench_log(LOG_ERROR, "cannot set mutex attr " "PROCESS_SHARED on this platform"); filebench_shutdown(1); } #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL if (mtx_type & IPC_MUTEX_PRIORITY) { if (pthread_mutexattr_setprotocol(mtx_attrp, PTHREAD_PRIO_INHERIT) != 0) { filebench_log(LOG_ERROR, "cannot set mutex attr " "PTHREAD_PRIO_INHERIT on this platform"); filebench_shutdown(1); } } #endif /* HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL */ #endif /* HAVE_PROCSCOPE_PTHREADS */ #ifdef HAVE_ROBUST_MUTEX if (mtx_type & IPC_MUTEX_ROBUST) { if (pthread_mutexattr_setrobust_np(mtx_attrp, PTHREAD_MUTEX_ROBUST_NP) != 0) { filebench_log(LOG_ERROR, "cannot set mutex attr " "PTHREAD_MUTEX_ROBUST_NP on this platform"); filebench_shutdown(1); } if (pthread_mutexattr_settype(mtx_attrp, PTHREAD_MUTEX_ERRORCHECK) != 0) { filebench_log(LOG_ERROR, "cannot set mutex attr " "PTHREAD_MUTEX_ERRORCHECK " "on this platform"); filebench_shutdown(1); } } #endif /* HAVE_ROBUST_MUTEX */ #endif /* USE_PROCESS_MODEL */ }
/* * Loops through the supplied list of flowops and creates and initializes * a flowop for each one by calling flowop_define. As a side effect of * calling flowop define, the created flowops are placed on the * master flowop list. All created flowops are set to instance "0". */ void flowop_flow_init(flowop_proto_t *list, int nops) { int i; for (i = 0; i < nops; i++) { flowop_t *flowop; flowop_proto_t *fl; fl = &(list[i]); if ((flowop = flowop_define(NULL, fl->fl_name, NULL, NULL, 0, fl->fl_type)) == 0) { filebench_log(LOG_ERROR, "failed to create flowop %s\n", fl->fl_name); filebench_shutdown(1); } flowop->fo_func = fl->fl_func; flowop->fo_init = fl->fl_init; flowop->fo_destruct = fl->fl_destruct; flowop->fo_attrs = fl->fl_attrs; } }
double get_cvar_value(cvar_t *cvar) { int ret; double value = 0.0; fbint_t round = cvar->round; ipc_mutex_lock(&cvar->cvar_lock); cvar_library_t *cvar_lib = cvar_libraries[cvar->cvar_lib_info->index]; ret = cvar_lib->cvar_op.cvar_next_value(cvar->cvar_handle, &value); ipc_mutex_unlock(&cvar->cvar_lock); if (ret) { filebench_log(LOG_ERROR, "Unable to get next_value from custom variable" " of type %s", cvar->cvar_lib_info->type); filebench_shutdown(1); } if (round) { fbint_t num, lower, upper; num = (fbint_t) value; lower = num - (num % round); upper = lower + round; value = (num - lower) > (upper - num) ? upper : lower; } if (value < cvar->min) value = cvar->min; else if (value > cvar->max) value = cvar->max; return value; }
/* * On first invocation, allocates a mutex attributes structure * and initializes it with appropriate attributes. In all cases, * returns a pointer to the structure. */ pthread_mutexattr_t * ipc_mutexattr(void) { #ifdef USE_PROCESS_MODEL if (mutexattr == NULL) { if ((mutexattr = malloc(sizeof (pthread_mutexattr_t))) == NULL) { filebench_log(LOG_ERROR, "cannot alloc mutex attr"); filebench_shutdown(1); } #ifdef HAVE_PROCSCOPE_PTHREADS (void) pthread_mutexattr_init(mutexattr); if (pthread_mutexattr_setpshared(mutexattr, PTHREAD_PROCESS_SHARED) != 0) { filebench_log(LOG_ERROR, "cannot set mutex attr " "PROCESS_SHARED on this platform"); filebench_shutdown(1); } #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL if (pthread_mutexattr_setprotocol(mutexattr, PTHREAD_PRIO_INHERIT) != 0) { filebench_log(LOG_ERROR, "cannot set mutex attr " "PTHREAD_PRIO_INHERIT on this platform"); filebench_shutdown(1); } #endif /* HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL */ #endif /* HAVE_PROCSCOPE_PTHREADS */ #ifdef HAVE_ROBUST_MUTEX if (pthread_mutexattr_setrobust_np(mutexattr, PTHREAD_MUTEX_ROBUST_NP) != 0) { filebench_log(LOG_ERROR, "cannot set mutex attr " "PTHREAD_MUTEX_ROBUST_NP on this platform"); filebench_shutdown(1); } if (pthread_mutexattr_settype(mutexattr, PTHREAD_MUTEX_ERRORCHECK) != 0) { filebench_log(LOG_ERROR, "cannot set mutex attr " "PTHREAD_MUTEX_ERRORCHECK on this platform"); filebench_shutdown(1); } #endif /* HAVE_ROBUST_MUTEX */ } #endif /* USE_PROCESS_MODEL */ return (mutexattr); }
/* * Returns the number of preallocated objects in the filebench_shm region */ static int preallocated_entries(int obj_type) { int entries; switch(obj_type) { case FILEBENCH_FILESET: entries = sizeof(filebench_shm->shm_fileset) / sizeof(fileset_t); break; case FILEBENCH_FILESETENTRY: entries = sizeof(filebench_shm->shm_filesetentry) / sizeof(filesetentry_t); break; case FILEBENCH_PROCFLOW: entries = sizeof(filebench_shm->shm_procflow) / sizeof(procflow_t); break; case FILEBENCH_THREADFLOW: entries = sizeof(filebench_shm->shm_threadflow) / sizeof(threadflow_t); break; case FILEBENCH_FLOWOP: entries = sizeof(filebench_shm->shm_flowop) / sizeof(flowop_t); break; case FILEBENCH_VARIABLE: entries = sizeof(filebench_shm->shm_var) / sizeof(var_t); break; case FILEBENCH_AVD: entries = sizeof(filebench_shm->shm_avd_ptrs) / sizeof(avd_t); break; case FILEBENCH_RANDDIST: entries = sizeof(filebench_shm->shm_randdist) / sizeof(randdist_t); break; case FILEBENCH_CVAR: entries = sizeof(filebench_shm->shm_cvar) / sizeof(cvar_t); break; case FILEBENCH_CVAR_LIB_INFO: entries = sizeof(filebench_shm->shm_cvar_lib_info) / sizeof(cvar_library_info_t); break; default: entries = -1; filebench_log(LOG_ERROR, "preallocated_entries: " "unknown object type"); filebench_shutdown(1); break; } return entries; }
/* * Initialize the urandom random number source */ void fb_random_init(void) { /* open the "urandom" random number device file */ if ((urandomfd = open("/dev/urandom", O_RDONLY)) < 0) { filebench_log(LOG_ERROR, "open /dev/urandom failed: %s", strerror(errno)); filebench_shutdown(1); } }
/* * On first invocation, allocates a condition variable attributes * structure and initializes it with appropriate attributes. In * all cases, returns a pointer to the structure. */ pthread_condattr_t * ipc_condattr(void) { #ifdef USE_PROCESS_MODEL if (condattr == NULL) { if ((condattr = malloc(sizeof (pthread_condattr_t))) == NULL) { filebench_log(LOG_ERROR, "cannot alloc cond attr"); filebench_shutdown(1); } #ifdef HAVE_PROCSCOPE_PTHREADS (void) pthread_condattr_init(condattr); if (pthread_condattr_setpshared(condattr, PTHREAD_PROCESS_SHARED) != 0) { filebench_log(LOG_ERROR, "cannot set cond attr PROCESS_SHARED"); filebench_shutdown(1); } #endif /* HAVE_PROCSCOPE_PTHREADS */ } #endif /* USE_PROCESS_MODEL */ return (condattr); }
/* * Allocates a semid from the table of semids for pre intialized * semaphores. Searches for the first available semaphore, and * sets the entry in the table to "1" to indicate allocation. * Returns the allocated semid. Stops the run if all semaphores * are already in use. */ int ipc_semidalloc(void) { int semid; for (semid = 0; filebench_shm->shm_semids[semid] == 1; semid++) ; if (semid == FILEBENCH_NSEMS) { filebench_log(LOG_ERROR, "Out of semaphores, increase system tunable limit"); filebench_shutdown(1); } filebench_shm->shm_semids[semid] = 1; return (semid); }
void init_random_my() { int urandomfd; int random_seed_my; urandomfd = open("/home/shubhamiit/random_seed", O_RDONLY); if (urandomfd < 0) { filebench_log(LOG_ERROR, "open /dev/urandom failed: %s", strerror(errno)); filebench_shutdown(1); } read (urandomfd,&random_seed_my,sizeof(random_seed_my)); printf("random seed: %d\n", random_seed_my); srand(random_seed_my); }
/* ARGSUSED */ static double rand_src_urandom(unsigned short *xi) { fbint_t randnum; if (read(urandomfd, &randnum, sizeof (fbint_t)) != sizeof (fbint_t)) { filebench_log(LOG_ERROR, "read /dev/urandom failed: %s", strerror(errno)); filebench_shutdown(1); return (0.0); } /* convert to 0-1 probability */ return ((double)randnum / (double)(FILEBENCH_RANDMAX64)); }
/* * Reads a 32 bit random number from the urandom "file". * Shuts down the run if the read fails. Otherwise returns * the random number after rounding it off by "round". * Returns 0 on success, -1 on failure. */ int filebench_randomno32(uint32_t *randp, uint32_t max, uint32_t round, avd_t avd) { uint32_t random; /* check for round value too large */ if (max <= round) { *randp = 0; /* if it just fits, its ok, otherwise error */ if (max == round) return (0); else return (-1); } if (avd) { /* get it from the variable */ random = (uint32_t)avd_get_int(avd); } else { /* get it from urandom */ if (read(urandomfd, &random, sizeof (uint32_t)) != sizeof (uint32_t)) { filebench_log(LOG_ERROR, "read /dev/urandom failed: %s", strerror(errno)); filebench_shutdown(1); } } /* clip with max and optionally round */ max -= round; random = random / (FILEBENCH_RANDMAX32 / max); if (round) { random = random / round; random *= round; } if (random > max) random = max; *randp = random; return (0); }
/* * Creates a thread for the supplied threadflow. If interprocess * shared memory is desired, then increments the amount of shared * memory needed by the amount specified in the threadflow's * tf_memsize parameter. The thread starts in routine * flowop_start() with a poineter to the threadflow supplied * as the argument. */ static int threadflow_createthread(threadflow_t *threadflow) { filebench_log(LOG_DEBUG_SCRIPT, "Creating thread %s, memory = %ld", threadflow->tf_name, *threadflow->tf_memsize); if (threadflow->tf_attrs & THREADFLOW_USEISM) filebench_shm->shm_required += (*threadflow->tf_memsize); if (pthread_create(&threadflow->tf_tid, NULL, (void *(*)(void*))flowop_start, threadflow) != 0) { filebench_log(LOG_ERROR, "thread create failed"); filebench_shutdown(1); return (FILEBENCH_ERROR); } return (FILEBENCH_OK); }
/* * On first invocation, allocates a condition variable attributes * structure and initializes it with appropriate attributes. In * all cases, returns a pointer to the structure. */ pthread_condattr_t * ipc_condattr(void) { if (condattr == NULL) { if ((condattr = malloc(sizeof (pthread_condattr_t))) == NULL) { filebench_log(LOG_ERROR, "cannot alloc cond attr"); filebench_shutdown(1); } (void) pthread_condattr_init(condattr); #ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED if (pthread_condattr_setpshared(condattr, PTHREAD_PROCESS_SHARED) != 0) { filebench_log(LOG_ERROR, "cannot set cond attr PROCESS_SHARED"); // filebench_shutdown(1); } #endif /* HAVE_PTHREAD_MUTEXATTR_SETPSHARED */ } return (condattr); }
/* * Calls semget() to get a set of shared system V semaphores. */ void ipc_seminit(void) { key_t key = filebench_shm->shm_semkey; int sys_semid; /* Already done? */ if (filebench_shm->shm_sys_semid >= 0) return; if ((sys_semid = semget(key, FILEBENCH_NSEMS, IPC_CREAT | S_IRUSR | S_IWUSR)) == -1) { filebench_log(LOG_ERROR, "could not create sysv semaphore set " "(need to increase sems?): %s", strerror(errno)); filebench_shutdown(1); } filebench_shm->shm_sys_semid = sys_semid; }
/* * On first invocation, allocates a readers/writers attributes * structure and initializes it with appropriate attributes. * In all cases, returns a pointer to the structure. */ static pthread_rwlockattr_t * ipc_rwlockattr(void) { if (rwlockattr == NULL) { if ((rwlockattr = malloc(sizeof (pthread_rwlockattr_t))) == NULL) { filebench_log(LOG_ERROR, "cannot alloc rwlock attr"); filebench_shutdown(1); } (void) pthread_rwlockattr_init(rwlockattr); #ifdef HAVE_PROCSCOPE_PTHREADS if (pthread_rwlockattr_setpshared(rwlockattr, PTHREAD_PROCESS_SHARED) != 0) { filebench_log(LOG_ERROR, "cannot set rwlock attr PROCESS_SHARED"); // filebench_shutdown(1); } #endif /* HAVE_PROCSCOPE_PTHREADS */ } return (rwlockattr); }
/* * Searches for the named var, and if found returns a pointer * to the var's var_integer. If not found, attempts to allocate * a var named "name" and returns a pointer to it's (zeroed) * var_integer. If the var cannot be found or allocated, an * error is logged and the run is terminated. */ vinteger_t * var_ref_integer(char *name) { var_t *var; name += 1; if ((var = var_find(name)) == NULL) var = var_find_dynamic(name); if (var == NULL) var = var_alloc(name); if (var == NULL) { filebench_log(LOG_ERROR, "Invalid variable $%s", name); filebench_shutdown(1); } return (&var->var_integer); }
/* * Initializes a random distribution entity, converting avd_t * parameters to doubles, and converting the list of probability density * function table entries, if supplied, into a probablilty function table */ static void randdist_init_one(randdist_t *rndp) { probtabent_t *rdte_hdp, *ptep; double tablemean, tablemin; int pteidx; /* convert parameters to doubles */ rndp->rnd_dbl_gamma = (double)avd_get_int(rndp->rnd_gamma) / 1000.0; if (rndp->rnd_mean != NULL) rndp->rnd_dbl_mean = (double)avd_get_int(rndp->rnd_mean); else rndp->rnd_dbl_mean = rndp->rnd_dbl_gamma; /* de-reference min and round amounts for later use */ rndp->rnd_vint_min = avd_get_int(rndp->rnd_min); rndp->rnd_vint_round = avd_get_int(rndp->rnd_round); filebench_log(LOG_DEBUG_IMPL, "init random var %s: Mean = %6.0llf, Gamma = %6.3llf, Min = %llu", rndp->rnd_var->var_name, rndp->rnd_dbl_mean, rndp->rnd_dbl_gamma, (u_longlong_t)rndp->rnd_vint_min); /* initialize distribution to apply */ switch (rndp->rnd_type & RAND_TYPE_MASK) { case RAND_TYPE_UNIFORM: rndp->rnd_get = rand_uniform_get; break; case RAND_TYPE_GAMMA: rndp->rnd_get = rand_gamma_get; break; case RAND_TYPE_TABLE: rndp->rnd_get = rand_table_get; break; default: filebench_log(LOG_DEBUG_IMPL, "Random Type not Specified"); filebench_shutdown(1); return; } /* initialize source of random numbers */ if (rndp->rnd_type & RAND_SRC_GENERATOR) { rndp->rnd_src = rand_src_rand48; rand_seed_set(rndp); } else { rndp->rnd_src = rand_src_urandom; } /* any random distribution table to convert? */ if ((rdte_hdp = rndp->rnd_probtabs) == NULL) return; /* determine random distribution max and mins and initialize table */ pteidx = 0; tablemean = 0.0; for (ptep = rdte_hdp; ptep; ptep = ptep->pte_next) { double dmin, dmax; int entcnt; dmax = (double)avd_get_int(ptep->pte_segmax); dmin = (double)avd_get_int(ptep->pte_segmin); /* initialize table minimum on first pass */ if (pteidx == 0) tablemin = dmin; /* update table minimum */ if (tablemin > dmin) tablemin = dmin; entcnt = (int)avd_get_int(ptep->pte_percent); tablemean += (((dmin + dmax)/2.0) * (double)entcnt); /* populate the lookup table */ for (; entcnt > 0; entcnt--) { rndp->rnd_rft[pteidx].rf_base = dmin; rndp->rnd_rft[pteidx].rf_range = dmax - dmin; pteidx++; } } /* check to see if probability equals 100% */ if (pteidx != PF_TAB_SIZE) filebench_log(LOG_ERROR, "Prob table only totals %d%%", pteidx); /* If table is not supplied with a mean value, set it to table mean */ if (rndp->rnd_dbl_mean == 0.0) rndp->rnd_dbl_mean = (double)tablemean / (double)PF_TAB_SIZE; /* now normalize the entries for a min value of 0, mean of 1 */ tablemean = (tablemean / 100.0) - tablemin; /* special case if really a constant value */ if (tablemean == 0.0) { for (pteidx = 0; pteidx < PF_TAB_SIZE; pteidx++) { rndp->rnd_rft[pteidx].rf_base = 0.0; rndp->rnd_rft[pteidx].rf_range = 0.0; } return; } for (pteidx = 0; pteidx < PF_TAB_SIZE; pteidx++) { rndp->rnd_rft[pteidx].rf_base = ((rndp->rnd_rft[pteidx].rf_base - tablemin) / tablemean); rndp->rnd_rft[pteidx].rf_range = (rndp->rnd_rft[pteidx].rf_range / tablemean); } }
/* * The final initialization and main execution loop for the * worker threads. Sets threadflow and flowop start times, * waits for all process to start, then creates the runtime * flowops from those defined by the F language workload * script. It does some more initialization, then enters a * loop to repeatedly execute the flowops on the flowop list * until an abort condition is detected, at which time it exits. * This is the starting routine for the new worker thread * created by threadflow_createthread(), and is not currently * called from anywhere else. */ void flowop_start(threadflow_t *threadflow) { flowop_t *flowop; size_t memsize; int ret = FILEBENCH_OK; set_thread_ioprio(threadflow); #ifdef HAVE_PROC_PID_LWP char procname[128]; long ctl[2] = {PCSET, PR_MSACCT}; int pfd; (void) snprintf(procname, sizeof (procname), "/proc/%d/lwp/%d/lwpctl", (int)my_pid, _lwp_self()); pfd = open(procname, O_WRONLY); (void) pwrite(pfd, &ctl, sizeof (ctl), 0); (void) close(pfd); #endif (void) ipc_mutex_lock(&controlstats_lock); if (!controlstats_zeroed) { (void) memset(&controlstats, 0, sizeof (controlstats)); controlstats_zeroed = 1; } (void) ipc_mutex_unlock(&controlstats_lock); flowop = threadflow->tf_thrd_fops; /* Hold the flowop find lock as reader to prevent lookups */ (void) pthread_rwlock_rdlock(&filebench_shm->shm_flowop_find_lock); /* Create the runtime flowops from those defined by the script */ (void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock); if (flowop_create_runtime_flowops(threadflow, &threadflow->tf_thrd_fops) != FILEBENCH_OK) { (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock); filebench_shutdown(1); return; } (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock); /* Release the find lock as reader to allow lookups */ (void) pthread_rwlock_unlock(&filebench_shm->shm_flowop_find_lock); /* Set to the start of the new flowop list */ flowop = threadflow->tf_thrd_fops; memsize = (size_t)threadflow->tf_constmemsize; /* If we are going to use ISM, allocate later */ if (threadflow->tf_attrs & THREADFLOW_USEISM) { threadflow->tf_mem = ipc_ismmalloc(memsize); } else { threadflow->tf_mem = malloc(memsize); } (void) memset(threadflow->tf_mem, 0, memsize); filebench_log(LOG_DEBUG_SCRIPT, "Thread allocated %d bytes", memsize); #ifdef HAVE_LWPS filebench_log(LOG_DEBUG_SCRIPT, "Thread %zx (%d) started", threadflow, _lwp_self()); #endif /* * Now we set tf_running flag to indicate to the main process * that the worker thread is running. However, the thread is * still not executing the workload, as it is blocked by the * shm_run_lock. Main thread will release this lock when all * threads set their tf_running flag to 1. */ threadflow->tf_abort = 0; threadflow->tf_running = 1; /* * Block until all processes have started, acting like * a barrier. The original filebench process initially * holds the run_lock as a reader, preventing any of the * threads from obtaining the writer lock, and hence * passing this point. Once all processes and threads * have been created, the original process unlocks * run_lock, allowing each waiting thread to lock * and then immediately unlock it, then begin running. */ (void) pthread_rwlock_wrlock(&filebench_shm->shm_run_lock); (void) pthread_rwlock_unlock(&filebench_shm->shm_run_lock); /* Main filebench worker loop */ while (ret == FILEBENCH_OK) { int i, count; /* Abort if asked */ if (threadflow->tf_abort || filebench_shm->shm_f_abort) break; /* Be quiet while stats are gathered */ if (filebench_shm->shm_bequiet) { (void) sleep(1); continue; } /* Take it easy until everyone is ready to go */ if (!filebench_shm->shm_procs_running) { (void) sleep(1); continue; } if (flowop == NULL) { filebench_log(LOG_ERROR, "flowop_read null flowop"); return; } /* Execute the flowop for fo_iters times */ count = (int)avd_get_int(flowop->fo_iters); for (i = 0; i < count; i++) { filebench_log(LOG_DEBUG_SCRIPT, "%s: executing flowop " "%s-%d", threadflow->tf_name, flowop->fo_name, flowop->fo_instance); ret = (*flowop->fo_func)(threadflow, flowop); /* * Return value FILEBENCH_ERROR means "flowop * failed, stop the filebench run" */ if (ret == FILEBENCH_ERROR) { filebench_log(LOG_ERROR, "%s-%d: flowop %s-%d failed", threadflow->tf_name, threadflow->tf_instance, flowop->fo_name, flowop->fo_instance); (void) ipc_mutex_lock(&threadflow->tf_lock); threadflow->tf_abort = 1; filebench_shm->shm_f_abort = FILEBENCH_ABORT_ERROR; (void) ipc_mutex_unlock(&threadflow->tf_lock); break; } /* * Return value of FILEBENCH_NORSC means "stop * the filebench run" if in "end on no work mode", * otherwise it indicates an error */ if (ret == FILEBENCH_NORSC) { (void) ipc_mutex_lock(&threadflow->tf_lock); threadflow->tf_abort = FILEBENCH_DONE; if (filebench_shm->shm_rmode == FILEBENCH_MODE_Q1STDONE) { filebench_shm->shm_f_abort = FILEBENCH_ABORT_RSRC; } else if (filebench_shm->shm_rmode != FILEBENCH_MODE_QALLDONE) { filebench_log(LOG_ERROR1, "WARNING! Run stopped early:\n " " flowop %s-%d could " "not obtain a file. Please\n " " reduce runtime, " "increase fileset entries " "($nfiles), or switch modes.", flowop->fo_name, flowop->fo_instance); filebench_shm->shm_f_abort = FILEBENCH_ABORT_ERROR; } (void) ipc_mutex_unlock(&threadflow->tf_lock); break; } /* * Return value of FILEBENCH_DONE means "stop * the filebench run without error" */ if (ret == FILEBENCH_DONE) { (void) ipc_mutex_lock(&threadflow->tf_lock); threadflow->tf_abort = FILEBENCH_DONE; filebench_shm->shm_f_abort = FILEBENCH_ABORT_DONE; (void) ipc_mutex_unlock(&threadflow->tf_lock); break; } /* * If we get here and the return is something other * than FILEBENCH_OK, it means a spurious code * was returned, so treat as major error. This * probably indicates a bug in the flowop. */ if (ret != FILEBENCH_OK) { filebench_log(LOG_ERROR, "Flowop %s unexpected return value = %d\n", flowop->fo_name, ret); filebench_shm->shm_f_abort = FILEBENCH_ABORT_ERROR; break; } } /* advance to next flowop */ flowop = flowop->fo_exec_next; /* but if at end of list, start over from the beginning */ if (flowop == NULL) { flowop = threadflow->tf_thrd_fops; threadflow->tf_stats.fs_count++; } } #ifdef HAVE_LWPS filebench_log(LOG_DEBUG_SCRIPT, "Thread %d exiting", _lwp_self()); #endif /* Tell flowops to destroy locally acquired state */ flowop_destruct_all_flows(threadflow); pthread_exit(&threadflow->tf_abort); }
/* * Given a fileset "fileset", create the associated files as * specified in the attributes of the fileset. The fileset is * rooted in a directory whose pathname is in fs_path. If the * directory exists, meaning that there is already a fileset, * and the fs_reuse attribute is false, then remove it and all * its contained files and subdirectories. Next, the routine * creates a root directory for the fileset. All the file type * filesetentries are cycled through creating as needed * their containing subdirectory trees in the filesystem and * creating actual files for fs_preallocpercent of them. The * created files are filled with fse_size bytes of unitialized * data. The routine returns -1 on errors, 0 on success. */ static int fileset_create(fileset_t *fileset) { filesetentry_t *entry; char path[MAXPATHLEN]; struct stat64 sb; int pickflags = FILESET_PICKUNIQUE | FILESET_PICKRESET; hrtime_t start = gethrtime(); int preallocated = 0; int reusing = 0; if (*fileset->fs_path == NULL) { filebench_log(LOG_ERROR, "%s path not set", fileset_entity_name(fileset)); return (-1); } #ifdef HAVE_RAW_SUPPORT /* treat raw device as special case */ if (fileset->fs_attrs & FILESET_IS_RAW_DEV) return (0); #endif /* HAVE_RAW_SUPPORT */ /* XXX Add check to see if there is enough space */ /* Remove existing */ (void) strcpy(path, *fileset->fs_path); (void) strcat(path, "/"); (void) strcat(path, fileset->fs_name); if ((stat64(path, &sb) == 0) && (strlen(path) > 3) && (strlen(*fileset->fs_path) > 2)) { if (!integer_isset(fileset->fs_reuse)) { char cmd[MAXPATHLEN]; (void) snprintf(cmd, sizeof (cmd), "rm -rf %s", path); (void) system(cmd); filebench_log(LOG_VERBOSE, "Removed any existing %s %s in %lld seconds", fileset_entity_name(fileset), fileset->fs_name, ((gethrtime() - start) / 1000000000) + 1); } else { /* we are re-using */ reusing = 1; filebench_log(LOG_VERBOSE, "Re-using %s %s on %s file system.", fileset_entity_name(fileset), fileset->fs_name, sb.st_fstype); } } (void) mkdir(path, 0755); /* make the filesets directory tree */ if (fileset_create_subdirs(fileset, path) == -1) return (-1); start = gethrtime(); filebench_log(LOG_VERBOSE, "Creating %s %s...", fileset_entity_name(fileset), fileset->fs_name); if (!integer_isset(fileset->fs_prealloc)) goto exit; while (entry = fileset_pick(fileset, pickflags, 0)) { int randno; pthread_t tid; pickflags = FILESET_PICKUNIQUE; entry->fse_flags &= ~FSE_EXISTS; randno = ((RAND_MAX * (100 - *(fileset->fs_preallocpercent))) / 100); /* entry doesn't need to be locked during initialization */ (void) ipc_mutex_unlock(&entry->fse_lock); if (rand() < randno) continue; preallocated++; if (reusing) entry->fse_flags |= FSE_REUSING; else entry->fse_flags &= (~FSE_REUSING); if (integer_isset(fileset->fs_paralloc)) { /* fire off a separate allocation thread */ (void) pthread_mutex_lock(¶lloc_lock); while (paralloc_count >= MAX_PARALLOC_THREADS) { (void) pthread_cond_wait( ¶lloc_cv, ¶lloc_lock); } if (paralloc_count < 0) { (void) pthread_mutex_unlock(¶lloc_lock); return (-1); } paralloc_count++; (void) pthread_mutex_unlock(¶lloc_lock); if (pthread_create(&tid, NULL, (void *(*)(void*))fileset_alloc_thread, entry) != 0) { filebench_log(LOG_ERROR, "File prealloc thread create failed"); filebench_shutdown(1); } } else { if (fileset_alloc_file(entry) == -1) return (-1); } } exit: filebench_log(LOG_VERBOSE, "Preallocated %d of %lld of %s %s in %lld seconds", preallocated, *(fileset->fs_entries), fileset_entity_name(fileset), fileset->fs_name, ((gethrtime() - start) / 1000000000) + 1); return (0); }