summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authoraw148015 <Andrew.W.Wilson@sun.com>2008-10-27 11:14:30 -0700
committeraw148015 <Andrew.W.Wilson@sun.com>2008-10-27 11:14:30 -0700
commit0bb1cc7eeccb58d82ac6a19e80e41a3781810c28 (patch)
treeda69b8fc153d7fb6f58cf9fbb0306ee8bd5a725b /usr/src
parent5338c544ca00e11e246822f5d465dd162f781dbf (diff)
downloadillumos-joyent-0bb1cc7eeccb58d82ac6a19e80e41a3781810c28.tar.gz
6720351 FileBench should have a Video Server like workload
6725102 FileBench needs some directory manipulation flowops 6753319 SUNWfilebench package dependency issue in snv_99
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/filebench/common/eventgen.c40
-rw-r--r--usr/src/cmd/filebench/common/eventgen.h4
-rw-r--r--usr/src/cmd/filebench/common/filebench.h2
-rw-r--r--usr/src/cmd/filebench/common/fileset.c490
-rw-r--r--usr/src/cmd/filebench/common/fileset.h56
-rw-r--r--usr/src/cmd/filebench/common/flowop_library.c251
-rw-r--r--usr/src/cmd/filebench/common/ipc.h2
-rw-r--r--usr/src/cmd/filebench/common/parser_gram.y22
-rw-r--r--usr/src/cmd/filebench/common/parser_lex.l1
-rw-r--r--usr/src/cmd/filebench/common/utils.c71
-rw-r--r--usr/src/cmd/filebench/common/utils.h12
-rw-r--r--usr/src/cmd/filebench/common/vars.h3
-rw-r--r--usr/src/cmd/filebench/config/Makefile2
-rw-r--r--usr/src/cmd/filebench/config/videoserver.prof43
-rw-r--r--usr/src/cmd/filebench/workloads/Makefile5
-rw-r--r--usr/src/cmd/filebench/workloads/listdirs.f50
-rw-r--r--usr/src/cmd/filebench/workloads/makedirs.f51
-rw-r--r--usr/src/cmd/filebench/workloads/openfiles.f51
-rw-r--r--usr/src/cmd/filebench/workloads/removedirs.f51
-rw-r--r--usr/src/cmd/filebench/workloads/videoserver.f82
-rw-r--r--usr/src/pkgdefs/SUNWfilebench/depend6
-rw-r--r--usr/src/pkgdefs/SUNWfilebench/prototype_com6
22 files changed, 1108 insertions, 193 deletions
diff --git a/usr/src/cmd/filebench/common/eventgen.c b/usr/src/cmd/filebench/common/eventgen.c
index 5080004ba3..71dce57d6c 100644
--- a/usr/src/cmd/filebench/common/eventgen.c
+++ b/usr/src/cmd/filebench/common/eventgen.c
@@ -25,8 +25,6 @@
* Portions Copyright 2008 Denis Cheng
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* The event generator in this module is the producer half of a
* metering system which blocks flows using consumer routines in the
@@ -86,16 +84,18 @@ eventgen_thread(void)
while (1) {
struct timespec sleeptime;
hrtime_t delta;
- int count;
+ int count, rate;
- if (filebench_shm->shm_eventgen_hz == 0) {
+ if (filebench_shm->shm_eventgen_hz == NULL) {
(void) sleep(1);
continue;
+ } else {
+ rate = avd_get_int(filebench_shm->shm_eventgen_hz);
}
+
/* Sleep for 10xperiod */
sleeptime.tv_sec = 0;
- sleeptime.tv_nsec = FB_SEC2NSEC /
- filebench_shm->shm_eventgen_hz;
+ sleeptime.tv_nsec = FB_SEC2NSEC / rate;
sleeptime.tv_nsec *= 10;
if (sleeptime.tv_nsec < 1000UL)
@@ -108,7 +108,7 @@ eventgen_thread(void)
(void) nanosleep(&sleeptime, NULL);
delta = gethrtime() - last;
last = gethrtime();
- count = (filebench_shm->shm_eventgen_hz * delta) / FB_SEC2NSEC;
+ count = (rate * delta) / FB_SEC2NSEC;
filebench_log(LOG_DEBUG_SCRIPT,
"delta %llums count %d",
@@ -117,8 +117,7 @@ eventgen_thread(void)
/* Send 'count' events */
(void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
/* Keep the producer with a max of 5 second depth */
- if (filebench_shm->shm_eventgen_q <
- (5 * filebench_shm->shm_eventgen_hz))
+ if (filebench_shm->shm_eventgen_q < (5 * rate))
filebench_shm->shm_eventgen_q += count;
(void) pthread_cond_signal(&filebench_shm->shm_eventgen_cv);
@@ -157,22 +156,35 @@ eventgen_init(void)
var_t *
eventgen_ratevar(var_t *var)
{
- VAR_SET_INT(var, filebench_shm->shm_eventgen_hz);
+ VAR_SET_INT(var, avd_get_int(filebench_shm->shm_eventgen_hz));
return (var);
}
/*
* Sets the event generator rate to that supplied by
- * fbint_t rate.
+ * var_t *rate.
*/
void
-eventgen_setrate(fbint_t rate)
+eventgen_setrate(avd_t rate)
{
- filebench_shm->shm_eventgen_hz = (int)rate;
+ filebench_shm->shm_eventgen_hz = rate;
+ if (rate == NULL) {
+ filebench_log(LOG_ERROR,
+ "eventgen_setrate() called without a rate");
+ return;
+ }
+
+ if (AVD_IS_VAR(rate)) {
+ filebench_log(LOG_VERBOSE,
+ "Eventgen rate taken from variable");
+ } else {
+ filebench_log(LOG_VERBOSE, "Eventgen: %llu per second",
+ (u_longlong_t)avd_get_int(rate));
+ }
}
/*
- * Turns off the event generator by setting the rate to zero
+ * Clears the event queue so we have a clean start
*/
void
eventgen_reset(void)
diff --git a/usr/src/cmd/filebench/common/eventgen.h b/usr/src/cmd/filebench/common/eventgen.h
index 2f50fcac82..4797714224 100644
--- a/usr/src/cmd/filebench/common/eventgen.h
+++ b/usr/src/cmd/filebench/common/eventgen.h
@@ -26,8 +26,6 @@
#ifndef _FB_EVENTGEN_H
#define _FB_EVENTGEN_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "config.h"
#include "vars.h"
@@ -37,7 +35,7 @@ extern "C" {
#define FB_SEC2NSEC 1000000000UL
void eventgen_init(void);
-void eventgen_setrate(fbint_t rate);
+void eventgen_setrate(avd_t rate);
var_t *eventgen_ratevar(var_t *var);
void eventgen_usage(void);
void eventgen_reset(void);
diff --git a/usr/src/cmd/filebench/common/filebench.h b/usr/src/cmd/filebench/common/filebench.h
index d31df501c2..3c2e482bbb 100644
--- a/usr/src/cmd/filebench/common/filebench.h
+++ b/usr/src/cmd/filebench/common/filebench.h
@@ -117,7 +117,7 @@ void filebench_shutdown(int error);
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif
-#define FILEBENCH_VERSION "1.4.0"
+#define FILEBENCH_VERSION "1.4.1"
#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 99ee2887c9..4521913ec7 100644
--- a/usr/src/cmd/filebench/common/fileset.c
+++ b/usr/src/cmd/filebench/common/fileset.c
@@ -35,6 +35,7 @@
#include "filebench.h"
#include "fileset.h"
#include "gamma_dist.h"
+#include "utils.h"
/*
* File sets, of type fileset_t, are entities which contain
@@ -48,9 +49,10 @@
* 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.
+ * medium is built by fileset_populate(), which is This routine is called
+ * from fileset_createset(), which is in turn called by 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
@@ -129,8 +131,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 times the number of
- * times msync() failed.
+ * If successful, returns 0. Otherwise returns -1 if "size"
+ * is zero, or -1 times the number of times msync() failed.
*/
static int
fileset_freemem(int fd, off64_t size)
@@ -166,17 +168,17 @@ fileset_resolvepath(filesetentry_t *entry)
char pathtmp[MAXPATHLEN];
char *s;
- *path = 0;
+ path[0] = '\0';
while (fsep->fse_parent) {
(void) strcpy(pathtmp, "/");
- (void) strcat(pathtmp, fsep->fse_path);
- (void) strcat(pathtmp, path);
- (void) strcpy(path, pathtmp);
+ (void) fb_strlcat(pathtmp, fsep->fse_path, MAXPATHLEN);
+ (void) fb_strlcat(pathtmp, path, MAXPATHLEN);
+ (void) fb_strlcpy(path, pathtmp, MAXPATHLEN);
fsep = fsep->fse_parent;
}
s = malloc(strlen(path) + 1);
- (void) strcpy(s, path);
+ (void) fb_strlcpy(s, path, MAXPATHLEN);
return (s);
}
@@ -233,7 +235,6 @@ null_str:
filebench_log(LOG_ERROR,
"Failed to create directory path %s: Out of memory", path);
-
return (FILEBENCH_ERROR);
}
@@ -250,9 +251,9 @@ fileset_create_subdirs(fileset_t *fileset, char *filesetpath)
/* walk the subdirectory list, enstanciating subdirs */
direntry = fileset->fs_dirlist;
while (direntry) {
- (void) strcpy(full_path, filesetpath);
+ (void) fb_strlcpy(full_path, filesetpath, MAXPATHLEN);
part_path = fileset_resolvepath(direntry);
- (void) strcat(full_path, part_path);
+ (void) fb_strlcat(full_path, part_path, MAXPATHLEN);
free(part_path);
/* now create this portion of the subdirectory tree */
@@ -265,12 +266,56 @@ fileset_create_subdirs(fileset_t *fileset, char *filesetpath)
}
/*
+ * given a fileset entry, determines if the associated leaf directory
+ * needs to be made or not, and if so does the mkdir.
+ */
+static int
+fileset_alloc_leafdir(filesetentry_t *entry)
+{
+ fileset_t *fileset;
+ char path[MAXPATHLEN];
+ struct stat64 sb;
+ char *pathtmp;
+
+ fileset = entry->fse_fileset;
+ (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
+ (void) fb_strlcat(path, "/", MAXPATHLEN);
+ (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
+ pathtmp = fileset_resolvepath(entry);
+ (void) fb_strlcat(path, pathtmp, MAXPATHLEN);
+ free(pathtmp);
+
+ filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path);
+
+ /* see if not reusing and this directory does not exist */
+ if (!((entry->fse_flags & FSE_REUSING) && (stat64(path, &sb) == 0))) {
+
+ /* No file or not reusing, so create */
+ if (mkdir(path, 0755) < 0) {
+ filebench_log(LOG_ERROR,
+ "Failed to pre-allocate leaf directory %s: %s",
+ path, strerror(errno));
+
+ return (FILEBENCH_ERROR);
+ }
+ }
+
+ (void) ipc_mutex_lock(&fileset->fs_pick_lock);
+ entry->fse_flags |= FSE_EXISTS;
+ fileset->fs_num_act_leafdirs++;
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
+
+ return (FILEBENCH_OK);
+}
+
+/*
* given a fileset entry, determines if the associated file
* needs to be allocated or not, and if so does the allocation.
*/
static int
fileset_alloc_file(filesetentry_t *entry)
{
+ fileset_t *fileset;
char path[MAXPATHLEN];
char *buf;
struct stat64 sb;
@@ -278,12 +323,13 @@ fileset_alloc_file(filesetentry_t *entry)
off64_t seek;
int fd;
- *path = 0;
- (void) strcpy(path, avd_get_str(entry->fse_fileset->fs_path));
- (void) strcat(path, "/");
- (void) strcat(path, avd_get_str(entry->fse_fileset->fs_name));
+ fileset = entry->fse_fileset;
+ (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
+ (void) fb_strlcat(path, "/", MAXPATHLEN);
+ (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
pathtmp = fileset_resolvepath(entry);
- (void) strcat(path, pathtmp);
+ (void) fb_strlcat(path, pathtmp, MAXPATHLEN);
+ free(pathtmp);
filebench_log(LOG_DEBUG_IMPL, "Populated %s", entry->fse_path);
@@ -300,16 +346,14 @@ fileset_alloc_file(filesetentry_t *entry)
filebench_log(LOG_DEBUG_IMPL,
"Re-using file %s", path);
- if (!avd_get_bool(entry->fse_fileset->fs_cached))
+ if (!avd_get_bool(fileset->fs_cached))
(void) fileset_freemem(fd,
entry->fse_size);
- (void) ipc_mutex_lock(
- &entry->fse_fileset->fs_pick_lock);
+ (void) ipc_mutex_lock(&fileset->fs_pick_lock);
entry->fse_flags |= FSE_EXISTS;
- entry->fse_fileset->fs_num_act_files++;
- (void) ipc_mutex_unlock(
- &entry->fse_fileset->fs_pick_lock);
+ fileset->fs_num_act_files++;
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
(void) close(fd);
return (FILEBENCH_OK);
@@ -325,16 +369,14 @@ fileset_alloc_file(filesetentry_t *entry)
(void) ftruncate(fd, (off_t)entry->fse_size);
#endif
- if (!avd_get_bool(entry->fse_fileset->fs_cached))
+ if (!avd_get_bool(fileset->fs_cached))
(void) fileset_freemem(fd,
entry->fse_size);
- (void) ipc_mutex_lock(
- &entry->fse_fileset->fs_pick_lock);
+ (void) ipc_mutex_lock(&fileset->fs_pick_lock);
entry->fse_flags |= FSE_EXISTS;
- entry->fse_fileset->fs_num_act_files++;
- (void) ipc_mutex_unlock(
- &entry->fse_fileset->fs_pick_lock);
+ fileset->fs_num_act_files++;
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
(void) close(fd);
return (FILEBENCH_OK);
@@ -354,10 +396,10 @@ fileset_alloc_file(filesetentry_t *entry)
if ((buf = (char *)malloc(FILE_ALLOC_BLOCK)) == NULL)
return (FILEBENCH_ERROR);
- (void) ipc_mutex_lock(&entry->fse_fileset->fs_pick_lock);
+ (void) ipc_mutex_lock(&fileset->fs_pick_lock);
entry->fse_flags |= FSE_EXISTS;
- entry->fse_fileset->fs_num_act_files++;
- (void) ipc_mutex_unlock(&entry->fse_fileset->fs_pick_lock);
+ fileset->fs_num_act_files++;
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
for (seek = 0; seek < entry->fse_size; ) {
off64_t wsize;
@@ -381,7 +423,7 @@ fileset_alloc_file(filesetentry_t *entry)
seek += wsize;
}
- if (!avd_get_bool(entry->fse_fileset->fs_cached))
+ if (!avd_get_bool(fileset->fs_cached))
(void) fileset_freemem(fd, entry->fse_size);
(void) close(fd);
@@ -438,13 +480,12 @@ fileset_openfile(fileset_t *fileset,
int fd;
int open_attrs = 0;
- *path = 0;
- (void) strcpy(path, avd_get_str(fileset->fs_path));
- (void) strcat(path, "/");
- (void) strcat(path, avd_get_str(fileset->fs_name));
+ (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
+ (void) fb_strlcat(path, "/", MAXPATHLEN);
+ (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
pathtmp = fileset_resolvepath(entry);
- (void) strcat(path, pathtmp);
- (void) strcpy(dir, path);
+ (void) fb_strlcat(path, pathtmp, MAXPATHLEN);
+ (void) fb_strlcpy(dir, path, MAXPATHLEN);
free(pathtmp);
(void) trunc_dirname(dir);
@@ -489,7 +530,8 @@ fileset_openfile(fileset_t *fileset,
/*
* Selects a fileset entry from a fileset. If the
- * FILESET_PICKDIR flag is set it will pick a directory
+ * FILESET_PICKLEAFDIR flag is set it will pick a leaf directory entry,
+ * if the FILESET_PICKDIR flag is set it will pick a non leaf directory
* entry, otherwise a file entry. The FILESET_PICKRESET
* flag will cause it to reset the free list to the
* overall list (file or directory). The FILESET_PICKUNIQUE
@@ -512,72 +554,130 @@ fileset_pick(fileset_t *fileset, int flags, int tid)
(void) ipc_mutex_lock(&fileset->fs_pick_lock);
/* see if we have to wait for available files or directories */
- if (flags & FILESET_PICKDIR) {
+ switch (flags & FILESET_PICKMASK) {
+ case FILESET_PICKFILE:
+ if (fileset->fs_filelist == NULL)
+ goto empty;
+ while (fileset->fs_idle_files == 0) {
+ (void) pthread_cond_wait(&fileset->fs_idle_files_cv,
+ &fileset->fs_pick_lock);
+ }
+ break;
+ case FILESET_PICKDIR:
+ if (fileset->fs_dirlist == NULL)
+ goto empty;
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,
+ break;
+ case FILESET_PICKLEAFDIR:
+ if (fileset->fs_leafdirlist == NULL)
+ goto empty;
+ while (fileset->fs_idle_leafdirs == 0) {
+ (void) pthread_cond_wait(&fileset->fs_idle_leafdirs_cv,
&fileset->fs_pick_lock);
}
+ break;
}
/* see if asking for impossible */
- if (flags & FILESET_PICKEXISTS) {
- if (fileset->fs_num_act_files == 0) {
- (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
- return (NULL);
+ switch (flags & FILESET_PICKMASK) {
+ case FILESET_PICKFILE:
+ if (flags & FILESET_PICKEXISTS) {
+ if (fileset->fs_num_act_files == 0) {
+ (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_pick_lock);
+ return (NULL);
+ }
}
- } else if (flags & FILESET_PICKNOEXIST) {
- if (fileset->fs_num_act_files == fileset->fs_realfiles) {
- (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
- return (NULL);
+ break;
+ case FILESET_PICKLEAFDIR:
+ if (flags & FILESET_PICKEXISTS) {
+ if (fileset->fs_num_act_leafdirs == 0) {
+ (void) ipc_mutex_unlock(
+ &fileset->fs_pick_lock);
+ return (NULL);
+ }
+ } else if (flags & FILESET_PICKNOEXIST) {
+ if (fileset->fs_num_act_leafdirs ==
+ fileset->fs_realleafdirs) {
+ (void) ipc_mutex_unlock(
+ &fileset->fs_pick_lock);
+ return (NULL);
+ }
}
+ break;
+ case FILESET_PICKDIR:
+ default:
+ break;
}
while (entry == NULL) {
- if ((flags & FILESET_PICKDIR) && (flags & FILESET_PICKRESET)) {
- entry = fileset->fs_dirlist;
- while (entry) {
- entry->fse_flags |= FSE_FREE;
- entry = entry->fse_dirnext;
- }
- fileset->fs_dirfree = fileset->fs_dirlist;
- }
-
- if (!(flags & FILESET_PICKDIR) && (flags & FILESET_PICKRESET)) {
- entry = fileset->fs_filelist;
- while (entry) {
- entry->fse_flags |= FSE_FREE;
- entry = entry->fse_filenext;
+ if (flags & FILESET_PICKRESET) {
+ switch (flags & FILESET_PICKMASK) {
+ case FILESET_PICKFILE:
+ entry = fileset->fs_filelist;
+ while (entry) {
+ entry->fse_flags |= FSE_FREE;
+ entry = entry->fse_filenext;
+ }
+ fileset->fs_filefree = fileset->fs_filelist;
+ break;
+ case FILESET_PICKDIR:
+ entry = fileset->fs_dirlist;
+ while (entry) {
+ entry->fse_flags |= FSE_FREE;
+ entry = entry->fse_dirnext;
+ }
+ fileset->fs_dirfree = fileset->fs_dirlist;
+ break;
+ case FILESET_PICKLEAFDIR:
+ entry = fileset->fs_leafdirlist;
+ while (entry) {
+ entry->fse_flags |= FSE_FREE;
+ entry = entry->fse_leafdirnext;
+ }
+ fileset->fs_leafdirfree =
+ fileset->fs_leafdirlist;
+ break;
}
- fileset->fs_filefree = fileset->fs_filelist;
}
if (flags & FILESET_PICKUNIQUE) {
- if (flags & FILESET_PICKDIR) {
+ switch (flags & FILESET_PICKMASK) {
+ case FILESET_PICKFILE:
+ entry = fileset->fs_filefree;
+ if (entry == NULL)
+ goto empty;
+ fileset->fs_filefree = entry->fse_filenext;
+ break;
+ case FILESET_PICKDIR:
entry = fileset->fs_dirfree;
if (entry == NULL)
goto empty;
fileset->fs_dirfree = entry->fse_dirnext;
- } else {
- entry = fileset->fs_filefree;
+ break;
+ case FILESET_PICKLEAFDIR:
+ entry = fileset->fs_leafdirfree;
if (entry == NULL)
goto empty;
- fileset->fs_filefree = entry->fse_filenext;
+ fileset->fs_leafdirfree =
+ entry->fse_leafdirnext;
+ break;
}
entry->fse_flags &= ~FSE_FREE;
} else {
- if (flags & FILESET_PICKDIR) {
- entry = fileset->fs_dirrotor;
- if (entry == NULL)
- fileset->fs_dirrotor =
- entry = fileset->fs_dirlist;
- fileset->fs_dirrotor = entry->fse_dirnext;
- } else {
+ switch (flags & FILESET_PICKMASK) {
+ case FILESET_PICKFILE:
if (flags & FILESET_PICKNOEXIST) {
entry = fileset->fs_file_ne_rotor;
if (entry == NULL)
@@ -595,6 +695,22 @@ fileset_pick(fileset_t *fileset, int flags, int tid)
fileset->fs_filerotor[tid] =
entry->fse_filenext;
}
+ break;
+ case FILESET_PICKDIR:
+ entry = fileset->fs_dirrotor;
+ if (entry == NULL)
+ fileset->fs_dirrotor =
+ entry = fileset->fs_dirlist;
+ fileset->fs_dirrotor = entry->fse_dirnext;
+ break;
+ case FILESET_PICKLEAFDIR:
+ entry = fileset->fs_leafdirrotor;
+ if (entry == NULL)
+ fileset->fs_leafdirrotor =
+ entry = fileset->fs_leafdirlist;
+ fileset->fs_leafdirrotor =
+ entry->fse_leafdirnext;
+ break;
}
}
@@ -624,10 +740,17 @@ fileset_pick(fileset_t *fileset, int flags, int tid)
}
/* update file or directory idle counts */
- if (flags & FILESET_PICKDIR)
- fileset->fs_idle_dirs--;
- else
+ switch (flags & FILESET_PICKMASK) {
+ case FILESET_PICKFILE:
fileset->fs_idle_files--;
+ break;
+ case FILESET_PICKDIR:
+ fileset->fs_idle_dirs--;
+ break;
+ case FILESET_PICKLEAFDIR:
+ fileset->fs_idle_leafdirs--;
+ break;
+ }
/* Indicate that file or directory is now busy */
entry->fse_flags |= FSE_BUSY;
@@ -650,7 +773,6 @@ 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;
@@ -661,7 +783,6 @@ fileset_unbusy(filesetentry_t *entry, int update_exist, int new_exist_val)
}
(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) {
@@ -677,18 +798,28 @@ fileset_unbusy(filesetentry_t *entry, int update_exist, int new_exist_val)
}
/* increment idle count and signal waiting threads */
- if (fse_is_dir) {
+ switch (entry->fse_flags & FSE_TYPE_MASK) {
+ case FSE_TYPE_FILE:
+ fileset->fs_idle_files++;
+ if (fileset->fs_idle_files == 1) {
+ (void) pthread_cond_signal(
+ &fileset->fs_idle_files_cv);
+ }
+ break;
+ case FSE_TYPE_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) {
+ break;
+ case FSE_TYPE_LEAFDIR:
+ fileset->fs_idle_leafdirs++;
+ if (fileset->fs_idle_leafdirs == 1) {
(void) pthread_cond_signal(
- &fileset->fs_idle_files_cv);
+ &fileset->fs_idle_leafdirs_cv);
}
+ break;
}
}
@@ -699,20 +830,32 @@ fileset_unbusy(filesetentry_t *entry, int update_exist, int new_exist_val)
/* asked to set, and it was clear */
entry->fse_flags |= FSE_EXISTS;
- if (fse_is_dir)
- fileset->fs_num_act_dirs++;
- else
+ switch (entry->fse_flags & FSE_TYPE_MASK) {
+ case FSE_TYPE_FILE:
fileset->fs_num_act_files++;
+ break;
+ case FSE_TYPE_DIR:
+ break;
+ case FSE_TYPE_LEAFDIR:
+ fileset->fs_num_act_leafdirs++;
+ break;
+ }
}
} 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
+ switch (entry->fse_flags & FSE_TYPE_MASK) {
+ case FSE_TYPE_FILE:
fileset->fs_num_act_files--;
+ break;
+ case FSE_TYPE_DIR:
+ break;
+ case FSE_TYPE_LEAFDIR:
+ fileset->fs_num_act_leafdirs--;
+ break;
+ }
}
}
}
@@ -741,7 +884,7 @@ fileset_create(fileset_t *fileset)
filesetentry_t *entry;
char path[MAXPATHLEN];
struct stat64 sb;
- int pickflags = FILESET_PICKUNIQUE | FILESET_PICKRESET;
+ int pickflags;
hrtime_t start = gethrtime();
char *fileset_path;
char *fileset_name;
@@ -761,6 +904,9 @@ fileset_create(fileset_t *fileset)
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)
@@ -770,9 +916,9 @@ fileset_create(fileset_t *fileset)
/* XXX Add check to see if there is enough space */
/* set up path to fileset */
- (void) strcpy(path, fileset_path);
- (void) strcat(path, "/");
- (void) strcat(path, fileset_name);
+ (void) fb_strlcpy(path, fileset_path, MAXPATHLEN);
+ (void) fb_strlcat(path, "/", MAXPATHLEN);
+ (void) fb_strlcat(path, fileset_name, MAXPATHLEN);
/* if exists and resusing, then don't create new */
if (((stat64(path, &sb) == 0)&& (strlen(path) > 3) &&
@@ -802,7 +948,7 @@ fileset_create(fileset_t *fileset)
/* make the filesets directory tree unless in reuse mode */
if (!reusing && (avd_get_bool(fileset->fs_prealloc))) {
- filebench_log(LOG_INFO,
+ filebench_log(LOG_VERBOSE,
"making tree for filset %s", path);
(void) mkdir(path, 0755);
@@ -822,6 +968,8 @@ fileset_create(fileset_t *fileset)
randno = ((RAND_MAX * (100
- avd_get_int(fileset->fs_preallocpercent))) / 100);
+ /* alloc any files, as required */
+ pickflags = FILESET_PICKUNIQUE | FILESET_PICKRESET;
while (entry = fileset_pick(fileset, pickflags, 0)) {
pthread_t tid;
int newrand;
@@ -892,6 +1040,30 @@ fileset_create(fileset_t *fileset)
}
}
+ /* alloc any leaf directories, as required */
+ pickflags =
+ FILESET_PICKUNIQUE | FILESET_PICKRESET | FILESET_PICKLEAFDIR;
+ while (entry = fileset_pick(fileset, pickflags, 0)) {
+
+ pickflags = FILESET_PICKUNIQUE | FILESET_PICKLEAFDIR;
+
+ /* entry doesn't need to be locked during initialization */
+ fileset_unbusy(entry, FALSE, FALSE);
+
+ if (rand() < randno)
+ continue;
+
+ preallocated++;
+
+ if (reusing)
+ entry->fse_flags |= FSE_REUSING;
+ else
+ entry->fse_flags &= (~FSE_REUSING);
+
+ if (fileset_alloc_leafdir(entry) == FILEBENCH_ERROR)
+ return (FILEBENCH_ERROR);
+ }
+
exit:
filebench_log(LOG_VERBOSE,
"Preallocated %d of %llu of %s %s in %llu seconds",
@@ -936,7 +1108,23 @@ fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry)
}
/*
- * Obtaines a filesetentry entity for a file to be placed in a
+ * Adds an entry to the fileset's leaf directory list. Single
+ * threaded so no locking needed.
+ */
+static void
+fileset_insleafdirlist(fileset_t *fileset, filesetentry_t *entry)
+{
+ if (fileset->fs_leafdirlist == NULL) {
+ fileset->fs_leafdirlist = entry;
+ entry->fse_leafdirnext = NULL;
+ } else {
+ entry->fse_leafdirnext = fileset->fs_leafdirlist;
+ fileset->fs_leafdirlist = entry;
+ }
+}
+
+/*
+ * Obtains 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 fileset_meansize, or calculated from a gamma
* distribution of parameter fileset_sizegamma and of mean size
@@ -968,7 +1156,7 @@ fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial)
entry->fse_parent = parent;
entry->fse_fileset = fileset;
- entry->fse_flags = FSE_FREE;
+ entry->fse_flags = FSE_TYPE_FILE | FSE_FREE;
fileset_insfilelist(fileset, entry);
(void) snprintf(tmpname, sizeof (tmpname), "%08d", serial);
@@ -1001,6 +1189,50 @@ fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial)
}
/*
+ * Obtaines a filesetentry entity for a leaf directory to be placed in a
+ * (sub)directory of a fileset. The leaf directory will always be empty so
+ * it can be created and deleted (mkdir, rmdir) at will. The filesetentry
+ * entity is placed on the leaf directory list in the specified parent
+ * filesetentry entity, which may be a (sub) directory filesetentry, or
+ * the root filesetentry in the fileset. It is also placed on the fileset's
+ * list of all contained leaf directories. Returns FILEBENCH_OK if successful
+ * or FILEBENCH_ERROR if ipc memory cannot be allocated.
+ */
+static int
+fileset_populate_leafdir(fileset_t *fileset, filesetentry_t *parent, int serial)
+{
+ char tmpname[16];
+ filesetentry_t *entry;
+
+ if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY))
+ == NULL) {
+ filebench_log(LOG_ERROR,
+ "fileset_populate_file: Can't malloc filesetentry");
+ return (FILEBENCH_ERROR);
+ }
+
+ /* Another currently idle leaf directory */
+ (void) ipc_mutex_lock(&fileset->fs_pick_lock);
+ fileset->fs_idle_leafdirs++;
+ (void) ipc_mutex_unlock(&fileset->fs_pick_lock);
+
+ entry->fse_parent = parent;
+ entry->fse_fileset = fileset;
+ entry->fse_flags = FSE_TYPE_LEAFDIR | FSE_FREE;
+ fileset_insleafdirlist(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 (FILEBENCH_ERROR);
+ }
+
+ fileset->fs_realleafdirs++;
+ return (FILEBENCH_OK);
+}
+
+/*
* 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
@@ -1052,7 +1284,8 @@ fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent,
}
entry->fse_parent = parent;
- entry->fse_flags = FSE_DIR | FSE_FREE;
+ entry->fse_fileset = fileset;
+ entry->fse_flags = FSE_TYPE_DIR | FSE_FREE;
fileset_insdirlist(fileset, entry);
if (fileset->fs_dirdepthrv) {
@@ -1093,8 +1326,8 @@ fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent,
isleaf = 1;
/*
- * Create directory of random width according to distribution, or
- * if root directory, continue until #files required
+ * Create directory of random width filled with files according
+ * to distribution, or if root directory, continue until #files required
*/
for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) &&
(fileset->fs_realfiles < fileset->fs_constentries);
@@ -1109,6 +1342,26 @@ fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent,
if (ret != 0)
return (ret);
}
+
+ /*
+ * Create directory of random width filled with leaf directories
+ * according to distribution, or if root directory, continue until
+ * the number of leaf directories required has been generated.
+ */
+ for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) &&
+ (fileset->fs_realleafdirs < fileset->fs_constleafdirs);
+ i++) {
+ int ret = 0;
+
+ if (parent && isleaf)
+ ret = fileset_populate_leafdir(fileset, entry, i);
+ else
+ ret = fileset_populate_subdir(fileset, entry, i, depth);
+
+ if (ret != 0)
+ return (ret);
+ }
+
return (FILEBENCH_OK);
}
@@ -1127,6 +1380,7 @@ static int
fileset_populate(fileset_t *fileset)
{
int entries = (int)avd_get_int(fileset->fs_entries);
+ int leafdirs = (int)avd_get_int(fileset->fs_leafdirs);
int meandirwidth;
int ret;
@@ -1140,19 +1394,26 @@ fileset_populate(fileset_t *fileset)
return (FILEBENCH_OK);
#endif /* HAVE_RAW_SUPPORT */
- /* save value of entries obtained for later, in case it was random */
+ /*
+ * save value of entries and leaf dirs obtained for later
+ * in case it was random
+ */
fileset->fs_constentries = entries;
+ fileset->fs_constleafdirs = leafdirs;
- /* declare all files currently non existant */
+ /* declare all files and leafdirs currently non existant */
fileset->fs_num_act_files = 0;
+ fileset->fs_num_act_leafdirs = 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());
+ (void) pthread_cond_init(&fileset->fs_idle_dirs_cv, ipc_condattr());
+ (void) pthread_cond_init(&fileset->fs_idle_leafdirs_cv, ipc_condattr());
/* no files or dirs idle (or busy) yet */
fileset->fs_idle_files = 0;
fileset->fs_idle_dirs = 0;
+ fileset->fs_idle_leafdirs = 0;
/* initialize locks and other condition variables */
(void) pthread_mutex_init(&fileset->fs_pick_lock,
@@ -1177,7 +1438,7 @@ fileset_populate(fileset_t *fileset)
* # ave size of file
* max size of file
*/
- fileset->fs_meandepth = log(entries) / log(meandirwidth);
+ fileset->fs_meandepth = log(entries+leafdirs) / log(meandirwidth);
/* Has a random variable been supplied for dirdepth? */
if (fileset->fs_dirdepthrv) {
@@ -1202,9 +1463,9 @@ exists:
avd_get_str(fileset->fs_name),
(u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL));
} else {
- filebench_log(LOG_VERBOSE, "Fileset %s: %d files, "
+ filebench_log(LOG_VERBOSE, "Fileset %s: %d files, %d leafdirs "
"avg dir = %d, avg depth = %.1lf, mbytes=%llu",
- avd_get_str(fileset->fs_name), entries,
+ avd_get_str(fileset->fs_name), entries, leafdirs,
meandirwidth,
fileset->fs_meandepth,
(u_longlong_t)(fileset->fs_bytes / 1024UL / 1024UL));
@@ -1456,6 +1717,7 @@ fileset_print(fileset_t *fileset, int first)
}
return (FILEBENCH_OK);
}
+
/*
* checks to see if the path/name pair points to a raw device. If
* so it sets the raw device flag (FILESET_IS_RAW_DEV) and returns 1.
@@ -1480,9 +1742,9 @@ fileset_checkraw(fileset_t *fileset)
if ((setname = avd_get_str(fileset->fs_name)) == NULL)
return (FILEBENCH_OK);
- (void) strcpy(path, pathname);
- (void) strcat(path, "/");
- (void) strcat(path, setname);
+ (void) fb_strlcpy(path, pathname, MAXPATHLEN);
+ (void) fb_strlcat(path, "/", MAXPATHLEN);
+ (void) fb_strlcat(path, setname, MAXPATHLEN);
if ((stat64(path, &sb) == 0) &&
((sb.st_mode & S_IFMT) == S_IFBLK) && sb.st_rdev) {
fileset->fs_attrs |= FILESET_IS_RAW_DEV;
diff --git a/usr/src/cmd/filebench/common/fileset.h b/usr/src/cmd/filebench/common/fileset.h
index 84ca652c3f..fa08b443c5 100644
--- a/usr/src/cmd/filebench/common/fileset.h
+++ b/usr/src/cmd/filebench/common/fileset.h
@@ -59,18 +59,22 @@ extern "C" {
#define FSE_MAXTID 16384
#define FSE_MAXPATHLEN 16
-#define FSE_DIR 0x01
-#define FSE_FREE 0x02
-#define FSE_EXISTS 0x04
-#define FSE_BUSY 0x08
-#define FSE_THRD_WAITNG 0x10
-#define FSE_REUSING 0x20
+#define FSE_TYPE_FILE 0x00
+#define FSE_TYPE_DIR 0x01
+#define FSE_TYPE_LEAFDIR 0x02
+#define FSE_TYPE_MASK 0x03
+#define FSE_FREE 0x04
+#define FSE_EXISTS 0x08
+#define FSE_BUSY 0x10
+#define FSE_REUSING 0x20
+#define FSE_THRD_WAITNG 0x40
typedef struct filesetentry {
struct filesetentry *fse_next;
struct filesetentry *fse_parent;
struct filesetentry *fse_filenext; /* List of files */
struct filesetentry *fse_dirnext; /* List of directories */
+ struct filesetentry *fse_leafdirnext; /* List of leaf dirs */
struct fileset *fse_fileset; /* Parent fileset */
char *fse_path;
int fse_depth;
@@ -78,10 +82,15 @@ typedef struct filesetentry {
int fse_flags; /* protected by fs_pick_lock */
} filesetentry_t;
-#define FILESET_PICKANY 0x1 /* Pick any file from the set */
-#define FILESET_PICKUNIQUE 0x2 /* Pick a unique file from set until empty */
-#define FILESET_PICKRESET 0x4 /* Reset FILESET_PICKUNIQUE selection list */
-#define FILESET_PICKDIR 0x8 /* Pick a directory */
+/* type of fileset entry to obtain */
+#define FILESET_PICKFILE 0x00 /* Pick a file from the set */
+#define FILESET_PICKDIR 0x01 /* Pick a directory */
+#define FILESET_PICKLEAFDIR 0x02 /* Pick a leaf directory */
+#define FILESET_PICKMASK 0x03 /* Pick type mask */
+/* other pick flags */
+#define FILESET_PICKUNIQUE 0x04 /* Pick a unique file or leafdir from the */
+ /* fileset until empty */
+#define FILESET_PICKRESET 0x08 /* Reset FILESET_PICKUNIQUE selection list */
#define FILESET_PICKEXISTS 0x10 /* Pick an existing file */
#define FILESET_PICKNOEXIST 0x20 /* Pick a file that doesn't exist */
@@ -96,6 +105,10 @@ typedef struct fileset {
avd_t fs_entries; /* Number of entries attr */
/* (possibly random) */
fbint_t fs_constentries; /* Constant version of enties attr */
+ avd_t fs_leafdirs; /* Number of leaf directories attr */
+ /* (possibly random) */
+ fbint_t fs_constleafdirs; /* Constant version of leafdirs */
+ /* attr */
avd_t fs_preallocpercent; /* Prealloc size */
int fs_attrs; /* Attributes */
avd_t fs_dirwidth; /* Explicit or mean for distribution */
@@ -116,28 +129,37 @@ typedef struct fileset {
double fs_meanwidth; /* Specified mean dir width */
double fs_meansize; /* Specified mean file size */
int fs_realfiles; /* Actual files */
+ int fs_realleafdirs; /* Actual explicit leaf directories */
off64_t fs_bytes; /* Total space consumed by files */
+
+ int64_t fs_idle_files; /* number of files NOT busy */
+ pthread_cond_t fs_idle_files_cv; /* idle files condition variable */
fbint_t fs_num_act_files; /* total number of files */
/* actually existing in the */
/* host or server's file system */
- 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 */
+
+ int64_t fs_idle_leafdirs; /* number of dirs NOT busy */
+ pthread_cond_t fs_idle_leafdirs_cv; /* idle dirs condition variable */
+ fbint_t fs_num_act_leafdirs; /* total number of leaf dirs */
+ /* actually existing in the */
+ /* host or server's file system */
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_dirlist; /* List of directories */
+ filesetentry_t *fs_dirfree; /* List of free directories */
filesetentry_t *fs_dirrotor; /* Ptr to next directory to select */
+ filesetentry_t *fs_leafdirlist; /* List of leaf directories */
+ filesetentry_t *fs_leafdirfree; /* Ptr to next free leaf directory */
+ filesetentry_t *fs_leafdirrotor; /* Ptr to next leaf */
+ /* directory to select */
} fileset_t;
int fileset_createset(fileset_t *);
diff --git a/usr/src/cmd/filebench/common/flowop_library.c b/usr/src/cmd/filebench/common/flowop_library.c
index 9299ca0a6b..7727c169a8 100644
--- a/usr/src/cmd/filebench/common/flowop_library.c
+++ b/usr/src/cmd/filebench/common/flowop_library.c
@@ -38,6 +38,7 @@
#include <inttypes.h>
#include <fcntl.h>
#include <math.h>
+#include <dirent.h>
#ifdef HAVE_UTILITY_H
#include <utility.h>
@@ -75,7 +76,7 @@
#include "flowop.h"
#include "fileset.h"
#include "fb_random.h"
-
+#include "utils.h"
/*
* These routines implement the flowops from the f language. Each
* flowop has has a name such as "read", and a set of function pointers
@@ -128,6 +129,9 @@ static int flowoplib_openfile(threadflow_t *, flowop_t *flowop);
static int flowoplib_openfile_common(threadflow_t *, flowop_t *flowop, int fd);
static int flowoplib_createfile(threadflow_t *, flowop_t *flowop);
static int flowoplib_closefile(threadflow_t *, flowop_t *flowop);
+static int flowoplib_makedir(threadflow_t *, flowop_t *flowop);
+static int flowoplib_removedir(threadflow_t *, flowop_t *flowop);
+static int flowoplib_listdir(threadflow_t *, flowop_t *flowop);
static int flowoplib_fsync(threadflow_t *, flowop_t *flowop);
static int flowoplib_readwholefile(threadflow_t *, flowop_t *flowop);
static int flowoplib_writewholefile(threadflow_t *, flowop_t *flowop);
@@ -192,6 +196,12 @@ static flowoplib_t flowoplib_funcs[] = {
flowoplib_createfile, flowoplib_destruct_generic,
FLOW_TYPE_IO, 0, "closefile", flowoplib_init_generic,
flowoplib_closefile, flowoplib_destruct_generic,
+ FLOW_TYPE_IO, 0, "makedir", flowoplib_init_generic,
+ flowoplib_makedir, flowoplib_destruct_generic,
+ FLOW_TYPE_IO, 0, "removedir", flowoplib_init_generic,
+ flowoplib_removedir, flowoplib_destruct_generic,
+ FLOW_TYPE_IO, 0, "listdir", flowoplib_init_generic,
+ flowoplib_listdir, flowoplib_destruct_generic,
FLOW_TYPE_IO, 0, "fsync", flowoplib_init_generic,
flowoplib_fsync, flowoplib_destruct_generic,
FLOW_TYPE_IO, 0, "fsyncset", flowoplib_init_generic,
@@ -996,7 +1006,7 @@ static int
flowoplib_eventlimit(threadflow_t *threadflow, flowop_t *flowop)
{
/* Immediately bail if not set/enabled */
- if (filebench_shm->shm_eventgen_hz == 0)
+ if (filebench_shm->shm_eventgen_hz == NULL)
return (FILEBENCH_OK);
if (flowop->fo_initted == 0) {
@@ -1006,7 +1016,7 @@ flowoplib_eventlimit(threadflow_t *threadflow, flowop_t *flowop)
}
flowop_beginop(threadflow, flowop);
- while (filebench_shm->shm_eventgen_hz) {
+ while (filebench_shm->shm_eventgen_hz != NULL) {
(void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
if (filebench_shm->shm_eventgen_q > 0) {
filebench_shm->shm_eventgen_q--;
@@ -1059,7 +1069,7 @@ flowoplib_iopslimit(threadflow_t *threadflow, flowop_t *flowop)
uint64_t events;
/* Immediately bail if not set/enabled */
- if (filebench_shm->shm_eventgen_hz == 0)
+ if (filebench_shm->shm_eventgen_hz == NULL)
return (FILEBENCH_OK);
if (flowop->fo_initted == 0) {
@@ -1114,7 +1124,7 @@ flowoplib_iopslimit(threadflow_t *threadflow, flowop_t *flowop)
events = iops;
flowop_beginop(threadflow, flowop);
- while (filebench_shm->shm_eventgen_hz) {
+ while (filebench_shm->shm_eventgen_hz != NULL) {
(void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
if (filebench_shm->shm_eventgen_q >= events) {
@@ -1147,7 +1157,7 @@ flowoplib_opslimit(threadflow_t *threadflow, flowop_t *flowop)
uint64_t events;
/* Immediately bail if not set/enabled */
- if (filebench_shm->shm_eventgen_hz == 0)
+ if (filebench_shm->shm_eventgen_hz == NULL)
return (FILEBENCH_OK);
if (flowop->fo_initted == 0) {
@@ -1188,7 +1198,7 @@ flowoplib_opslimit(threadflow_t *threadflow, flowop_t *flowop)
events = ops;
flowop_beginop(threadflow, flowop);
- while (filebench_shm->shm_eventgen_hz) {
+ while (filebench_shm->shm_eventgen_hz != NULL) {
(void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
if (filebench_shm->shm_eventgen_q >= events) {
filebench_shm->shm_eventgen_q -= events;
@@ -1222,7 +1232,7 @@ flowoplib_bwlimit(threadflow_t *threadflow, flowop_t *flowop)
uint64_t events;
/* Immediately bail if not set/enabled */
- if (filebench_shm->shm_eventgen_hz == 0)
+ if (filebench_shm->shm_eventgen_hz == NULL)
return (FILEBENCH_OK);
if (flowop->fo_initted == 0) {
@@ -1281,7 +1291,7 @@ flowoplib_bwlimit(threadflow_t *threadflow, flowop_t *flowop)
(u_longlong_t)bytes, (u_longlong_t)events);
flowop_beginop(threadflow, flowop);
- while (filebench_shm->shm_eventgen_hz) {
+ while (filebench_shm->shm_eventgen_hz != NULL) {
(void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
if (filebench_shm->shm_eventgen_q >= events) {
filebench_shm->shm_eventgen_q -= events;
@@ -1775,10 +1785,10 @@ flowoplib_openfile_common(threadflow_t *threadflow, flowop_t *flowop, int fd)
int open_attrs = 0;
char name[MAXPATHLEN];
- (void) strcpy(name,
- avd_get_str(flowop->fo_fileset->fs_path));
- (void) strcat(name, "/");
- (void) strcat(name, fileset_name);
+ (void) fb_strlcpy(name,
+ avd_get_str(flowop->fo_fileset->fs_path), MAXPATHLEN);
+ (void) fb_strlcat(name, "/", MAXPATHLEN);
+ (void) fb_strlcat(name, fileset_name, MAXPATHLEN);
if (avd_get_bool(flowop->fo_dsync)) {
#ifdef sun
@@ -1987,12 +1997,11 @@ flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop)
(void) ipc_mutex_unlock(&fileset->fs_pick_lock);
}
- *path = 0;
- (void) strcpy(path, avd_get_str(fileset->fs_path));
- (void) strcat(path, "/");
- (void) strcat(path, avd_get_str(fileset->fs_name));
+ (void) fb_strlcpy(path, avd_get_str(fileset->fs_path), MAXPATHLEN);
+ (void) fb_strlcat(path, "/", MAXPATHLEN);
+ (void) fb_strlcat(path, avd_get_str(fileset->fs_name), MAXPATHLEN);
pathtmp = fileset_resolvepath(file);
- (void) strcat(path, pathtmp);
+ (void) fb_strlcat(path, pathtmp, MAXPATHLEN);
free(pathtmp);
/* delete the selected file */
@@ -2118,6 +2127,200 @@ flowoplib_closefile(threadflow_t *threadflow, flowop_t *flowop)
}
/*
+ * Obtain a filesetentry for a leaf directory. Result placed where dirp
+ * points. Supply with flowop and a flag to indicate whether an existent
+ * or non-existent leaf directory is required. Returns FILEBENCH_NORSC
+ * if all out of the appropriate type of directories, FILEBENCH_ERROR
+ * if the flowop does not point to a fileset, and FILEBENCH_OK otherwise.
+ */
+static int
+flowoplib_pickleafdir(filesetentry_t **dirp, flowop_t *flowop, int flags)
+{
+ fileset_t *fileset;
+
+ if ((fileset = flowop->fo_fileset) == NULL) {
+ filebench_log(LOG_ERROR, "flowop NO fileset");
+ return (FILEBENCH_ERROR);
+ }
+
+ if ((*dirp = fileset_pick(fileset,
+ FILESET_PICKLEAFDIR | flags, 0)) == NULL) {
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "flowop %s failed to pick directory from fileset %s",
+ flowop->fo_name,
+ avd_get_str(fileset->fs_name));
+ return (FILEBENCH_NORSC);
+ }
+
+ return (FILEBENCH_OK);
+}
+
+/*
+ * Obtain the full pathname of the directory described by the filesetentry
+ * indicated by "dir", and copy it into the character array pointed to by
+ * path. Returns FILEBENCH_ERROR on errors, FILEBENCH_OK otherwise.
+ */
+static int
+flowoplib_getdirpath(filesetentry_t *dir, char *path)
+{
+ char *fileset_path;
+ char *fileset_name;
+ char *part_path;
+
+ if ((fileset_path = avd_get_str(dir->fse_fileset->fs_path)) == NULL) {
+ filebench_log(LOG_ERROR, "Fileset path not set");
+ return (FILEBENCH_ERROR);
+ }
+
+ if ((fileset_name = avd_get_str(dir->fse_fileset->fs_name)) == NULL) {
+ filebench_log(LOG_ERROR, "Fileset name not set");
+ return (FILEBENCH_ERROR);
+ }
+
+ (void) fb_strlcpy(path, fileset_path, MAXPATHLEN);
+ (void) fb_strlcat(path, "/", MAXPATHLEN);
+ (void) fb_strlcat(path, fileset_name, MAXPATHLEN);
+
+ if ((part_path = fileset_resolvepath(dir)) == NULL)
+ return (FILEBENCH_ERROR);
+
+ (void) fb_strlcat(path, part_path, MAXPATHLEN);
+ free(part_path);
+
+ return (FILEBENCH_OK);
+}
+
+/*
+ * Use mkdir to create a directory. Obtains the fileset name from the
+ * flowop, selects a non-existent leaf directory and obtains its full
+ * path, then uses mkdir to create it on the storage subsystem (make it
+ * existent). Returns FILEBENCH_NORSC is there are no more non-existent
+ * directories in the fileset, FILEBENCH_ERROR on other errors, and
+ * FILEBENCH_OK on success.
+ */
+static int
+flowoplib_makedir(threadflow_t *threadflow, flowop_t *flowop)
+{
+ filesetentry_t *dir;
+ int ret;
+ char full_path[MAXPATHLEN];
+
+ if ((ret = flowoplib_pickleafdir(&dir, flowop,
+ FILESET_PICKNOEXIST)) != FILEBENCH_OK)
+ return (ret);
+
+ if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK)
+ return (ret);
+
+ flowop_beginop(threadflow, flowop);
+ (void) mkdir(full_path, 0755);
+ flowop_endop(threadflow, flowop, 0);
+
+ /* indicate that it is no longer busy and now exists */
+ fileset_unbusy(dir, TRUE, TRUE);
+
+ return (FILEBENCH_OK);
+}
+
+/*
+ * Use rmdir to delete a directory. Obtains the fileset name from the
+ * flowop, selects an existent leaf directory and obtains its full path,
+ * then uses rmdir to remove it from the storage subsystem (make it
+ * non-existent). Returns FILEBENCH_NORSC is there are no more existent
+ * directories in the fileset, FILEBENCH_ERROR on other errors, and
+ * FILEBENCH_OK on success.
+ */
+static int
+flowoplib_removedir(threadflow_t *threadflow, flowop_t *flowop)
+{
+ filesetentry_t *dir;
+ int ret;
+ char full_path[MAXPATHLEN];
+
+ if ((ret = flowoplib_pickleafdir(&dir, flowop,
+ FILESET_PICKEXISTS)) != FILEBENCH_OK)
+ return (ret);
+
+ if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK)
+ return (ret);
+
+ flowop_beginop(threadflow, flowop);
+ (void) rmdir(full_path);
+ flowop_endop(threadflow, flowop, 0);
+
+ /* indicate that it is no longer busy and no longer exists */
+ fileset_unbusy(dir, TRUE, FALSE);
+
+ return (FILEBENCH_OK);
+}
+
+/*
+ * Use opendir(), multiple readdir() calls, and closedir() to list the
+ * contents of a directory. Obtains the fileset name from the
+ * flowop, selects a normal subdirectory (which always exist) and obtains
+ * its full path, then uses opendir() to get a DIR handle to it from the
+ * file system, a readdir() loop to access each directory entry, and
+ * finally cleans up with a closedir(). The latency reported is the total
+ * for all this activity, and it also reports the total number of bytes
+ * in the entries as the amount "read". Returns FILEBENCH_ERROR on errors,
+ * and FILEBENCH_OK on success.
+ */
+static int
+flowoplib_listdir(threadflow_t *threadflow, flowop_t *flowop)
+{
+ fileset_t *fileset;
+ filesetentry_t *dir;
+ DIR *dir_handlep;
+ struct dirent *direntp;
+ int dir_bytes = 0;
+ int ret;
+ char full_path[MAXPATHLEN];
+
+ if ((fileset = flowop->fo_fileset) == NULL) {
+ filebench_log(LOG_ERROR, "flowop NO fileset");
+ return (FILEBENCH_ERROR);
+ }
+
+ if ((dir = fileset_pick(fileset,
+ FILESET_PICKDIR, 0)) == NULL) {
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "flowop %s failed to pick directory from fileset %s",
+ flowop->fo_name,
+ avd_get_str(fileset->fs_name));
+ return (FILEBENCH_NORSC);
+ }
+
+ if ((ret = flowoplib_getdirpath(dir, full_path)) != FILEBENCH_OK)
+ return (ret);
+
+ flowop_beginop(threadflow, flowop);
+
+ /* open the directory */
+ if ((dir_handlep = opendir(full_path)) == NULL) {
+ filebench_log(LOG_ERROR,
+ "flowop %s failed to open directory in fileset %s\n",
+ flowop->fo_name, avd_get_str(fileset->fs_name));
+ return (FILEBENCH_ERROR);
+ }
+
+ /* read through the directory entries */
+ while ((direntp = readdir(dir_handlep)) != NULL) {
+ dir_bytes += (strlen(direntp->d_name) +
+ sizeof (struct dirent) - 1);
+ }
+
+ /* close the directory */
+ (void) closedir(dir_handlep);
+
+ flowop_endop(threadflow, flowop, dir_bytes);
+
+ /* indicate that it is no longer busy */
+ fileset_unbusy(dir, FALSE, FALSE);
+
+ return (FILEBENCH_OK);
+}
+
+/*
* Emulate stat of a file. Picks an arbitrary filesetentry with
* an existing file from the flowop's fileset, then performs a
* stat() operation on it. Returns FILEBENCH_ERROR if the flowop has no
@@ -2151,7 +2354,6 @@ flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop)
fileset = flowop->fo_fileset;
}
-
if (fileset == NULL) {
filebench_log(LOG_ERROR,
"statfile with no fileset specified");
@@ -2182,12 +2384,13 @@ flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop)
}
/* 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));
+ (void) fb_strlcpy(path, avd_get_str(fileset->fs_path),
+ MAXPATHLEN);
+ (void) fb_strlcat(path, "/", MAXPATHLEN);
+ (void) fb_strlcat(path, avd_get_str(fileset->fs_name),
+ MAXPATHLEN);
pathtmp = fileset_resolvepath(file);
- (void) strcat(path, pathtmp);
+ (void) fb_strlcat(path, pathtmp, MAXPATHLEN);
free(pathtmp);
/* stat the file */
diff --git a/usr/src/cmd/filebench/common/ipc.h b/usr/src/cmd/filebench/common/ipc.h
index 937171ca10..8416a32ca7 100644
--- a/usr/src/cmd/filebench/common/ipc.h
+++ b/usr/src/cmd/filebench/common/ipc.h
@@ -146,7 +146,7 @@ typedef struct filebench_shm {
/*
* Event generator state
*/
- int shm_eventgen_hz; /* number of events per sec. */
+ avd_t 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 */
diff --git a/usr/src/cmd/filebench/common/parser_gram.y b/usr/src/cmd/filebench/common/parser_gram.y
index 7e4510cf9d..d6424d30ff 100644
--- a/usr/src/cmd/filebench/common/parser_gram.y
+++ b/usr/src/cmd/filebench/common/parser_gram.y
@@ -185,6 +185,7 @@ static void parser_version(cmd_t *cmd);
%token FSA_HIGHWATER FSA_DIRECTIO FSA_DIRWIDTH FSA_FD FSA_SRCFD FSA_ROTATEFD
%token FSA_NAMELENGTH FSA_FILESIZE FSA_ENTRIES FSA_FILESIZEGAMMA FSA_DIRDEPTHRV
%token FSA_DIRGAMMA FSA_USEISM FSA_TYPE FSA_RANDTABLE FSA_RANDSRC FSA_RANDROUND
+%token FSA_LEAFDIRS
%token FSA_RANDSEED FSA_RANDGAMMA FSA_RANDMEAN FSA_RANDMIN FSA_MASTER
%token FSA_CLIENT
%token FSS_TYPE FSS_SEED FSS_GAMMA FSS_MEAN FSS_MIN FSS_SRC FSS_ROUND
@@ -1441,6 +1442,7 @@ attrs_define_fileset:
| FSA_DIRGAMMA { $$ = FSA_DIRGAMMA;}
| FSA_CACHED { $$ = FSA_CACHED;}
| FSA_ENTRIES { $$ = FSA_ENTRIES;};
+| FSA_LEAFDIRS { $$ = FSA_LEAFDIRS;};
randvar_attr_name:
FSA_NAME { $$ = FSA_NAME;}
@@ -2009,16 +2011,11 @@ static void
parser_eventgen(cmd_t *cmd)
{
attr_t *attr;
- fbint_t rate;
/* Get the rate from attribute */
if (attr = get_attr_integer(cmd, FSA_RATE)) {
if (attr->attr_avd) {
- rate = avd_get_int(attr->attr_avd);
- filebench_log(LOG_VERBOSE,
- "Eventgen: %llu per second",
- (u_longlong_t)rate);
- eventgen_setrate(rate);
+ eventgen_setrate(attr->attr_avd);
}
}
}
@@ -2727,10 +2724,21 @@ parser_fileset_define(cmd_t *cmd)
if (attr = get_attr_integer(cmd, FSA_ENTRIES)) {
fileset->fs_entries = attr->attr_avd;
} else {
- filebench_log(LOG_ERROR, "Fileset has zero entries");
fileset->fs_entries = avd_int_alloc(0);
}
+ /* Get the number of leafdirs in the fileset */
+ if (attr = get_attr_integer(cmd, FSA_LEAFDIRS)) {
+ fileset->fs_leafdirs = attr->attr_avd;
+ } else {
+ fileset->fs_leafdirs = avd_int_alloc(0);
+ }
+
+ if ((avd_get_int(fileset->fs_entries) == 0) &&
+ (avd_get_int(fileset->fs_leafdirs) == 0)) {
+ filebench_log(LOG_ERROR, "Fileset has no files or leafdirs");
+ }
+
/* Get the mean dir width of the fileset */
if (attr = get_attr_integer(cmd, FSA_DIRWIDTH)) {
fileset->fs_dirwidth = attr->attr_avd;
diff --git a/usr/src/cmd/filebench/common/parser_lex.l b/usr/src/cmd/filebench/common/parser_lex.l
index 5485899877..6ac2645e86 100644
--- a/usr/src/cmd/filebench/common/parser_lex.l
+++ b/usr/src/cmd/filebench/common/parser_lex.l
@@ -126,6 +126,7 @@ name { return FSA_NAME;}
namelength { return FSA_NAMELENGTH; }
nice { return FSA_NICE;}
entries { return FSA_ENTRIES;}
+leafdirs { return FSA_LEAFDIRS;}
prealloc { return FSA_PREALLOC; }
paralloc { return FSA_PARALLOC; }
reuse { return FSA_REUSE; }
diff --git a/usr/src/cmd/filebench/common/utils.c b/usr/src/cmd/filebench/common/utils.c
index 68dc415a2f..a68f72446d 100644
--- a/usr/src/cmd/filebench/common/utils.c
+++ b/usr/src/cmd/filebench/common/utils.c
@@ -25,8 +25,6 @@
* Portions Copyright 2008 Denis Cheng
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <limits.h>
#include <string.h>
#include <stdlib.h>
@@ -42,9 +40,10 @@
#include "parsertypes.h"
/*
- * For now, just two routines: one to allocate a string in shared
- * memory, and one to get the final file or directory name from a
- * supplied pathname.
+ * For now, just three routines: one to allocate a string in shared
+ * memory, one to emulate a strlcpy() function and one to emulate a
+ * strlcat() function, both the second and third only used in non
+ * Solaris environments,
*
*/
@@ -65,3 +64,65 @@ fb_stralloc(char *str)
(void) strcpy(newstr, str);
return (newstr);
}
+
+#ifndef sun
+
+/*
+ * Implements the strlcpy function when compilied for non Solaris
+ * operating systems. On solaris the strlcpy() function is used
+ * directly.
+ */
+size_t
+fb_strlcpy(char *dst, const char *src, size_t dstsize)
+{
+ uint_t i;
+
+ for (i = 0; i < (dstsize - 1); i++) {
+
+ /* quit if at end of source string */
+ if (src[i] == '\0')
+ break;
+
+ dst[i] = src[i];
+ }
+
+ /* set end of dst string to \0 */
+ dst[i] = '\0';
+ i++;
+
+ return (i);
+}
+
+/*
+ * Implements the strlcat function when compilied for non Solaris
+ * operating systems. On solaris the strlcat() function is used
+ * directly.
+ */
+size_t
+fb_strlcat(char *dst, const char *src, size_t dstsize)
+{
+ uint_t i, j;
+
+ /* find the end of the current destination string */
+ for (i = 0; i < (dstsize - 1); i++) {
+ if (dst[i] == '\0')
+ break;
+ }
+
+ /* append the source string to the destination string */
+ for (j = 0; i < (dstsize - 1); i++) {
+ if (src[j] == '\0')
+ break;
+
+ dst[i] = src[j];
+ j++;
+ }
+
+ /* set end of dst string to \0 */
+ dst[i] = '\0';
+ i++;
+
+ return (i);
+}
+
+#endif /* !sun */
diff --git a/usr/src/cmd/filebench/common/utils.h b/usr/src/cmd/filebench/common/utils.h
index d2a8b655a3..cb9e39a9fc 100644
--- a/usr/src/cmd/filebench/common/utils.h
+++ b/usr/src/cmd/filebench/common/utils.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _FB_UTILS_H
#define _FB_UTILS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "config.h"
#include <sys/types.h>
@@ -41,6 +39,14 @@ extern "C" {
extern char *fb_stralloc(char *str);
+#ifdef sun
+#define fb_strlcat strlcat
+#define fb_strlcpy strlcpy
+#else
+extern size_t fb_strlcat(char *dst, const char *src, size_t dstsize);
+extern size_t fb_strlcpy(char *dst, const char *src, size_t dstsize);
+#endif /* sun */
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/cmd/filebench/common/vars.h b/usr/src/cmd/filebench/common/vars.h
index d3f8185c97..9225d22b9b 100644
--- a/usr/src/cmd/filebench/common/vars.h
+++ b/usr/src/cmd/filebench/common/vars.h
@@ -76,6 +76,9 @@ typedef struct avd {
#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)))
+#define AVD_IS_VAR(vp) ((vp) && (((vp)->avd_type == AVD_IND_VAR) || \
+ ((vp)->avd_type == AVD_VARVAL_INT) || \
+ ((vp)->avd_type == AVD_VARVAL_DBL)))
typedef struct var {
char *var_name;
diff --git a/usr/src/cmd/filebench/config/Makefile b/usr/src/cmd/filebench/config/Makefile
index 5697c531bf..ef6541041e 100644
--- a/usr/src/cmd/filebench/config/Makefile
+++ b/usr/src/cmd/filebench/config/Makefile
@@ -28,7 +28,7 @@
include ../../Makefile.cmd
CONFIGS = fileio.prof filemacro.prof filemicro.prof generic.func \
-seqread.prof randomread.prof multi_fileserver.prof
+seqread.prof randomread.prof multi_fileserver.prof videoserver.prof
ROOTUSRBENCHDIR = $(ROOT)/usr/benchmarks
ROOTUSRBENCHFBCONFIGDIR = $(ROOTUSRBENCHDIR)/filebench/config
FBCONFIGS = $(CONFIGS:%=$(ROOTUSRBENCHFBCONFIGDIR)/%)
diff --git a/usr/src/cmd/filebench/config/videoserver.prof b/usr/src/cmd/filebench/config/videoserver.prof
new file mode 100644
index 0000000000..c749c992ae
--- /dev/null
+++ b/usr/src/cmd/filebench/config/videoserver.prof
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+DEFAULTS {
+ runtime = 120;
+ dir = /export/home/tmp;
+ stats = /tmp;
+ filesystem = zfs;
+ description = "fileserver zfs";
+}
+
+CONFIG video_server {
+ function = generic;
+ personality = videoserver;
+ filesize = 2g;
+ numactivevids = 8;
+ numpassivevids = 40;
+ nthreads = 16;
+ srvbwrate = 32;
+ repintval = 60;
+}
diff --git a/usr/src/cmd/filebench/workloads/Makefile b/usr/src/cmd/filebench/workloads/Makefile
index f7025f58e1..f5dca4ac11 100644
--- a/usr/src/cmd/filebench/workloads/Makefile
+++ b/usr/src/cmd/filebench/workloads/Makefile
@@ -49,22 +49,27 @@ WORKLOADS = \
filemicro_statfile.f \
filemicro_writefsync.f \
fileserver.f \
+ listdirs.f \
+ makedirs.f \
mongo.f \
multistreamread.f \
multistreamreaddirect.f \
multistreamwrite.f \
multistreamwritedirect.f \
oltp.f \
+ openfiles.f \
randomread.f \
randomrw.f \
randomwrite.f \
ratelimcopyfiles.f \
+ removedirs.f \
singlestreamread.f \
singlestreamreaddirect.f \
singlestreamwrite.f \
singlestreamwritedirect.f \
tpcso.f \
varmail.f \
+ videoserver.f \
webproxy.f \
webserver.f
diff --git a/usr/src/cmd/filebench/workloads/listdirs.f b/usr/src/cmd/filebench/workloads/listdirs.f
new file mode 100644
index 0000000000..e3fadc66c3
--- /dev/null
+++ b/usr/src/cmd/filebench/workloads/listdirs.f
@@ -0,0 +1,50 @@
+#
+# 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 with a fairly deep directory tree, then does readdir
+# operations on them for a specified amount of time
+#
+set $dir=/tmp
+set $nfiles=50000
+set $meandirwidth=5
+set $nthreads=16
+
+define fileset name=bigfileset,path=$dir,size=0,entries=$nfiles,dirwidth=$meandirwidth,prealloc
+
+define process name=lsdir,instances=1
+{
+ thread name=dirlister,memsize=1m,instances=$nthreads
+ {
+ flowop listdir name=open1,filesetname=bigfileset
+ }
+}
+
+echo "ListDirs Version 1.0 personality successfully loaded"
+usage "Usage: set \$dir=<dir> defaults to $dir"
+usage " set \$meandirwidth=<size> defaults to $meandirwidth"
+usage " set \$nfiles=<value> defaults to $nfiles"
+usage " set \$nthreads=<value> defaults to $nthreads"
+usage "(sets mean dir width and dir depth is calculated as log (width, nfiles)"
+usage " "
+usage " run 60"
diff --git a/usr/src/cmd/filebench/workloads/makedirs.f b/usr/src/cmd/filebench/workloads/makedirs.f
new file mode 100644
index 0000000000..34f2991468
--- /dev/null
+++ b/usr/src/cmd/filebench/workloads/makedirs.f
@@ -0,0 +1,51 @@
+#
+# 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 directory with $ndirs potential leaf directories, than mkdir's them
+#
+set $dir=/tmp
+set $ndirs=10000
+set $meandirwidth=100
+set $nthreads=16
+
+set mode quit firstdone
+
+define fileset name=bigfileset,path=$dir,size=0,leafdirs=$ndirs,dirwidth=$meandirwidth
+
+define process name=dirmake,instances=1
+{
+ thread name=dirmaker,memsize=1m,instances=$nthreads
+ {
+ flowop makedir name=mkdir1,filesetname=bigfileset
+ }
+}
+
+echo "MakeDirs Version 1.0 personality successfully loaded"
+usage "Usage: set \$dir=<dir> defaults to $dir"
+usage " set \$meandirwidth=<size> defaults to $meandirwidth"
+usage " set \$ndirs=<value> defaults to $ndirs"
+usage " set \$nthreads=<value> defaults to $nthreads"
+usage "(sets mean dir width and dir depth is calculated as log (width, ndirs)"
+usage " "
+usage " run"
diff --git a/usr/src/cmd/filebench/workloads/openfiles.f b/usr/src/cmd/filebench/workloads/openfiles.f
new file mode 100644
index 0000000000..b6eb1be835
--- /dev/null
+++ b/usr/src/cmd/filebench/workloads/openfiles.f
@@ -0,0 +1,51 @@
+#
+# 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 with $nfiles empty files, then proceeds to open each one
+# and then close it.
+#
+set $dir=/tmp
+set $nfiles=50000
+set $meandirwidth=100
+set $nthreads=16
+
+define fileset name=bigfileset,path=$dir,size=0,entries=$nfiles,dirwidth=$meandirwidth,prealloc
+
+define process name=fileopen,instances=1
+{
+ thread name=fileopener,memsize=1m,instances=$nthreads
+ {
+ flowop openfile name=open1,filesetname=bigfileset,fd=1
+ flowop closefile name=close1,fd=1
+ }
+}
+
+echo "Openfiles Version 1.0 personality successfully loaded"
+usage "Usage: set \$dir=<dir> defaults to $dir"
+usage " set \$meandirwidth=<size> defaults to $meandirwidth"
+usage " set \$nfiles=<value> defaults to $nfiles"
+usage " set \$nthreads=<value> defaults to $nthreads"
+usage "(sets mean dir width and dir depth is calculated as log (width, nfiles)"
+usage " "
+usage " run 60"
diff --git a/usr/src/cmd/filebench/workloads/removedirs.f b/usr/src/cmd/filebench/workloads/removedirs.f
new file mode 100644
index 0000000000..f64255bc8c
--- /dev/null
+++ b/usr/src/cmd/filebench/workloads/removedirs.f
@@ -0,0 +1,51 @@
+#
+# 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 with $ndirs empty leaf directories then rmdir's all of them
+#
+set $dir=/tmp
+set $ndirs=10000
+set $meandirwidth=100
+set $nthreads=16
+
+set mode quit firstdone
+
+define fileset name=bigfileset,path=$dir,size=0,leafdirs=$ndirs,dirwidth=$meandirwidth,prealloc
+
+define process name=remdir,instances=1
+{
+ thread name=fileopener,memsize=1m,instances=$nthreads
+ {
+ flowop removedir name=dirremover,filesetname=bigfileset
+ }
+}
+
+echo "RemoveDir Version 1.0 personality successfully loaded"
+usage "Usage: set \$dir=<dir> defaults to $dir"
+usage " set \$meandirwidth=<size> defaults to $meandirwidth"
+usage " set \$ndirs=<value> defaults to $ndirs"
+usage " set \$nthreads=<value> defaults to $nthreads"
+usage "(sets mean dir width and dir depth is calculated as log (width, ndirs)"
+usage " "
+usage " run"
diff --git a/usr/src/cmd/filebench/workloads/videoserver.f b/usr/src/cmd/filebench/workloads/videoserver.f
new file mode 100644
index 0000000000..668fd0e81c
--- /dev/null
+++ b/usr/src/cmd/filebench/workloads/videoserver.f
@@ -0,0 +1,82 @@
+#
+# 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.
+#
+# This workloads emulates a video server. It has two filesets, one of videos
+# being actively served, and one of videos availabe but currently inactive
+# (passive). However, one thread, vidwriter, is writing new videos to replace
+# no longer viewed videos in the passive set. Meanwhile $nthreads threads are
+# serving up videos from the activevids fileset. If the desired rate is R mb/s,
+# and $nthreads is set to T, then set the $srvbwrate to R * T to get the
+# desired rate per video stream. The video replacement rate of one video
+# file per replacement interval, is set by $repintval which defaults to
+# 10 seconds. Thus the write bandwidth will be set as $filesize/$repintval.
+
+set $dir=/tmp
+set $filesize=10g
+set $nthreads=48
+set $writeiosize=1m
+set $readiosize=256k
+set $numactivevids=32
+set $numpassivevids=194
+set $srvbwrate=96
+set $repintval=10
+
+eventgen rate=$srvbwrate
+
+define fileset name=activevids,path=$dir,size=$filesize,entries=$numactivevids,dirwidth=4,prealloc,paralloc,reuse
+define fileset name=passivevids,path=$dir,size=$filesize,entries=$numpassivevids,dirwidth=20,prealloc,paralloc,reuse,prealloc=50
+
+define process name=vidwriter,instances=1
+{
+ thread name=vidwriter,memsize=10m,instances=1
+ {
+ flowop deletefile name=vidremover,filesetname=passivevids
+ flowop createfile name=wrtopen,filesetname=passivevids,fd=1
+ flowop writewholefile name=newvid,iosize=$writeiosize,fd=1,srcfd=1
+ flowop closefile name=wrtclose, fd=1
+ flowop delay name=replaceinterval, value=$repintval
+ }
+}
+
+define process name=vidreaders,instances=1
+{
+ thread name=vidreaders,memsize=10m,instances=$nthreads
+ {
+ flowop read name=vidreader,filesetname=activevids,iosize=$readiosize
+ flowop bwlimit name=serverlimit, target=vidreader
+ }
+}
+
+echo "Video Server Version 1.0 personality successfully loaded"
+usage "Usage: set \$dir=<dir> defaults to $dir"
+usage " set \$filesize=<size> defaults to $filesize"
+usage " set \$nthreads=<value> defaults to $nthreads"
+usage " set \$writeiosize=<value> defaults to $writeiosize"
+usage " set \$readiosize=<value> defaults to $readiosize"
+usage " set \$numactivevids=<value> defaults to $numactivevids"
+usage " set \$numpassivevids=<value> defaults to $numpassivevids"
+usage " set \$srvbwrate=<value> defaults to $srvbwrate"
+usage " "
+usage " run runtime (e.g. run 60)"
+
diff --git a/usr/src/pkgdefs/SUNWfilebench/depend b/usr/src/pkgdefs/SUNWfilebench/depend
index 759ad37f76..a67e617920 100644
--- a/usr/src/pkgdefs/SUNWfilebench/depend
+++ b/usr/src/pkgdefs/SUNWfilebench/depend
@@ -20,11 +20,9 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
# This package information file defines software dependencies associated
# with the pkg. You can define three types of pkg dependencies with this file:
# P indicates a prerequisite for installation
@@ -49,3 +47,5 @@ P SUNWcsr Core Solaris, (Root)
P SUNWcsu Core Solaris, (Usr)
P SUNWcsl Core Solaris Libraries
P SUNWperl584core Perl 5.8.4 (core)
+P SUNWlibmsr
+P SUNWtecla Tecla command-line editing library
diff --git a/usr/src/pkgdefs/SUNWfilebench/prototype_com b/usr/src/pkgdefs/SUNWfilebench/prototype_com
index 5efa232bce..9e421e095e 100644
--- a/usr/src/pkgdefs/SUNWfilebench/prototype_com
+++ b/usr/src/pkgdefs/SUNWfilebench/prototype_com
@@ -46,6 +46,7 @@ f none usr/benchmarks/filebench/config/generic.func 444 root bin
f none usr/benchmarks/filebench/config/multi_fileserver.prof 444 root bin
f none usr/benchmarks/filebench/config/seqread.prof 444 root bin
f none usr/benchmarks/filebench/config/randomread.prof 444 root bin
+f none usr/benchmarks/filebench/config/videoserver.prof 444 root bin
d none usr/benchmarks/filebench/scripts 755 root bin
f none usr/benchmarks/filebench/scripts/filebench_compare 555 root bin
f none usr/benchmarks/filebench/scripts/fs_flush 555 root bin
@@ -71,21 +72,26 @@ f none usr/benchmarks/filebench/workloads/filemicro_seqwriterandvartab.f 444 roo
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/listdirs.f 444 root bin
+f none usr/benchmarks/filebench/workloads/makedirs.f 444 root bin
f none usr/benchmarks/filebench/workloads/mongo.f 444 root bin
f none usr/benchmarks/filebench/workloads/multistreamread.f 444 root bin
f none usr/benchmarks/filebench/workloads/multistreamreaddirect.f 444 root bin
f none usr/benchmarks/filebench/workloads/multistreamwrite.f 444 root bin
f none usr/benchmarks/filebench/workloads/multistreamwritedirect.f 444 root bin
f none usr/benchmarks/filebench/workloads/oltp.f 444 root bin
+f none usr/benchmarks/filebench/workloads/openfiles.f 444 root bin
f none usr/benchmarks/filebench/workloads/randomread.f 444 root bin
f none usr/benchmarks/filebench/workloads/randomrw.f 444 root bin
f none usr/benchmarks/filebench/workloads/randomwrite.f 444 root bin
f none usr/benchmarks/filebench/workloads/ratelimcopyfiles.f 444 root bin
+f none usr/benchmarks/filebench/workloads/removedirs.f 444 root bin
f none usr/benchmarks/filebench/workloads/singlestreamread.f 444 root bin
f none usr/benchmarks/filebench/workloads/singlestreamreaddirect.f 444 root bin
f none usr/benchmarks/filebench/workloads/singlestreamwrite.f 444 root bin
f none usr/benchmarks/filebench/workloads/singlestreamwritedirect.f 444 root bin
f none usr/benchmarks/filebench/workloads/tpcso.f 444 root bin
f none usr/benchmarks/filebench/workloads/varmail.f 444 root bin
+f none usr/benchmarks/filebench/workloads/videoserver.f 444 root bin
f none usr/benchmarks/filebench/workloads/webproxy.f 444 root bin
f none usr/benchmarks/filebench/workloads/webserver.f 444 root bin