diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/filebench/common/filebench.h | 20 | ||||
-rw-r--r-- | usr/src/cmd/filebench/common/fileset.c | 435 | ||||
-rw-r--r-- | usr/src/cmd/filebench/common/fileset.h | 23 | ||||
-rw-r--r-- | usr/src/cmd/filebench/common/flowop.c | 16 | ||||
-rw-r--r-- | usr/src/cmd/filebench/common/flowop_library.c | 133 | ||||
-rw-r--r-- | usr/src/cmd/filebench/common/ipc.c | 104 | ||||
-rw-r--r-- | usr/src/cmd/filebench/common/ipc.h | 142 | ||||
-rw-r--r-- | usr/src/cmd/filebench/common/procflow.c | 18 | ||||
-rw-r--r-- | usr/src/cmd/filebench/common/threadflow.c | 5 | ||||
-rw-r--r-- | usr/src/cmd/filebench/common/vars.h | 6 | ||||
-rw-r--r-- | usr/src/cmd/filebench/workloads/Makefile | 2 | ||||
-rw-r--r-- | usr/src/cmd/filebench/workloads/filemicro_statfile.f | 55 | ||||
-rw-r--r-- | usr/src/pkgdefs/SUNWfilebench/prototype_com | 3 |
13 files changed, 669 insertions, 293 deletions
diff --git a/usr/src/cmd/filebench/common/filebench.h b/usr/src/cmd/filebench/common/filebench.h index 74d184494e..e0610a0478 100644 --- a/usr/src/cmd/filebench/common/filebench.h +++ b/usr/src/cmd/filebench/common/filebench.h @@ -28,8 +28,6 @@ #ifndef _FB_FILEBENCH_H #define _FB_FILEBENCH_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include "config.h" #include <stdio.h> @@ -44,6 +42,14 @@ typedef enum { B_FALSE, B_TRUE } boolean_t; typedef unsigned long long u_longlong_t; #endif +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + #include "procflow.h" #include "misc.h" #include "ipc.h" @@ -76,14 +82,6 @@ typedef unsigned long long u_longlong_t; extern "C" { #endif -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - extern pid_t my_pid; /* this process' process id */ extern procflow_t *my_procflow; /* if slave process, procflow pointer */ extern int errno; @@ -119,7 +117,7 @@ void filebench_shutdown(int error); #define MIN(x, y) ((x) < (y) ? (x) : (y)) #endif -#define FILEBENCH_VERSION "1.3.3" +#define FILEBENCH_VERSION "1.3.4" #define FILEBENCHDIR "/usr/benchmarks/filebench" #define FILEBENCH_PROMPT "filebench> " #define MAX_LINE_LEN 1024 diff --git a/usr/src/cmd/filebench/common/fileset.c b/usr/src/cmd/filebench/common/fileset.c index d402c49431..be81898860 100644 --- a/usr/src/cmd/filebench/common/fileset.c +++ b/usr/src/cmd/filebench/common/fileset.c @@ -25,9 +25,6 @@ * Portions Copyright 2008 Denis Cheng */ -#pragma ident "%Z%%M% %I% %E% SMI" - - #include <fcntl.h> #include <pthread.h> #include <errno.h> @@ -48,21 +45,24 @@ * fileset has been created, has a tree of directories and files * corresponding to the fileset's filesetentry tree. * - * This routine is called from fileset_createset(), which is in turn - * called from parser_gram.y: parser_create_fileset() when a - * "create fileset" or "run" command is encountered. - * When the "create fileset" command is used, it is generally paired with + * Fileset entities are allocated by fileset_define() which is called from + * parser_gram.y: parser_fileset_define(). The filesetentry tree corrseponding + * to the eventual directory and file tree to be instantiated on the storage + * medium is built by fileset_populate(), which is called from + * fileset_createset(). After calling fileset_populate(), fileset_createset() + * will call fileset_create() to pre-allocate designated files and directories. + * + * Fileset_createset() is called from parser_gram.y: parser_create_fileset() + * when a "create fileset" or "run" command is encountered. When the + * "create fileset" command is used, it is generally paired with * a "create processes" command, and must appear first, in order to * instantiate all the files in the fileset before trying to use them. */ static int fileset_checkraw(fileset_t *fileset); -/* parallel allocation control */ +/* maximum parallel allocation control */ #define MAX_PARALLOC_THREADS 32 -static pthread_mutex_t paralloc_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t paralloc_cv = PTHREAD_COND_INITIALIZER; -static int paralloc_count; /* * returns pointer to file or fileset @@ -129,8 +129,8 @@ fileset_usage(void) /* * Frees up memory mapped file region of supplied size. The * file descriptor "fd" indicates which memory mapped file. - * If successful, returns 0. Otherwise returns -1 if "size" - * is zero, or -1 times the number of times msync() failed. + * If successful, returns 0. Otherwise returns -1 times the number of + * times msync() failed. */ static int fileset_freemem(int fd, off64_t size) @@ -224,7 +224,7 @@ fileset_mkdir(char *path, int mode) } free(p); - return (0); + return (FILEBENCH_OK); null_str: /* clean up */ @@ -234,7 +234,7 @@ null_str: filebench_log(LOG_ERROR, "Failed to create directory path %s: Out of memory", path); - return (-1); + return (FILEBENCH_ERROR); } /* @@ -256,12 +256,12 @@ fileset_create_subdirs(fileset_t *fileset, char *filesetpath) free(part_path); /* now create this portion of the subdirectory tree */ - if (fileset_mkdir(full_path, 0755) == -1) - return (-1); + if (fileset_mkdir(full_path, 0755) == FILEBENCH_ERROR) + return (FILEBENCH_ERROR); direntry = direntry->fse_dirnext; } - return (0); + return (FILEBENCH_OK); } /* @@ -293,26 +293,26 @@ fileset_alloc_file(filesetentry_t *entry) filebench_log(LOG_INFO, "Attempted but failed to Re-use file %s", path); - return (-1); + return (FILEBENCH_ERROR); } if (sb.st_size == (off64_t)entry->fse_size) { - filebench_log(LOG_INFO, + filebench_log(LOG_DEBUG_IMPL, "Re-using file %s", path); if (!avd_get_bool(entry->fse_fileset->fs_cached)) (void) fileset_freemem(fd, entry->fse_size); - entry->fse_flags |= FSE_EXISTS; (void) ipc_mutex_lock( - &entry->fse_fileset->fs_num_files_lock); + &entry->fse_fileset->fs_pick_lock); + entry->fse_flags |= FSE_EXISTS; entry->fse_fileset->fs_num_act_files++; (void) ipc_mutex_unlock( - &entry->fse_fileset->fs_num_files_lock); + &entry->fse_fileset->fs_pick_lock); (void) close(fd); - return (0); + return (FILEBENCH_OK); } else if (sb.st_size > (off64_t)entry->fse_size) { /* reuse, but too large */ @@ -329,16 +329,15 @@ fileset_alloc_file(filesetentry_t *entry) (void) fileset_freemem(fd, entry->fse_size); - entry->fse_flags |= FSE_EXISTS; - (void) ipc_mutex_lock( - &entry->fse_fileset->fs_num_files_lock); + &entry->fse_fileset->fs_pick_lock); + entry->fse_flags |= FSE_EXISTS; entry->fse_fileset->fs_num_act_files++; (void) ipc_mutex_unlock( - &entry->fse_fileset->fs_num_files_lock); + &entry->fse_fileset->fs_pick_lock); (void) close(fd); - return (0); + return (FILEBENCH_OK); } } else { @@ -348,18 +347,17 @@ fileset_alloc_file(filesetentry_t *entry) "Failed to pre-allocate file %s: %s", path, strerror(errno)); - return (-1); + return (FILEBENCH_ERROR); } } if ((buf = (char *)malloc(FILE_ALLOC_BLOCK)) == NULL) - return (-1); + return (FILEBENCH_ERROR); + (void) ipc_mutex_lock(&entry->fse_fileset->fs_pick_lock); entry->fse_flags |= FSE_EXISTS; - - (void) ipc_mutex_lock(&entry->fse_fileset->fs_num_files_lock); entry->fse_fileset->fs_num_act_files++; - (void) ipc_mutex_unlock(&entry->fse_fileset->fs_num_files_lock); + (void) ipc_mutex_unlock(&entry->fse_fileset->fs_pick_lock); for (seek = 0; seek < entry->fse_size; ) { off64_t wsize; @@ -378,7 +376,7 @@ fileset_alloc_file(filesetentry_t *entry) path, strerror(errno)); (void) close(fd); free(buf); - return (-1); + return (FILEBENCH_ERROR); } seek += wsize; } @@ -394,26 +392,27 @@ fileset_alloc_file(filesetentry_t *entry) "Pre-allocated file %s size %llu", path, (u_longlong_t)entry->fse_size); - return (0); + return (FILEBENCH_OK); } /* * given a fileset entry, determines if the associated file * needs to be allocated or not, and if so does the allocation. + * Sets shm_fsparalloc_count to -1 on error. */ static void * fileset_alloc_thread(filesetentry_t *entry) { - if (fileset_alloc_file(entry) == -1) { - (void) pthread_mutex_lock(¶lloc_lock); - paralloc_count = -1; + if (fileset_alloc_file(entry) == FILEBENCH_ERROR) { + (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); + filebench_shm->shm_fsparalloc_count = -1; } else { - (void) pthread_mutex_lock(¶lloc_lock); - paralloc_count--; + (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); + filebench_shm->shm_fsparalloc_count--; } - (void) pthread_cond_signal(¶lloc_cv); - (void) pthread_mutex_unlock(¶lloc_lock); + (void) pthread_cond_signal(&filebench_shm->shm_fsparalloc_cv); + (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock); pthread_exit(NULL); return (NULL); @@ -451,16 +450,8 @@ fileset_openfile(fileset_t *fileset, /* If we are going to create a file, create the parent dirs */ if ((flag & O_CREAT) && (stat64(dir, &sb) != 0)) { - if (fileset_mkdir(dir, 0755) == -1) - return (-1); - } - - if (flag & O_CREAT) { - entry->fse_flags |= FSE_EXISTS; - - (void) ipc_mutex_lock(&fileset->fs_num_files_lock); - fileset->fs_num_act_files++; - (void) ipc_mutex_unlock(&fileset->fs_num_files_lock); + if (fileset_mkdir(dir, 0755) == FILEBENCH_ERROR) + return (FILEBENCH_ERROR); } if (attrs & FLOW_ATTR_DSYNC) { @@ -475,10 +466,15 @@ fileset_openfile(fileset_t *fileset, filebench_log(LOG_ERROR, "Failed to open file %s: %s", path, strerror(errno)); - (void) ipc_mutex_unlock(&entry->fse_lock); - return (-1); + + fileset_unbusy(entry, FALSE, FALSE); + return (FILEBENCH_ERROR); } - (void) ipc_mutex_unlock(&entry->fse_lock); + + if (flag & O_CREAT) + fileset_unbusy(entry, TRUE, TRUE); + else + fileset_unbusy(entry, FALSE, FALSE); #ifdef sun if (attrs & FLOW_ATTR_DIRECTIO) @@ -505,7 +501,7 @@ fileset_openfile(fileset_t *fileset, * FILESET_PICKNOEXIST insures that only non extant * (not FSE_EXISTS) state files are selected. * Note that the selected fileset entry (file) is returned - * with its fse_lock field locked. + * with its FSE_BUSY flag (in fse_flags) set. */ filesetentry_t * fileset_pick(fileset_t *fileset, int flags, int tid) @@ -513,26 +509,33 @@ fileset_pick(fileset_t *fileset, int flags, int tid) filesetentry_t *entry = NULL; filesetentry_t *first = NULL; - (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); + (void) ipc_mutex_lock(&fileset->fs_pick_lock); + + /* see if we have to wait for available files or directories */ + if (flags & FILESET_PICKDIR) { + while (fileset->fs_idle_dirs == 0) { + (void) pthread_cond_wait(&fileset->fs_idle_dirs_cv, + &fileset->fs_pick_lock); + } + } else { + while (fileset->fs_idle_files == 0) { + (void) pthread_cond_wait(&fileset->fs_idle_files_cv, + &fileset->fs_pick_lock); + } + } /* see if asking for impossible */ - (void) ipc_mutex_lock(&fileset->fs_num_files_lock); if (flags & FILESET_PICKEXISTS) { if (fileset->fs_num_act_files == 0) { - (void) ipc_mutex_unlock(&fileset->fs_num_files_lock); - (void) ipc_mutex_unlock( - &filebench_shm->shm_fileset_lock); + (void) ipc_mutex_unlock(&fileset->fs_pick_lock); return (NULL); } } else if (flags & FILESET_PICKNOEXIST) { if (fileset->fs_num_act_files == fileset->fs_realfiles) { - (void) ipc_mutex_unlock(&fileset->fs_num_files_lock); - (void) ipc_mutex_unlock( - &filebench_shm->shm_fileset_lock); + (void) ipc_mutex_unlock(&fileset->fs_pick_lock); return (NULL); } } - (void) ipc_mutex_unlock(&fileset->fs_num_files_lock); while (entry == NULL) { @@ -575,12 +578,23 @@ fileset_pick(fileset_t *fileset, int flags, int tid) entry = fileset->fs_dirlist; fileset->fs_dirrotor = entry->fse_dirnext; } else { - entry = fileset->fs_filerotor[tid]; - if (entry == NULL) + if (flags & FILESET_PICKNOEXIST) { + entry = fileset->fs_file_ne_rotor; + if (entry == NULL) + fileset->fs_file_ne_rotor = + entry = + fileset->fs_filelist; + fileset->fs_file_ne_rotor = + entry->fse_filenext; + } else { + entry = fileset->fs_filerotor[tid]; + if (entry == NULL) + fileset->fs_filerotor[tid] = + entry = + fileset->fs_filelist; fileset->fs_filerotor[tid] = - entry = fileset->fs_filelist; - fileset->fs_filerotor[tid] = - entry->fse_filenext; + entry->fse_filenext; + } } } @@ -590,34 +604,123 @@ fileset_pick(fileset_t *fileset, int flags, int tid) if (first == NULL) first = entry; - /* Return locked entry */ - (void) ipc_mutex_lock(&entry->fse_lock); + /* see if entry in use */ + if (entry->fse_flags & FSE_BUSY) { + + /* it is, so try next */ + entry = NULL; + continue; + } /* If we ask for an existing file, go round again */ if ((flags & FILESET_PICKEXISTS) && - !(entry->fse_flags & FSE_EXISTS)) { - (void) ipc_mutex_unlock(&entry->fse_lock); + !(entry->fse_flags & FSE_EXISTS)) entry = NULL; - } /* If we ask for not an existing file, go round again */ if ((flags & FILESET_PICKNOEXIST) && - (entry->fse_flags & FSE_EXISTS)) { - (void) ipc_mutex_unlock(&entry->fse_lock); + (entry->fse_flags & FSE_EXISTS)) entry = NULL; - } } - (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); + /* update file or directory idle counts */ + if (flags & FILESET_PICKDIR) + fileset->fs_idle_dirs--; + else + fileset->fs_idle_files--; + + /* Indicate that file or directory is now busy */ + entry->fse_flags |= FSE_BUSY; + + (void) ipc_mutex_unlock(&fileset->fs_pick_lock); filebench_log(LOG_DEBUG_SCRIPT, "Picked file %s", entry->fse_path); return (entry); empty: - (void) ipc_mutex_unlock(&filebench_shm->shm_fileset_lock); + (void) ipc_mutex_unlock(&fileset->fs_pick_lock); return (NULL); } /* + * Removes a filesetentry from the "FSE_BUSY" state, signaling any threads + * that are waiting for a NOT BUSY filesetentry. Also sets whether it is + * existant or not, or leaves that designation alone. + */ +void +fileset_unbusy(filesetentry_t *entry, int update_exist, int new_exist_val) +{ + fileset_t *fileset = NULL; + int fse_is_dir; + + if (entry) + fileset = entry->fse_fileset; + + if (fileset == NULL) { + filebench_log(LOG_ERROR, "fileset_unbusy: NO FILESET!"); + return; + } + + (void) ipc_mutex_lock(&fileset->fs_pick_lock); + fse_is_dir = entry->fse_flags & FSE_DIR; + + /* increment idle count, clear FSE_BUSY and signal IF it was busy */ + if (entry->fse_flags & FSE_BUSY) { + + /* unbusy it */ + entry->fse_flags &= (~FSE_BUSY); + + /* release any threads waiting for unbusy */ + if (entry->fse_flags & FSE_THRD_WAITNG) { + entry->fse_flags &= (~FSE_THRD_WAITNG); + (void) pthread_cond_broadcast( + &fileset->fs_thrd_wait_cv); + } + + /* increment idle count and signal waiting threads */ + if (fse_is_dir) { + fileset->fs_idle_dirs++; + if (fileset->fs_idle_dirs == 1) { + (void) pthread_cond_signal( + &fileset->fs_idle_dirs_cv); + } + } else { + fileset->fs_idle_files++; + if (fileset->fs_idle_files == 1) { + (void) pthread_cond_signal( + &fileset->fs_idle_files_cv); + } + } + } + + /* modify FSE_EXIST flag and actual dirs/files count, if requested */ + if (update_exist) { + if (new_exist_val == TRUE) { + if (!(entry->fse_flags & FSE_EXISTS)) { + + /* asked to set, and it was clear */ + entry->fse_flags |= FSE_EXISTS; + if (fse_is_dir) + fileset->fs_num_act_dirs++; + else + fileset->fs_num_act_files++; + } + } else { + if (entry->fse_flags & FSE_EXISTS) { + + /* asked to clear, and it was set */ + entry->fse_flags &= (~FSE_EXISTS); + if (fse_is_dir) + fileset->fs_num_act_dirs--; + else + fileset->fs_num_act_files--; + } + } + } + + (void) ipc_mutex_unlock(&fileset->fs_pick_lock); +} + +/* * 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 fileset_path. If the @@ -629,7 +732,8 @@ empty: * their containing subdirectory trees in the filesystem and * creating actual files for fileset_preallocpercent of them. The * created files are filled with fse_size bytes of unitialized - * data. The routine returns -1 on errors, 0 on success. + * data. The routine returns FILEBENCH_ERROR on errors, + * FILEBENCH_OK on success. */ static int fileset_create(fileset_t *fileset) @@ -648,22 +752,19 @@ fileset_create(fileset_t *fileset) if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { filebench_log(LOG_ERROR, "%s path not set", fileset_entity_name(fileset)); - return (-1); + return (FILEBENCH_ERROR); } if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { filebench_log(LOG_ERROR, "%s name not set", fileset_entity_name(fileset)); - return (-1); + return (FILEBENCH_ERROR); } - /* declare all files currently non existant (single threaded code) */ - fileset->fs_num_act_files = 0; - #ifdef HAVE_RAW_SUPPORT /* treat raw device as special case */ if (fileset->fs_attrs & FILESET_IS_RAW_DEV) - return (0); + return (FILEBENCH_OK); #endif /* HAVE_RAW_SUPPORT */ /* XXX Add check to see if there is enough space */ @@ -694,8 +795,8 @@ fileset_create(fileset_t *fileset) (void) mkdir(path, 0755); /* make the filesets directory tree */ - if (fileset_create_subdirs(fileset, path) == -1) - return (-1); + if (fileset_create_subdirs(fileset, path) == FILEBENCH_ERROR) + return (FILEBENCH_ERROR); start = gethrtime(); @@ -713,10 +814,8 @@ fileset_create(fileset_t *fileset) pickflags = FILESET_PICKUNIQUE; - entry->fse_flags &= ~FSE_EXISTS; - /* entry doesn't need to be locked during initialization */ - (void) ipc_mutex_unlock(&entry->fse_lock); + fileset_unbusy(entry, FALSE, FALSE); if (rand() < randno) continue; @@ -728,34 +827,52 @@ fileset_create(fileset_t *fileset) else entry->fse_flags &= (~FSE_REUSING); + /* fire off allocation threads for each file if paralloc set */ if (avd_get_bool(fileset->fs_paralloc)) { - /* fire off a separate allocation thread */ - (void) pthread_mutex_lock(¶lloc_lock); - while (paralloc_count >= MAX_PARALLOC_THREADS) { + /* limit total number of simultaneous allocations */ + (void) pthread_mutex_lock( + &filebench_shm->shm_fsparalloc_lock); + while (filebench_shm->shm_fsparalloc_count + >= MAX_PARALLOC_THREADS) { (void) pthread_cond_wait( - ¶lloc_cv, ¶lloc_lock); + &filebench_shm->shm_fsparalloc_cv, + &filebench_shm->shm_fsparalloc_lock); } - if (paralloc_count < 0) { - (void) pthread_mutex_unlock(¶lloc_lock); - return (-1); + /* quit if any allocation thread reports and error */ + if (filebench_shm->shm_fsparalloc_count < 0) { + (void) pthread_mutex_unlock( + &filebench_shm->shm_fsparalloc_lock); + return (FILEBENCH_ERROR); } - paralloc_count++; - (void) pthread_mutex_unlock(¶lloc_lock); + filebench_shm->shm_fsparalloc_count++; + (void) pthread_mutex_unlock( + &filebench_shm->shm_fsparalloc_lock); + /* + * Fire off a detached allocation thread per file. + * The thread will self destruct when it finishes + * writing pre-allocation data to the file. + */ if (pthread_create(&tid, NULL, (void *(*)(void*))fileset_alloc_thread, - entry) != 0) { + entry) == 0) { + /* + * A thread was created; detach it so it can + * fully quit when finished. + */ + (void) pthread_detach(tid); + } else { filebench_log(LOG_ERROR, "File prealloc thread create failed"); filebench_shutdown(1); } } else { - if (fileset_alloc_file(entry) == -1) - return (-1); + if (fileset_alloc_file(entry) == FILEBENCH_ERROR) + return (FILEBENCH_ERROR); } } @@ -767,7 +884,7 @@ exit: fileset_entity_name(fileset), fileset_name, (u_longlong_t)(((gethrtime() - start) / 1000000000) + 1)); - return (0); + return (FILEBENCH_OK); } /* @@ -811,8 +928,8 @@ fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry) * 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. + * contained files. Returns FILEBENCH_OK if successful or FILEBENCH_ERROR + * if ipc memory for the path string cannot be allocated. */ static int fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) @@ -825,20 +942,24 @@ fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) == NULL) { filebench_log(LOG_ERROR, "fileset_populate_file: Can't malloc filesetentry"); - return (-1); + return (FILEBENCH_ERROR); } - (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr()); + /* Another currently idle file */ + (void) ipc_mutex_lock(&fileset->fs_pick_lock); + fileset->fs_idle_files++; + (void) ipc_mutex_unlock(&fileset->fs_pick_lock); + entry->fse_parent = parent; entry->fse_fileset = fileset; - entry->fse_flags |= FSE_FREE; + 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); + return (FILEBENCH_ERROR); } /* see if random variable was supplied for file size */ @@ -860,7 +981,7 @@ fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) fileset->fs_bytes += entry->fse_size; fileset->fs_realfiles++; - return (0); + return (FILEBENCH_OK); } /* @@ -877,9 +998,9 @@ fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) * 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 + * Returns FILEBENCH_OK on success. Returns FILEBENCH_ERROR if ipc path + * string memory cannot be allocated and returns the error code (currently + * also FILEBENCH_ERROR) from calls to fileset_populate_file or recursive * calls to fileset_populate_subdir. */ static int @@ -899,20 +1020,23 @@ fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, == NULL) { filebench_log(LOG_ERROR, "fileset_populate_subdir: Can't malloc filesetentry"); - return (-1); + return (FILEBENCH_ERROR); } - (void) pthread_mutex_init(&entry->fse_lock, ipc_mutexattr()); + /* another idle directory */ + (void) ipc_mutex_lock(&fileset->fs_pick_lock); + fileset->fs_idle_dirs++; + (void) ipc_mutex_unlock(&fileset->fs_pick_lock); (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); + return (FILEBENCH_ERROR); } entry->fse_parent = parent; - entry->fse_flags |= FSE_DIR | FSE_FREE; + entry->fse_flags = FSE_DIR | FSE_FREE; fileset_insdirlist(fileset, entry); if (fileset->fs_dirdepthrv) { @@ -969,7 +1093,7 @@ fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, if (ret != 0) return (ret); } - return (0); + return (FILEBENCH_OK); } /* @@ -997,12 +1121,28 @@ fileset_populate(fileset_t *fileset) #ifdef HAVE_RAW_SUPPORT /* check for raw device */ if (fileset->fs_attrs & FILESET_IS_RAW_DEV) - return (0); + return (FILEBENCH_OK); #endif /* HAVE_RAW_SUPPORT */ /* save value of entries obtained for later, in case it was random */ fileset->fs_constentries = entries; + /* declare all files currently non existant */ + fileset->fs_num_act_files = 0; + + /* initialize idle files and directories condition variables */ + (void) pthread_cond_init(&fileset->fs_idle_dirs_cv, ipc_condattr()); + (void) pthread_cond_init(&fileset->fs_idle_files_cv, ipc_condattr()); + + /* no files or dirs idle (or busy) yet */ + fileset->fs_idle_files = 0; + fileset->fs_idle_dirs = 0; + + /* initialize locks and other condition variables */ + (void) pthread_mutex_init(&fileset->fs_pick_lock, + ipc_mutexattr(IPC_MUTEX_NORMAL)); + (void) pthread_cond_init(&fileset->fs_thrd_wait_cv, ipc_condattr()); + /* is dirwidth a random variable? */ if (AVD_IS_RANDOM(fileset->fs_dirwidth)) { meandirwidth = @@ -1054,7 +1194,7 @@ exists: (u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL)); } - return (0); + return (FILEBENCH_OK); } /* @@ -1084,10 +1224,6 @@ fileset_define(avd_t name) filebench_log(LOG_DEBUG_IMPL, "Defining file %s", avd_get_str(name)); - /* initialize fs_num_act_files lock */ - (void) pthread_mutex_init(&fileset->fs_num_files_lock, - ipc_mutexattr()); - (void) ipc_mutex_lock(&filebench_shm->shm_fileset_lock); fileset->fs_dirgamma = avd_int_alloc(1500); @@ -1129,7 +1265,10 @@ fileset_createset(fileset_t *fileset) int ret = 0; /* set up for possible parallel allocate */ - paralloc_count = 0; + filebench_shm->shm_fsparalloc_count = 0; + (void) pthread_cond_init( + &filebench_shm->shm_fsparalloc_cv, + ipc_condattr()); if (fileset && avd_get_bool(fileset->fs_prealloc)) { @@ -1139,7 +1278,7 @@ fileset_createset(fileset_t *fileset) "file %s/%s is a RAW device", avd_get_str(fileset->fs_path), avd_get_str(fileset->fs_name)); - return (0); + return (FILEBENCH_OK); } filebench_log(LOG_INFO, @@ -1147,10 +1286,10 @@ fileset_createset(fileset_t *fileset) fileset_entity_name(fileset), avd_get_str(fileset->fs_name)); - if ((ret = fileset_populate(fileset)) != 0) + if ((ret = fileset_populate(fileset)) != FILEBENCH_OK) return (ret); - if ((ret = fileset_create(fileset)) != 0) + if ((ret = fileset_create(fileset)) != FILEBENCH_OK) return (ret); } else { @@ -1169,10 +1308,12 @@ fileset_createset(fileset_t *fileset) continue; } - if ((ret = fileset_populate(list)) != 0) + if ((ret = fileset_populate(list)) != FILEBENCH_OK) return (ret); - if ((ret = fileset_create(list)) != 0) + + if ((ret = fileset_create(list)) != FILEBENCH_OK) return (ret); + list = list->fs_next; } } @@ -1181,15 +1322,17 @@ fileset_createset(fileset_t *fileset) filebench_log(LOG_INFO, "waiting for fileset pre-allocation to finish"); - (void) pthread_mutex_lock(¶lloc_lock); - while (paralloc_count > 0) - (void) pthread_cond_wait(¶lloc_cv, ¶lloc_lock); - (void) pthread_mutex_unlock(¶lloc_lock); + (void) pthread_mutex_lock(&filebench_shm->shm_fsparalloc_lock); + while (filebench_shm->shm_fsparalloc_count > 0) + (void) pthread_cond_wait( + &filebench_shm->shm_fsparalloc_cv, + &filebench_shm->shm_fsparalloc_lock); + (void) pthread_mutex_unlock(&filebench_shm->shm_fsparalloc_lock); - if (paralloc_count < 0) - return (-1); + if (filebench_shm->shm_fsparalloc_count < 0) + return (FILEBENCH_ERROR); - return (0); + return (FILEBENCH_OK); } /* @@ -1255,13 +1398,13 @@ fileset_print(fileset_t *fileset, int first) if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { filebench_log(LOG_ERROR, "%s path not set", fileset_entity_name(fileset)); - return (-1); + return (FILEBENCH_ERROR); } if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { filebench_log(LOG_ERROR, "%s name not set", fileset_entity_name(fileset)); - return (-1); + return (FILEBENCH_ERROR); } pathlength = strlen(fileset_path) + strlen(fileset_name); @@ -1295,7 +1438,7 @@ fileset_print(fileset_t *fileset, int first) (u_longlong_t)avd_get_int(fileset->fs_dirwidth), (u_longlong_t)fileset->fs_constentries); } - return (0); + return (FILEBENCH_OK); } /* * checks to see if the path/name pair points to a raw device. If @@ -1316,10 +1459,10 @@ fileset_checkraw(fileset_t *fileset) #ifdef HAVE_RAW_SUPPORT /* check for raw device */ if ((pathname = avd_get_str(fileset->fs_path)) == NULL) - return (0); + return (FILEBENCH_OK); if ((setname = avd_get_str(fileset->fs_name)) == NULL) - return (0); + return (FILEBENCH_OK); (void) strcpy(path, pathname); (void) strcat(path, "/"); @@ -1339,5 +1482,5 @@ fileset_checkraw(fileset_t *fileset) } #endif /* HAVE_RAW_SUPPORT */ - return (0); + return (FILEBENCH_OK); } diff --git a/usr/src/cmd/filebench/common/fileset.h b/usr/src/cmd/filebench/common/fileset.h index c20bf28bf5..84ca652c3f 100644 --- a/usr/src/cmd/filebench/common/fileset.h +++ b/usr/src/cmd/filebench/common/fileset.h @@ -26,8 +26,7 @@ #ifndef _FB_FILESET_H #define _FB_FILESET_H -#pragma ident "%Z%%M% %I% %E% SMI" - +#include "filebench.h" #include "config.h" #ifndef HAVE_OFF64_T @@ -64,7 +63,8 @@ extern "C" { #define FSE_FREE 0x02 #define FSE_EXISTS 0x04 #define FSE_BUSY 0x08 -#define FSE_REUSING 0x10 +#define FSE_THRD_WAITNG 0x10 +#define FSE_REUSING 0x20 typedef struct filesetentry { struct filesetentry *fse_next; @@ -72,11 +72,10 @@ typedef struct filesetentry { struct filesetentry *fse_filenext; /* List of files */ struct filesetentry *fse_dirnext; /* List of directories */ struct fileset *fse_fileset; /* Parent fileset */ - pthread_mutex_t fse_lock; char *fse_path; int fse_depth; off64_t fse_size; - int fse_flags; + int fse_flags; /* protected by fs_pick_lock */ } filesetentry_t; #define FILESET_PICKANY 0x1 /* Pick any file from the set */ @@ -121,13 +120,23 @@ typedef struct fileset { fbint_t fs_num_act_files; /* total number of files */ /* actually existing in the */ /* host or server's file system */ - pthread_mutex_t fs_num_files_lock; /* lock for fs_num_act_files */ + fbint_t fs_num_act_dirs; /* total number of directories */ + /* actually existing in the */ + /* host or server's file system */ + int64_t fs_idle_files; /* number of files NOT busy */ + pthread_cond_t fs_idle_files_cv; /* idle files condition variable */ + int64_t fs_idle_dirs; /* number of dirs NOT busy */ + pthread_cond_t fs_idle_dirs_cv; /* idle dirs condition variable */ + pthread_mutex_t fs_pick_lock; /* per fileset "pick" function lock */ + pthread_cond_t fs_thrd_wait_cv; /* per fileset file busy wait cv */ filesetentry_t *fs_filelist; /* List of files */ filesetentry_t *fs_dirlist; /* List of directories */ filesetentry_t *fs_filefree; /* Ptr to next free file */ filesetentry_t *fs_dirfree; /* Ptr to next free directory */ filesetentry_t *fs_filerotor[FSE_MAXTID]; /* next file to */ /* select */ + filesetentry_t *fs_file_ne_rotor; /* next non existent file */ + /* to select for createfile */ filesetentry_t *fs_dirrotor; /* Ptr to next directory to select */ } fileset_t; @@ -141,6 +150,8 @@ char *fileset_resolvepath(filesetentry_t *entry); void fileset_usage(void); void fileset_iter(int (*cmd)(fileset_t *fileset, int first)); int fileset_print(fileset_t *fileset, int first); +void fileset_unbusy(filesetentry_t *entry, int update_exist, + int new_exist_val); #ifdef __cplusplus } diff --git a/usr/src/cmd/filebench/common/flowop.c b/usr/src/cmd/filebench/common/flowop.c index b75222cb23..6a7773b795 100644 --- a/usr/src/cmd/filebench/common/flowop.c +++ b/usr/src/cmd/filebench/common/flowop.c @@ -23,8 +23,6 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include "config.h" #ifdef HAVE_LWPS @@ -253,7 +251,9 @@ flowop_initflow(flowop_t *flowop) * save static copies of two items, in case they are supplied * from random variables */ - flowop->fo_constvalue = avd_get_int(flowop->fo_value); + if (!AVD_IS_STRING(flowop->fo_value)) + flowop->fo_constvalue = avd_get_int(flowop->fo_value); + flowop->fo_constwss = avd_get_int(flowop->fo_wss); if ((*flowop->fo_init)(flowop) < 0) { @@ -587,7 +587,8 @@ flowop_start(threadflow_t *threadflow) void flowop_init(void) { - (void) pthread_mutex_init(&controlstats_lock, ipc_mutexattr()); + (void) pthread_mutex_init(&controlstats_lock, + ipc_mutexattr(IPC_MUTEX_NORMAL)); flowoplib_init(); } @@ -744,7 +745,8 @@ flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit, if (inherit) { (void) memcpy(flowop, inherit, sizeof (flowop_t)); - (void) pthread_mutex_init(&flowop->fo_lock, ipc_mutexattr()); + (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; @@ -754,7 +756,8 @@ flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit, (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()); + (void) pthread_mutex_init(&flowop->fo_lock, + ipc_mutexattr(IPC_MUTEX_PRI_ROB)); (void) ipc_mutex_lock(&flowop->fo_lock); } @@ -814,6 +817,7 @@ flowop_define(threadflow_t *threadflow, char *name, flowop_t *inherit, return (NULL); (void) ipc_mutex_unlock(&flowop->fo_lock); + return (flowop); } diff --git a/usr/src/cmd/filebench/common/flowop_library.c b/usr/src/cmd/filebench/common/flowop_library.c index 0301b4937f..9299ca0a6b 100644 --- a/usr/src/cmd/filebench/common/flowop_library.c +++ b/usr/src/cmd/filebench/common/flowop_library.c @@ -25,8 +25,6 @@ * Portions Copyright 2008 Denis Cheng */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include "config.h" #include <sys/types.h> @@ -105,6 +103,7 @@ static int flowoplib_init_generic(flowop_t *flowop); static void flowoplib_destruct_generic(flowop_t *flowop); static void flowoplib_destruct_noop(flowop_t *flowop); static int flowoplib_fdnum(threadflow_t *threadflow, flowop_t *flowop); +static int flowoplib_print(threadflow_t *threadflow, flowop_t *flowop); static int flowoplib_write(threadflow_t *threadflow, flowop_t *flowop); #ifdef HAVE_AIO static int flowoplib_aiowrite(threadflow_t *threadflow, flowop_t *flowop); @@ -209,6 +208,8 @@ static flowoplib_t flowoplib_funcs[] = { flowoplib_deletefile, flowoplib_destruct_generic, FLOW_TYPE_IO, FLOW_ATTR_WRITE, "writewholefile", flowoplib_init_generic, flowoplib_writewholefile, flowoplib_destruct_generic, + FLOW_TYPE_OTHER, 0, "print", flowoplib_init_generic, + flowoplib_print, flowoplib_destruct_generic, /* routine to calculate mean and stddev for output from a randvar */ FLOW_TYPE_OTHER, 0, "testrandvar", flowoplib_testrandvar_init, flowoplib_testrandvar, flowoplib_testrandvar_destruct @@ -1964,6 +1965,7 @@ flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop) #endif /* HAVE_RAW_SUPPORT */ if (file == NULL) { + /* pick arbitrary, existing (allocated) file */ if ((file = fileset_pick(fileset, FILESET_PICKEXISTS, 0)) == NULL) { filebench_log(LOG_DEBUG_SCRIPT, @@ -1971,7 +1973,18 @@ flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop) return (FILEBENCH_NORSC); } } else { - (void) ipc_mutex_lock(&file->fse_lock); + /* delete specific file. wait for it to be non-busy */ + (void) ipc_mutex_lock(&fileset->fs_pick_lock); + while (file->fse_flags & FSE_BUSY) { + file->fse_flags |= FSE_THRD_WAITNG; + (void) pthread_cond_wait(&fileset->fs_thrd_wait_cv, + &fileset->fs_pick_lock); + } + + /* File now available, grab it for deletion */ + file->fse_flags |= FSE_BUSY; + fileset->fs_idle_files--; + (void) ipc_mutex_unlock(&fileset->fs_pick_lock); } *path = 0; @@ -1982,14 +1995,13 @@ flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop) (void) strcat(path, pathtmp); free(pathtmp); + /* delete the selected file */ flowop_beginop(threadflow, flowop); (void) unlink(path); flowop_endop(threadflow, flowop, 0); - file->fse_flags &= ~FSE_EXISTS; - (void) ipc_mutex_lock(&fileset->fs_num_files_lock); - fileset->fs_num_act_files--; - (void) ipc_mutex_unlock(&fileset->fs_num_files_lock); - (void) ipc_mutex_unlock(&file->fse_lock); + + /* indicate that it is no longer busy and no longer exists */ + fileset_unbusy(file, TRUE, FALSE); filebench_log(LOG_DEBUG_SCRIPT, "deleted file %s", file->fse_path); @@ -2117,33 +2129,84 @@ flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop) { filesetentry_t *file; fileset_t *fileset; - char path[MAXPATHLEN]; - char *pathtmp; + struct stat statbuf; + int fd = flowop->fo_fdnumber; - if ((fileset = flowop->fo_fileset) == NULL) { - filebench_log(LOG_ERROR, "flowop NULL file"); + /* if fd specified and the file is open, use it to access file */ + if ((fd > 0) && ((threadflow->tf_fd[fd]) > 0)) { + + /* check whether file handle still valid */ + if ((file = threadflow->tf_fse[fd]) == NULL) { + filebench_log(LOG_DEBUG_SCRIPT, + "flowop %s trying to stat NULL file at fd = %d", + flowop->fo_name, fd); + return (FILEBENCH_ERROR); + } + + /* if here, we still have a valid file pointer */ + fileset = file->fse_fileset; + } else { + /* Otherwise, pick arbitrary file */ + file = NULL; + fileset = flowop->fo_fileset; + } + + + if (fileset == NULL) { + filebench_log(LOG_ERROR, + "statfile with no fileset specified"); return (FILEBENCH_ERROR); } - if ((file = fileset_pick(fileset, FILESET_PICKEXISTS, 0)) == NULL) { - filebench_log(LOG_DEBUG_SCRIPT, - "flowop %s failed to pick file", +#ifdef HAVE_RAW_SUPPORT + /* can't be used with raw devices */ + if (fileset->fs_attrs & FILESET_IS_RAW_DEV) { + filebench_log(LOG_ERROR, + "flowop %s attempted do a statfile on a RAW device", flowop->fo_name); - return (FILEBENCH_NORSC); + return (FILEBENCH_ERROR); } +#endif /* HAVE_RAW_SUPPORT */ - *path = 0; - (void) strcpy(path, avd_get_str(fileset->fs_path)); - (void) strcat(path, "/"); - (void) strcat(path, avd_get_str(fileset->fs_name)); - pathtmp = fileset_resolvepath(file); - (void) strcat(path, pathtmp); - free(pathtmp); + if (file == NULL) { + char path[MAXPATHLEN]; + char *pathtmp; - flowop_beginop(threadflow, flowop); - flowop_endop(threadflow, flowop, 0); + /* pick arbitrary, existing (allocated) file */ + if ((file = fileset_pick(fileset, FILESET_PICKEXISTS, 0)) + == NULL) { + filebench_log(LOG_DEBUG_SCRIPT, + "Statfile flowop %s failed to pick file", + flowop->fo_name); + return (FILEBENCH_NORSC); + } + + /* resolve path and do a stat on file */ + *path = 0; + (void) strcpy(path, avd_get_str(fileset->fs_path)); + (void) strcat(path, "/"); + (void) strcat(path, avd_get_str(fileset->fs_name)); + pathtmp = fileset_resolvepath(file); + (void) strcat(path, pathtmp); + free(pathtmp); + + /* stat the file */ + flowop_beginop(threadflow, flowop); + if (stat(path, &statbuf) == -1) + filebench_log(LOG_ERROR, + "statfile flowop %s failed", flowop->fo_name); + flowop_endop(threadflow, flowop, 0); - (void) ipc_mutex_unlock(&file->fse_lock); + fileset_unbusy(file, FALSE, FALSE); + } else { + /* stat specific file */ + flowop_beginop(threadflow, flowop); + if (fstat(threadflow->tf_fd[fd], &statbuf) == -1) + filebench_log(LOG_ERROR, + "statfile flowop %s failed", flowop->fo_name); + flowop_endop(threadflow, flowop, 0); + + } return (FILEBENCH_OK); } @@ -2565,6 +2628,24 @@ flowoplib_testrandvar_destruct(flowop_t *flowop) } /* + * prints message to the console from within a thread + */ +static int +flowoplib_print(threadflow_t *threadflow, flowop_t *flowop) +{ + procflow_t *procflow; + + procflow = threadflow->tf_process; + filebench_log(LOG_INFO, + "Message from process (%s,%d), thread (%s,%d): %s", + procflow->pf_name, procflow->pf_instance, + threadflow->tf_name, threadflow->tf_instance, + avd_get_str(flowop->fo_value)); + + return (FILEBENCH_OK); +} + +/* * Prints usage information for flowop operations. */ void diff --git a/usr/src/cmd/filebench/common/ipc.c b/usr/src/cmd/filebench/common/ipc.c index ae52ee9e43..f0bf6fd14e 100644 --- a/usr/src/cmd/filebench/common/ipc.c +++ b/usr/src/cmd/filebench/common/ipc.c @@ -23,8 +23,6 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include "config.h" #include <stdio.h> @@ -42,7 +40,6 @@ static int shmfd; filebench_shm_t *filebench_shm = NULL; -static pthread_mutexattr_t *mutexattr = NULL; /* * Interprocess Communication mechanisms. If multiple processes @@ -114,55 +111,76 @@ ipc_mutex_unlock(pthread_mutex_t *mutex) } /* - * On first invocation, allocates a mutex attributes structure - * and initializes it with appropriate attributes. In all cases, - * returns a pointer to the structure. + * Initialize mutex attributes for the various flavors of mutexes */ -pthread_mutexattr_t * -ipc_mutexattr(void) +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 - 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); - } + 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 (pthread_mutexattr_setprotocol(mutexattr, + if (mtx_type & IPC_MUTEX_PRIORITY) { + if (pthread_mutexattr_setprotocol(mtx_attrp, PTHREAD_PRIO_INHERIT) != 0) { - filebench_log(LOG_ERROR, "cannot set mutex attr " + 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, + 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 " + filebench_log(LOG_ERROR, + "cannot set mutex attr " "PTHREAD_MUTEX_ROBUST_NP on this platform"); filebench_shutdown(1); } - if (pthread_mutexattr_settype(mutexattr, + 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_log(LOG_ERROR, + "cannot set mutex attr " + "PTHREAD_MUTEX_ERRORCHECK " + "on this platform"); filebench_shutdown(1); } + } #endif /* HAVE_ROBUST_MUTEX */ +#endif /* USE_PROCESS_MODEL */ +} +/* + * 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(int mtx_type) +{ + if ((mtx_type >= IPC_NUM_MUTEX_ATTRS) || + (mtx_type < IPC_MUTEX_NORMAL)) { + filebench_log(LOG_ERROR, + "ipc_mutexattr called with undefined attr selector %d", + mtx_type); + return (&(filebench_shm->shm_mutexattr[IPC_MUTEX_NORMAL])); } -#endif /* USE_PROCESS_MODEL */ - return (mutexattr); + + return (&(filebench_shm->shm_mutexattr[mtx_type])); } static pthread_condattr_t *condattr = NULL; @@ -332,28 +350,36 @@ ipc_init(void) filebench_shm->shm_path_ptr = &filebench_shm->shm_filesetpaths[0]; /* 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_fileset_lock, - ipc_mutexattr()); + ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_procflow_lock, - ipc_mutexattr()); + ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_procs_running_lock, - ipc_mutexattr()); + ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_threadflow_lock, - ipc_mutexattr()); + ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_flowop_lock, - ipc_mutexattr()); + ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_msg_lock, - ipc_mutexattr()); + ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_eventgen_lock, - ipc_mutexattr()); + ipc_mutexattr(IPC_MUTEX_PRI_ROB)); (void) pthread_mutex_init(&filebench_shm->shm_malloc_lock, - ipc_mutexattr()); + ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_mutex_init(&filebench_shm->shm_ism_lock, - ipc_mutexattr()); + ipc_mutexattr(IPC_MUTEX_NORMAL)); (void) pthread_cond_init(&filebench_shm->shm_eventgen_cv, ipc_condattr()); (void) pthread_rwlock_init(&filebench_shm->shm_flowop_find_lock, ipc_rwlockattr()); +#ifdef USE_PROCESS_MODEL + (void) pthread_cond_init(&filebench_shm->shm_procflow_procs_cv, + ipc_condattr()); +#endif (void) pthread_rwlock_init(&filebench_shm->shm_run_lock, ipc_rwlockattr()); (void) pthread_rwlock_rdlock(&filebench_shm->shm_run_lock); diff --git a/usr/src/cmd/filebench/common/ipc.h b/usr/src/cmd/filebench/common/ipc.h index 0bb6ca48e4..937171ca10 100644 --- a/usr/src/cmd/filebench/common/ipc.h +++ b/usr/src/cmd/filebench/common/ipc.h @@ -26,8 +26,6 @@ #ifndef _FB_IPC_H #define _FB_IPC_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include "config.h" #include <pthread.h> @@ -48,6 +46,13 @@ extern "C" { #define FILEBENCH_MEMSIZE 2048 #endif /* USE_PROCESS_MODEL */ +/* Mutex Priority Inheritance and Robustness flags */ +#define IPC_MUTEX_NORMAL 0x0 +#define IPC_MUTEX_PRIORITY 0x1 +#define IPC_MUTEX_ROBUST 0x2 +#define IPC_MUTEX_PRI_ROB 0x3 +#define IPC_NUM_MUTEX_ATTRS 4 + #define FILEBENCH_NFILESETS FILEBENCH_MEMSIZE #define FILEBENCH_NFILESETENTRIES (1024 * 1024) #define FILEBENCH_NPROCFLOWS FILEBENCH_MEMSIZE @@ -80,56 +85,113 @@ extern "C" { #define FILEBENCH_MODE_QALLDONE 0x2 typedef struct filebench_shm { - pthread_mutex_t shm_fileset_lock; - pthread_mutex_t shm_procflow_lock; - pthread_mutex_t shm_threadflow_lock; - pthread_mutex_t shm_flowop_lock; - pthread_mutex_t shm_msg_lock; - pthread_mutex_t shm_malloc_lock; - pthread_mutex_t shm_ism_lock; + /* + * All state down to shm_marker are set to zero during filebench + * initialization + */ + + /* + * list of defined filesets and related locks. + */ + fileset_t *shm_filesetlist; /* list of defined filesets */ + pthread_mutex_t shm_fileset_lock; /* protects access to list */ + + /* + * parallel file allocation control. Restricts number of spawned + * allocation threads and allows waiting for allocation to finish. + */ + pthread_cond_t shm_fsparalloc_cv; /* cv to wait for alloc threads */ + int shm_fsparalloc_count; /* active alloc thread count */ + pthread_mutex_t shm_fsparalloc_lock; /* lock to protect count */ + + /* + * Procflow and process state + */ + procflow_t *shm_proclist; /* list of defined procflows */ + pthread_mutex_t shm_procflow_lock; /* protects shm_proclist */ + int shm_procs_running; /* count of running processes */ pthread_mutex_t shm_procs_running_lock; /* protects shm_procs_running */ - pthread_rwlock_t shm_run_lock; - pthread_rwlock_t shm_flowop_find_lock; + int shm_f_abort; /* stop the run NOW! */ + pthread_rwlock_t shm_run_lock; /* used as barrier to sync run */ +#ifdef USE_PROCESS_MODEL + pthread_cond_t shm_procflow_procs_cv; /* pauses procflow_init till */ +#endif /* all procflows are created */ + + /* + * flowop state + */ + flowop_t *shm_flowoplist; /* list of defined flowops */ + pthread_mutex_t shm_flowop_lock; /* protects flowoplist */ + pthread_rwlock_t shm_flowop_find_lock; /* prevents flowop_find() */ + /* during initial flowop creation */ + + /* + * lists related to variables + */ + + var_t *shm_var_list; /* normal variables */ + var_t *shm_var_dyn_list; /* special system variables */ + var_t *shm_var_loc_list; /* variables local to comp flowops */ + randdist_t *shm_rand_list; /* random variables */ + + /* + * log and statistics dumping controls and state + */ + int shm_debug_level; + int shm_bequiet; /* pause run while collecting stats */ + int shm_log_fd; /* log file descriptor */ + int shm_dump_fd; /* dump file descriptor */ + char shm_dump_filename[MAXPATHLEN]; + /* + * Event generator state + */ + int shm_eventgen_hz; /* number of events per sec. */ + uint64_t shm_eventgen_q; /* count of unclaimed events */ + pthread_mutex_t shm_eventgen_lock; /* lock protecting count */ + pthread_cond_t shm_eventgen_cv; /* cv to wait on for more events */ + + /* + * System 5 semaphore state + */ + key_t shm_semkey; + int shm_sys_semid; + char shm_semids[FILEBENCH_NSEMS]; + + /* + * Misc. pointers and state + */ + char shm_fscriptname[1024]; + int shm_id; + int shm_rmode; + int shm_1st_err; + pthread_mutex_t shm_threadflow_lock; + pthread_mutex_t shm_msg_lock; + pthread_mutexattr_t shm_mutexattr[IPC_NUM_MUTEX_ATTRS]; char *shm_string_ptr; char *shm_path_ptr; - fileset_t *shm_filesetlist; - flowop_t *shm_flowoplist; - procflow_t *shm_proclist; - var_t *shm_var_list; - var_t *shm_var_dyn_list; - randdist_t *shm_rand_list; - var_t *shm_var_loc_list; - int shm_debug_level; hrtime_t shm_epoch; hrtime_t shm_starttime; - int shm_bequiet; - key_t shm_semkey; - int shm_sys_semid; int shm_utid; - int shm_log_fd; - int shm_dump_fd; - char shm_dump_filename[MAXPATHLEN]; - pthread_mutex_t shm_eventgen_lock; - pthread_cond_t shm_eventgen_cv; - int shm_eventgen_hz; - uint64_t shm_eventgen_q; - char shm_fscriptname[1024]; - int shm_id; + + /* + * Shared memory allocation control + */ + pthread_mutex_t shm_malloc_lock; + pthread_mutex_t shm_ism_lock; + int shm_bitmap[FILEBENCH_TYPES][FILEBENCH_MAXBITMAP]; + int shm_lastbitmapindex[FILEBENCH_TYPES]; size_t shm_required; size_t shm_allocated; caddr_t shm_addr; char *shm_ptr; - int shm_procs_running; - int shm_f_abort; - int shm_rmode; - int shm_1st_err; - int shm_bitmap[FILEBENCH_TYPES][FILEBENCH_MAXBITMAP]; - int shm_lastbitmapindex[FILEBENCH_TYPES]; - char shm_semids[FILEBENCH_NSEMS]; - int shm_marker; + int shm_marker; /* end of pre-zeroed data */ + /* + * actual storage for shared entities. + * These are not zeroed during initialization + */ fileset_t shm_fileset[FILEBENCH_NFILESETS]; filesetentry_t shm_filesetentry[FILEBENCH_NFILESETENTRIES]; char shm_filesetpaths[FILEBENCH_FILESETPATHMEMORY]; @@ -148,7 +210,7 @@ void ipc_init(void); void *ipc_malloc(int type); void ipc_free(int type, char *addr); int ipc_attach(caddr_t shmaddr); -pthread_mutexattr_t *ipc_mutexattr(void); +pthread_mutexattr_t *ipc_mutexattr(int); pthread_condattr_t *ipc_condattr(void); int ipc_semidalloc(void); void ipc_semidfree(int semid); diff --git a/usr/src/cmd/filebench/common/procflow.c b/usr/src/cmd/filebench/common/procflow.c index 5cfe559802..4fe5495363 100644 --- a/usr/src/cmd/filebench/common/procflow.c +++ b/usr/src/cmd/filebench/common/procflow.c @@ -25,8 +25,6 @@ * Portions Copyright 2008 Denis Cheng */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <signal.h> #include <fcntl.h> #include <sys/stat.h> @@ -51,8 +49,6 @@ static enum create_n_wait { CNW_ERROR } cnw_wait; -static pthread_cond_t procflow_procs_created; - #endif /* USE_PROCESS_MODEL */ @@ -358,7 +354,7 @@ procflow_createnwait(void *nothing) else cnw_wait = CNW_ERROR; - if (pthread_cond_signal(&procflow_procs_created) != 0) + if (pthread_cond_signal(&filebench_shm->shm_procflow_procs_cv) != 0) exit(1); (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); @@ -429,15 +425,13 @@ procflow_init(void) (u_longlong_t)avd_get_int(procflow->pf_instances)); #ifdef USE_PROCESS_MODEL - if ((ret = pthread_cond_init(&procflow_procs_created, NULL)) != 0) - return (ret); if ((pthread_create(&tid, NULL, procflow_createnwait, NULL)) != 0) return (ret); (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); - if ((ret = pthread_cond_wait(&procflow_procs_created, + if ((ret = pthread_cond_wait(&filebench_shm->shm_procflow_procs_cv, &filebench_shm->shm_procflow_lock)) != 0) return (ret); @@ -638,12 +632,11 @@ procflow_shutdown(void) int wait_cnt; (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); - if (filebench_shm->shm_procs_running == 0) { + if (filebench_shm->shm_procs_running <= 0) { /* No processes running, so no need to do anything */ (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); return; } - filebench_shm->shm_procs_running = 0; (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); @@ -670,6 +663,11 @@ procflow_shutdown(void) filebench_shm->shm_f_abort = 0; (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); + + /* indicate all processes are stopped, even if some are "stuck" */ + (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); + filebench_shm->shm_procs_running = 0; + (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); } diff --git a/usr/src/cmd/filebench/common/threadflow.c b/usr/src/cmd/filebench/common/threadflow.c index bcbf243272..0d903cb367 100644 --- a/usr/src/cmd/filebench/common/threadflow.c +++ b/usr/src/cmd/filebench/common/threadflow.c @@ -25,8 +25,6 @@ * Portions Copyright 2008 Denis Cheng */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include "config.h" #include <pthread.h> #ifdef HAVE_LWPS @@ -426,7 +424,8 @@ threadflow_define_common(procflow_t *procflow, char *name, threadflow->tf_instance = instance; (void) strcpy(threadflow->tf_name, name); threadflow->tf_process = procflow; - (void) pthread_mutex_init(&threadflow->tf_lock, ipc_mutexattr()); + (void) pthread_mutex_init(&threadflow->tf_lock, + ipc_mutexattr(IPC_MUTEX_NORMAL)); filebench_log(LOG_DEBUG_IMPL, "Defining thread %s-%d", name, instance); diff --git a/usr/src/cmd/filebench/common/vars.h b/usr/src/cmd/filebench/common/vars.h index ede8dca983..d3f8185c97 100644 --- a/usr/src/cmd/filebench/common/vars.h +++ b/usr/src/cmd/filebench/common/vars.h @@ -26,8 +26,6 @@ #ifndef _FB_VARS_H #define _FB_VARS_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include "config.h" #include <stdio.h> @@ -75,7 +73,9 @@ typedef struct avd { } avd_val; } *avd_t; -#define AVD_IS_RANDOM(vp) ((vp)->avd_type == AVD_IND_RANDVAR) +#define AVD_IS_RANDOM(vp) ((vp) && ((vp)->avd_type == AVD_IND_RANDVAR)) +#define AVD_IS_STRING(vp) ((vp) && (((vp)->avd_type == AVD_VAL_STR) || \ + ((vp)->avd_type == AVD_VARVAL_STR))) typedef struct var { char *var_name; diff --git a/usr/src/cmd/filebench/workloads/Makefile b/usr/src/cmd/filebench/workloads/Makefile index a056d540aa..f7025f58e1 100644 --- a/usr/src/cmd/filebench/workloads/Makefile +++ b/usr/src/cmd/filebench/workloads/Makefile @@ -22,7 +22,6 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" .KEEP_STATE: @@ -47,6 +46,7 @@ WORKLOADS = \ filemicro_seqread.f \ filemicro_seqwrite.f \ filemicro_seqwriterand.f \ + filemicro_statfile.f \ filemicro_writefsync.f \ fileserver.f \ mongo.f \ diff --git a/usr/src/cmd/filebench/workloads/filemicro_statfile.f b/usr/src/cmd/filebench/workloads/filemicro_statfile.f new file mode 100644 index 0000000000..2098d8ce4a --- /dev/null +++ b/usr/src/cmd/filebench/workloads/filemicro_statfile.f @@ -0,0 +1,55 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Creates a fileset of $nfiles number of files, then loops through them +# using $nthreads number of threads, doing "stat" calls on each file. +# + +set $dir=/tmp +set $nfiles=10000 +set $meandirwidth=20 +set $filesize=128k +set $nthreads=20 + +define fileset name=bigfileset,path=$dir,size=$filesize,entries=$nfiles,dirwidth=$meandirwidth,prealloc=100 + +define process name=examinefiles,instances=1 +{ + thread name=examinefilethread, memsize=10m,instances=$nthreads + { + flowop statfile name=statfile1,filesetname=bigfileset + } +} + +echo "Stat File Version 1.0 personality successfully loaded" +usage "Usage: set \$dir=<dir> defaults to $dir" +usage " set \$filesize=<size> defaults to $filesize" +usage " set \$nfiles=<value> defaults to $nfiles" +usage " set \$nthreads=<value> defaults to $nthreads" +usage " set \$meandirwidth=<size> defaults to $meandirwidth" +usage "(sets mean dir width and dir depth is calculated as log (width, nfiles)" +usage " " +usage " run runtime (e.g. run 60)" diff --git a/usr/src/pkgdefs/SUNWfilebench/prototype_com b/usr/src/pkgdefs/SUNWfilebench/prototype_com index d6d4d67ee6..44a37e9849 100644 --- a/usr/src/pkgdefs/SUNWfilebench/prototype_com +++ b/usr/src/pkgdefs/SUNWfilebench/prototype_com @@ -23,8 +23,6 @@ # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# # packaging files i copyright @@ -69,6 +67,7 @@ f none usr/benchmarks/filebench/workloads/filemicro_seqwrite.f 444 root bin f none usr/benchmarks/filebench/workloads/filemicro_seqwriterand.f 444 root bin f none usr/benchmarks/filebench/workloads/filemicro_seqwriterandvargam.f 444 root bin f none usr/benchmarks/filebench/workloads/filemicro_seqwriterandvartab.f 444 root bin +f none usr/benchmarks/filebench/workloads/filemicro_statfile.f 444 root bin f none usr/benchmarks/filebench/workloads/filemicro_writefsync.f 444 root bin f none usr/benchmarks/filebench/workloads/fileserver.f 444 root bin f none usr/benchmarks/filebench/workloads/mongo.f 444 root bin |