void flowop_init(void) { (void) pthread_mutex_init(&controlstats_lock, ipc_mutexattr(IPC_MUTEX_NORMAL)); flowoplib_flowinit(); }
/* * Obtaines a filesetentry entity for a file to be placed in a * (sub)directory of a fileset. The size of the file may be * specified by fs_meansize, or calculated from a gamma * distribution of parameter fs_sizegamma and of mean size * fs_meansize. The filesetentry entity is placed on the file * list in the specified parent filesetentry entity, which may * be a directory filesetentry, or the root filesetentry in the * fileset. It is also placed on the fileset's list of all * contained files. Returns 0 if successful or -1 if ipc memory * for the path string cannot be allocated. */ static int fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) { char tmpname[16]; filesetentry_t *entry; double drand; double gamma; if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_file: Can't malloc filesetentry"); return (-1); } (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr()); entry->fse_parent = parent; entry->fse_fileset = fileset; entry->fse_flags |= FSE_FREE; fileset_insfilelist(fileset, entry); (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_file: Can't alloc path string"); return (-1); } gamma = *(fileset->fs_sizegamma) / 1000.0; if (gamma > 0) { drand = gamma_dist_knuth(gamma, fileset->fs_meansize / gamma); entry->fse_size = (off64_t)drand; } else { entry->fse_size = (off64_t)fileset->fs_meansize; } fileset->fs_bytes += entry->fse_size; fileset->fs_realfiles++; return (0); }
/* * Create an in-memory thread object linked to a parent procflow. * A threadflow entity is allocated from shared memory and * initialized from the "inherit" threadflow if supplied, * otherwise to zeros. The threadflow is assigned a unique * thread id, the supplied instance number, the supplied name * and added to the procflow's pf_thread list. If no name is * supplied or the threadflow can't be allocated, NULL is * returned Otherwise a pointer to the newly allocated threadflow * is returned. * * The filebench_shm->shm_threadflow_lock must be held by the caller. */ static threadflow_t * threadflow_define_common(procflow_t *procflow, char *name, threadflow_t *inherit, int instance) { threadflow_t *threadflow; threadflow_t **threadlistp = &procflow->pf_threads; if (name == NULL) return (NULL); threadflow = (threadflow_t *)ipc_malloc(FILEBENCH_THREADFLOW); if (threadflow == NULL) return (NULL); if (inherit) (void) memcpy(threadflow, inherit, sizeof (threadflow_t)); else (void) memset(threadflow, 0, sizeof (threadflow_t)); threadflow->tf_utid = ++filebench_shm->shm_utid; threadflow->tf_instance = instance; (void) strcpy(threadflow->tf_name, name); threadflow->tf_process = procflow; (void) pthread_mutex_init(&threadflow->tf_lock, ipc_mutexattr(IPC_MUTEX_NORMAL)); filebench_log(LOG_DEBUG_IMPL, "Defining thread %s-%d", name, instance); /* Add threadflow to list */ if (*threadlistp == NULL) { *threadlistp = threadflow; threadflow->tf_next = NULL; } else { threadflow->tf_next = *threadlistp; *threadlistp = threadflow; } return (threadflow); }
/* * Allocates a flowop entity and initializes it with inherited * contents from the "inherit" flowop, if it is supplied, or * with zeros otherwise. In either case the fo_next and fo_exec_next * pointers are set to NULL, and fo_thread is set to point to * the owning threadflow. The initialized flowop is placed at * the head of the global flowop list, and also placed on the * tail of the supplied local flowop list, which will either * be a threadflow's tf_thrd_fops list or a composite flowop's * fo_comp_fops list. The routine locks the flowop's fo_lock and * leaves it held on return. If successful, it returns a pointer * to the allocated and initialized flowop, otherwise it returns NULL. * * filebench_shm->shm_flowop_lock must be held by caller. */ static flowop_t * flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit, flowop_t **flowoplist_hdp, int instance, int type) { flowop_t *flowop; if (name == NULL) return (NULL); if ((flowop = (flowop_t *)ipc_malloc(FILEBENCH_FLOWOP)) == NULL) { filebench_log(LOG_ERROR, "flowop_define: Can't malloc flowop"); return (NULL); } filebench_log(LOG_DEBUG_IMPL, "defining flowops %s-%d, addr %zx", name, instance, flowop); if (flowop == NULL) return (NULL); if (inherit) { (void) memcpy(flowop, inherit, sizeof (flowop_t)); (void) pthread_mutex_init(&flowop->fo_lock, ipc_mutexattr(IPC_MUTEX_PRI_ROB)); (void) ipc_mutex_lock(&flowop->fo_lock); flowop->fo_next = NULL; flowop->fo_exec_next = NULL; filebench_log(LOG_DEBUG_IMPL, "flowop %s-%d calling init", name, instance); } else { (void) memset(flowop, 0, sizeof (flowop_t)); flowop->fo_iters = avd_int_alloc(1); flowop->fo_type = type; (void) pthread_mutex_init(&flowop->fo_lock, ipc_mutexattr(IPC_MUTEX_PRI_ROB)); (void) ipc_mutex_lock(&flowop->fo_lock); } /* Create backpointer to thread */ flowop->fo_thread = threadflow; /* Add flowop to global list */ if (filebench_shm->shm_flowoplist == NULL) { filebench_shm->shm_flowoplist = flowop; flowop->fo_next = NULL; } else { flowop->fo_next = filebench_shm->shm_flowoplist; filebench_shm->shm_flowoplist = flowop; } (void) strcpy(flowop->fo_name, name); flowop->fo_instance = instance; if (flowoplist_hdp == NULL) return (flowop); /* Add flowop to thread op list */ if (*flowoplist_hdp == NULL) { *flowoplist_hdp = flowop; flowop->fo_exec_next = NULL; } else { flowop_t *flowend; /* Find the end of the thread list */ flowend = *flowoplist_hdp; while (flowend->fo_exec_next != NULL) flowend = flowend->fo_exec_next; flowend->fo_exec_next = flowop; flowop->fo_exec_next = NULL; } return (flowop); }
/* * Initialize the Interprocess Communication system and its associated shared * memory structure. It first creates a temporary file using the mkstemp() * function. It than sets the file large enough to hold the filebench_shm and an * additional megabyte. (Additional megabyte is required to make sure that all * sizeof(filebench_shm) bytes plus page alignment bytes will fit in the file.) * The file is then memory mapped. Once the shared memory region is created, * ipc_init initializes various locks, pointers, and variables in the shared * memory. It also uses ftok() to get a shared memory semaphore key for later * use in allocating shared semaphores. */ void ipc_init(char *fsplug) { int shmfd; char tmpbuf[MB] = {0}; key_t key; #ifdef HAVE_SEM_RMID int sys_semid; #endif char *shmdir; shmdir = getenv("FB_SHM_DIR"); if (shmdir == NULL) shmdir = "/tmp"; if (asprintf(&shmpath, "%s/filebench-shm-XXXXXX", shmdir) < 0) { filebench_log(LOG_FATAL, "Could not name shared memory file"); exit(1); } shmfd = mkstemp(shmpath); if (shmfd < 0) { filebench_log(LOG_FATAL, "Could not create shared memory " "file %s: %s", shmpath, strerror(errno)); exit(1); } (void)lseek(shmfd, sizeof(filebench_shm_t), SEEK_SET); if (write(shmfd, tmpbuf, MB) != MB) { filebench_log(LOG_FATAL, "Could not write to the shared memory " "file: %s", strerror(errno)); exit(1); } if ((filebench_shm = (filebench_shm_t *)mmap(NULL, sizeof(filebench_shm_t), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0)) == MAP_FAILED) { filebench_log(LOG_FATAL, "Could not mmap the shared " "memory file: %s", strerror(errno)); exit(1); } (void) memset(filebench_shm, 0, (char *)&filebench_shm->shm_marker - (char *)filebench_shm); /* * Pass the name of the target filesystem, if not the local driver */ if (fsplug) fb_strlcpy(filebench_shm->shm_filesys_path,fsplug, sizeof(filebench_shm->shm_filesys_path)); /* * First, initialize all the structures needed for the filebench_log() * function to work correctly with the log levels other than LOG_FATAL */ filebench_shm->shm_epoch = gethrtime(); filebench_shm->shm_debug_level = LOG_INFO; /* Setup mutexes for object lists */ ipc_mutexattr_init(IPC_MUTEX_NORMAL); ipc_mutexattr_init(IPC_MUTEX_PRIORITY); ipc_mutexattr_init(IPC_MUTEX_ROBUST); ipc_mutexattr_init(IPC_MUTEX_PRI_ROB); (void) pthread_mutex_init(&filebench_shm->shm_msg_lock, ipc_mutexattr(IPC_MUTEX_NORMAL)); filebench_log(LOG_INFO, "Allocated %lldMB of shared memory", (sizeof(filebench_shm_t) + MB) / MB); filebench_shm->shm_rmode = FILEBENCH_MODE_TIMEOUT; filebench_shm->shm_string_ptr = &filebench_shm->shm_strings[0]; filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; filebench_shm->shm_path_ptr = &filebench_shm->shm_filesetpaths[0]; (void) pthread_mutex_init(&filebench_shm->shm_fileset_lock, ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_procflow_lock, ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_procs_running_lock, ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_threadflow_lock, ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_flowop_lock, ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_eventgen_lock, ipc_mutexattr(IPC_MUTEX_PRI_ROB)); (void) pthread_mutex_init(&filebench_shm->shm_malloc_lock, ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_ism_lock, ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock); (void) pthread_cond_init(&filebench_shm->shm_eventgen_cv, ipc_condattr()); (void) pthread_rwlock_init(&filebench_shm->shm_flowop_find_lock, ipc_rwlockattr()); (void) pthread_rwlock_init(&filebench_shm->shm_run_lock, ipc_rwlockattr()); /* Create semaphore */ if ((key = ftok(shmpath, 1)) < 0) { filebench_log(LOG_ERROR, "cannot create sem: %s", strerror(errno)); exit(1); } #ifdef HAVE_SEM_RMID if ((sys_semid = semget(key, 0, 0)) != -1) (void) semctl(sys_semid, 0, IPC_RMID); #endif filebench_shm->shm_semkey = key; filebench_shm->shm_sys_semid = -1; filebench_shm->shm_dump_fd = -1; filebench_shm->shm_eventgen_hz = 0; filebench_shm->shm_id = -1; }
/* * Creates a directory node in a fileset, by obtaining a * filesetentry entity for the node and initializing it * according to parameters of the fileset. It determines a * directory tree depth and directory width, optionally using * a gamma distribution. If its calculated depth is less then * its actual depth in the directory tree, it becomes a leaf * node and files itself with "width" number of file type * filesetentries, otherwise it files itself with "width" * number of directory type filesetentries, using recursive * calls to fileset_populate_subdir. The end result of the * initial call to this routine is a tree of directories of * random width and varying depth with sufficient leaf * directories to contain all required files. * Returns 0 on success. Returns -1 if ipc path string memory * cannot be allocated and returns an error code (currently * also -1) from calls to fileset_populate_file or recursive * calls to fileset_populate_subdir. */ static int fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, int serial, double depth) { double randepth, drand, ranwidth, gamma; int isleaf = 0; char tmpname[16]; filesetentry_t *entry; int i; depth += 1; /* Create dir node */ if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_subdir: Can't malloc filesetentry"); return (-1); } (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr()); (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_subdir: Can't alloc path string"); return (-1); } entry->fse_parent = parent; entry->fse_flags |= FSE_DIR | FSE_FREE; fileset_insdirlist(fileset, entry); gamma = *(fileset->fs_dirgamma) / 1000.0; if (gamma > 0) { drand = gamma_dist_knuth(gamma, fileset->fs_meandepth / gamma); randepth = (int)drand; } else { randepth = (int)fileset->fs_meandepth; } gamma = *(fileset->fs_sizegamma) / 1000.0; if (gamma > 0) { drand = gamma_dist_knuth(gamma, fileset->fs_meanwidth / gamma); ranwidth = drand; } else { ranwidth = fileset->fs_meanwidth; } if (randepth == 0) randepth = 1; if (ranwidth == 0) ranwidth = 1; if (depth >= randepth) isleaf = 1; /* * Create directory of random width according to distribution, or * if root directory, continue until #files required */ for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) && (fileset->fs_realfiles < *(fileset->fs_entries)); i++) { int ret = 0; if (parent && isleaf) ret = fileset_populate_file(fileset, entry, i); else ret = fileset_populate_subdir(fileset, entry, i, depth); if (ret != 0) return (ret); } return (0); }
/* * Obtaines a filesetentry entity for a file to be placed in a * (sub)directory of a fileset. The size of the file may be * specified by fs_meansize, or calculated from a gamma * distribution of parameter fs_sizegamma and of mean size * fs_meansize. The filesetentry entity is placed on the file * list in the specified parent filesetentry entity, which may * be a directory filesetentry, or the root filesetentry in the * fileset. It is also placed on the fileset's list of all * contained files. Returns 0 if successful or -1 if ipc memory * for the path string cannot be allocated, or if a RAW device * cannot be located. */ static int fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, char *path, int serial) { char tmpname[16]; filesetentry_t *entry; double drand; double gamma; struct stat64 sb; int fd; if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_file: Can't malloc filesetentry"); return (-1); } (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr()); entry->fse_parent = parent; entry->fse_fileset = fileset; entry->fse_flags |= FSE_FREE; /* RAW File name */ if (path) { /* check for raw device */ fd = open(path, O_RDONLY); if ((fstat64(fd, &sb) == 0) && ((sb.st_mode & S_IFMT) == S_IFBLK) && sb.st_rdev) { entry->fse_size = lseek64(fd, 0, SEEK_END); close(fd); fileset->fs_attrs |= FILESET_IS_RAW_DEV; filebench_log(LOG_INFO, "RAW device for %s on %s size %lld", fileset->fs_name, path, entry->fse_size); } else { filebench_log(LOG_ERROR, "fileset_populate_file: Cannot open RAW device %s", path); close(fd); return (-1); } entry->fse_flags &= FSE_FREE; entry->fse_flags |= FSE_EXISTS; if ((entry->fse_path = (char *)ipc_pathalloc(path)) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_file: Can't alloc path string"); return (-1); } } else { (void) snprintf(tmpname, sizeof (tmpname), "%08d", serial); gamma = *(fileset->fs_sizegamma) / 1000.0; if (gamma > 0) { drand = gamma_dist_knuth(gamma, fileset->fs_meansize / gamma); entry->fse_size = (off64_t)drand; } else { entry->fse_size = (off64_t)fileset->fs_meansize; } if ((entry->fse_path = (char *)ipc_pathalloc(tmpname)) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_file: Can't alloc path string"); return (-1); } } fileset_insfilelist(fileset, entry); fileset->fs_bytes += entry->fse_size; fileset->fs_realfiles++; return (0); }
/* * Initialize the Interprocess Communication system and its * associated shared memory structure. It first creates a * temporary file using either the mkstemp() function or the * tempnam() and open() functions. If the process model is in * use,it than sets the file large enough to hold the * filebench_shm and an additional Megabyte. The file is then * memory mapped. If the process model is not in use, it simply * mallocs a region of sizeof (filebench_shm_t). * * Once the shared memory region / file is created, ipc_init * initializes various locks pointers, and variables in the * shared memory. It also uses ftok() to get a shared memory * semaphore key for later use in allocating shared semaphores. */ void ipc_init(void) { filebench_shm_t *buf = malloc(MB); key_t key; caddr_t c1; caddr_t c2; #ifdef HAVE_SEM_RMID int semid; #endif #ifdef HAVE_MKSTEMP shmpath = (char *)malloc(128); (void) strcpy(shmpath, "/var/tmp/fbenchXXXXXX"); shmfd = mkstemp(shmpath); #else shmfd = open(shmpath, O_CREAT | O_RDWR | O_TRUNC, 0666); shmpath = tempnam("/var/tmp", "fbench"); #endif /* HAVE_MKSTEMP */ #ifdef USE_PROCESS_MODEL if (shmfd < 0) { filebench_log(LOG_FATAL, "Cannot open shm %s: %s", shmpath, strerror(errno)); exit(1); } (void) lseek(shmfd, sizeof (filebench_shm_t), SEEK_SET); if (write(shmfd, buf, MB) != MB) { filebench_log(LOG_FATAL, "Cannot allocate shm: %s", strerror(errno)); exit(1); } /* LINTED E_BAD_PTR_CAST_ALIGN */ if ((filebench_shm = (filebench_shm_t *)mmap((caddr_t)0, sizeof (filebench_shm_t), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0)) == NULL) { filebench_log(LOG_FATAL, "Cannot mmap shm"); exit(1); } #else if ((filebench_shm = (filebench_shm_t *)malloc(sizeof (filebench_shm_t))) == NULL) { filebench_log(LOG_FATAL, "Cannot malloc shm"); exit(1); } #endif /* USE_PROCESS_MODEL */ c1 = (caddr_t)filebench_shm; c2 = (caddr_t)&filebench_shm->marker; (void) memset(filebench_shm, 0, c2 - c1); filebench_shm->epoch = gethrtime(); filebench_shm->debug_level = LOG_VERBOSE; filebench_shm->shm_rmode = FILEBENCH_MODE_TIMEOUT; filebench_shm->string_ptr = &filebench_shm->strings[0]; filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; filebench_shm->path_ptr = &filebench_shm->filesetpaths[0]; /* Setup mutexes for object lists */ (void) pthread_mutex_init(&filebench_shm->fileset_lock, ipc_mutexattr()); (void) pthread_mutex_init(&filebench_shm->procflow_lock, ipc_mutexattr()); (void) pthread_mutex_init(&filebench_shm->threadflow_lock, ipc_mutexattr()); (void) pthread_mutex_init(&filebench_shm->flowop_lock, ipc_mutexattr()); (void) pthread_mutex_init(&filebench_shm->msg_lock, ipc_mutexattr()); (void) pthread_mutex_init(&filebench_shm->eventgen_lock, ipc_mutexattr()); (void) pthread_mutex_init(&filebench_shm->malloc_lock, ipc_mutexattr()); (void) pthread_mutex_init(&filebench_shm->ism_lock, ipc_mutexattr()); (void) pthread_cond_init(&filebench_shm->eventgen_cv, ipc_condattr()); (void) pthread_rwlock_init(&filebench_shm->flowop_find_lock, ipc_rwlockattr()); (void) pthread_rwlock_init(&filebench_shm->run_lock, ipc_rwlockattr()); (void) pthread_rwlock_rdlock(&filebench_shm->run_lock); (void) ipc_mutex_lock(&filebench_shm->ism_lock); /* Create semaphore */ if ((key = ftok(shmpath, 1)) < 0) { filebench_log(LOG_ERROR, "cannot create sem: %s", strerror(errno)); exit(1); } #ifdef HAVE_SEM_RMID if ((semid = semget(key, 0, 0)) != -1) (void) semctl(semid, 0, IPC_RMID); #endif filebench_shm->semkey = key; filebench_shm->log_fd = -1; filebench_shm->dump_fd = -1; filebench_shm->eventgen_hz = 0; filebench_shm->shm_id = -1; free(buf); }