diff options
author | aw148015 <none@none> | 2008-03-18 13:52:42 -0700 |
---|---|---|
committer | aw148015 <none@none> | 2008-03-18 13:52:42 -0700 |
commit | 1b24378ce424258d555f0363de97728c68c862ce (patch) | |
tree | bbe79ddba7d5a5756ae39cbb3069307df2fa962e /usr/src | |
parent | 334edc4840d12dfd25a5559468cdd15a375cd111 (diff) | |
download | illumos-joyent-1b24378ce424258d555f0363de97728c68c862ce.tar.gz |
6627653 FileBench needs to support random variables
Diffstat (limited to 'usr/src')
30 files changed, 3551 insertions, 929 deletions
diff --git a/usr/src/cmd/filebench/Makefile.com b/usr/src/cmd/filebench/Makefile.com index 8902b2cd68..dbd3114a43 100644 --- a/usr/src/cmd/filebench/Makefile.com +++ b/usr/src/cmd/filebench/Makefile.com @@ -19,7 +19,7 @@ # 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. # #ident "%Z%%M% %I% %E% SMI" @@ -32,6 +32,7 @@ include ../../Makefile.targ SRCS = \ auto_comp.c \ eventgen.c \ + fb_random.c \ fileset.c \ flowop.c \ flowop_library.c \ diff --git a/usr/src/cmd/filebench/common/eventgen.c b/usr/src/cmd/filebench/common/eventgen.c index bff586e17d..a8ec68286b 100644 --- a/usr/src/cmd/filebench/common/eventgen.c +++ b/usr/src/cmd/filebench/common/eventgen.c @@ -19,7 +19,7 @@ * 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. */ @@ -149,18 +149,18 @@ eventgen_init(void) var_t * eventgen_ratevar(var_t *var) { - var->var_integer = filebench_shm->eventgen_hz; + VAR_SET_INT(var, filebench_shm->eventgen_hz); return (var); } /* * Sets the event generator rate to that supplied by - * vinteger_t rate. + * fbint_t rate. */ void -eventgen_setrate(vinteger_t rate) +eventgen_setrate(fbint_t rate) { - filebench_shm->eventgen_hz = rate; + filebench_shm->eventgen_hz = (int)rate; } /* diff --git a/usr/src/cmd/filebench/common/eventgen.h b/usr/src/cmd/filebench/common/eventgen.h index 21296614e6..51d80f9aed 100644 --- a/usr/src/cmd/filebench/common/eventgen.h +++ b/usr/src/cmd/filebench/common/eventgen.h @@ -19,7 +19,7 @@ * 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. */ @@ -36,7 +36,7 @@ extern "C" { #endif void eventgen_init(void); -void eventgen_setrate(vinteger_t rate); +void eventgen_setrate(fbint_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/fb_random.c b/usr/src/cmd/filebench/common/fb_random.c new file mode 100644 index 0000000000..a086185772 --- /dev/null +++ b/usr/src/cmd/filebench/common/fb_random.c @@ -0,0 +1,435 @@ +/* + * 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. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <fcntl.h> +#include <math.h> +#include "filebench.h" +#include "ipc.h" +#include "gamma_dist.h" + +static int urandomfd; + +/* + * Reads a 64 bit random number from the urandom "file". + * Shuts down the run if the read fails. Otherwise returns + * the random number after rounding it off by "round". + * Returns 0 on success, -1 on failure. + */ +int +filebench_randomno64(uint64_t *randp, uint64_t max, + uint64_t round, avd_t avd) +{ + uint64_t random; + + /* check for round value too large */ + if (max <= round) { + *randp = 0; + + /* if it just fits, its ok, otherwise error */ + if (max == round) + return (0); + else + return (-1); + } + + if (avd) { + + /* get it from the variable */ + random = avd_get_int(avd); + + } else { + + /* get it from urandom */ + if (read(urandomfd, &random, + sizeof (uint64_t)) != sizeof (uint64_t)) { + filebench_log(LOG_ERROR, + "read /dev/urandom failed: %s", strerror(errno)); + filebench_shutdown(1); + } + } + + /* clip with max and optionally round */ + max -= round; + random = random / (FILEBENCH_RANDMAX64 / max); + if (round) { + random = random / round; + random *= round; + } + if (random > max) + random = max; + + *randp = random; + return (0); +} + + +/* + * Reads a 32 bit random number from the urandom "file". + * Shuts down the run if the read fails. Otherwise returns + * the random number after rounding it off by "round". + * Returns 0 on success, -1 on failure. + */ +int +filebench_randomno32(uint32_t *randp, uint32_t max, + uint32_t round, avd_t avd) +{ + uint32_t random; + + /* check for round value too large */ + if (max <= round) { + *randp = 0; + + /* if it just fits, its ok, otherwise error */ + if (max == round) + return (0); + else + return (-1); + } + + if (avd) { + + /* get it from the variable */ + random = (uint32_t)avd_get_int(avd); + + } else { + + /* get it from urandom */ + if (read(urandomfd, &random, + sizeof (uint32_t)) != sizeof (uint32_t)) { + filebench_log(LOG_ERROR, + "read /dev/urandom failed: %s", strerror(errno)); + filebench_shutdown(1); + } + } + + /* clip with max and optionally round */ + max -= round; + random = random / (FILEBENCH_RANDMAX32 / max); + if (round) { + random = random / round; + random *= round; + } + if (random > max) + random = max; + + *randp = random; + return (0); +} + +/* + * fetch a source random number from the pseudo random number generator: + * erand48() + */ +static double +rand_src_rand48(unsigned short *xi) +{ + return (erand48(xi)); +} + +/* + * fetch a source random number from the hardware random number device: + * urandomfd. Convert it to a floating point probability. + */ +/* ARGSUSED */ +static double +rand_src_urandom(unsigned short *xi) +{ + fbint_t randnum; + + if (read(urandomfd, &randnum, + sizeof (fbint_t)) != sizeof (fbint_t)) { + filebench_log(LOG_ERROR, + "read /dev/urandom failed: %s", strerror(errno)); + filebench_shutdown(1); + return (0.0); + } + + /* convert to 0-1 probability */ + return ((double)randnum / (double)(FILEBENCH_RANDMAX64)); +} + +/* + * fetch a uniformly distributed random number from the supplied + * random object. + */ +static double +rand_uniform_get(randdist_t *rndp) +{ + double dprob, dmin, dres, dround; + + dmin = (double)rndp->rnd_vint_min; + dround = (double)rndp->rnd_vint_round; + + dprob = (*rndp->rnd_src)(rndp->rnd_xi); + + dres = (dprob * (2.0 * (rndp->rnd_dbl_mean - dmin))) + dmin; + + if (dround == 0.0) + return (dres); + else + return (round(dres / dround) * dround); +} + +/* + * fetch a gamma distributed random number from the supplied + * random object. + */ +static double +rand_gamma_get(randdist_t *rndp) +{ + double dmult, dres, dmin, dround; + + dmin = (double)rndp->rnd_vint_min; + dround = (double)rndp->rnd_vint_round; + + dmult = (rndp->rnd_dbl_mean - dmin) / rndp->rnd_dbl_gamma; + + dres = gamma_dist_knuth_src(rndp->rnd_dbl_gamma, + dmult, rndp->rnd_src, rndp->rnd_xi) + dmin; + + if (dround == 0.0) + return (dres); + else + return (round(dres / dround) * dround); +} + +/* + * fetch a table driven random number from the supplied + * random object. + */ +static double +rand_table_get(randdist_t *rndp) +{ + double dprob, dprcnt, dtabres, dsclres, dmin, dround; + int idx; + + dmin = (double)rndp->rnd_vint_min; + dround = (double)rndp->rnd_vint_round; + + dprob = (*rndp->rnd_src)(rndp->rnd_xi); + + dprcnt = (dprob * (double)(PF_TAB_SIZE)); + idx = (int)dprcnt; + + dtabres = (rndp->rnd_rft[idx].rf_base + + (rndp->rnd_rft[idx].rf_range * (dprcnt - (double)idx))); + + dsclres = (dtabres * (rndp->rnd_dbl_mean - dmin)) + dmin; + + if (dround == 0.0) + return (dsclres); + else + return (round(dsclres / dround) * dround); +} + +/* + * Set the random seed in the supplied random object. + */ +static void +rand_seed_set(randdist_t *rndp) +{ + union { + uint64_t ll; + uint16_t w[4]; + } temp1; + int idx; + + temp1.ll = (uint64_t)avd_get_int(rndp->rnd_seed); + + for (idx = 0; idx < 3; idx++) { + +#ifdef _BIG_ENDIAN + rndp->rnd_xi[idx] = temp1.w[3-idx]; +#else + rndp->rnd_xi[idx] = temp1.w[idx]; +#endif + } +} + +/* + * Define a random entity which will contain the parameters of a random + * distribution. + */ +randdist_t * +randdist_alloc(void) +{ + randdist_t *rndp; + + if ((rndp = (randdist_t *)ipc_malloc(FILEBENCH_RANDDIST)) == NULL) { + filebench_log(LOG_ERROR, "Out of memory for random dist"); + return (NULL); + } + + /* place on global list */ + rndp->rnd_next = filebench_shm->shm_rand_list; + filebench_shm->shm_rand_list = rndp; + + return (rndp); +} + +/* + * Initializes a random distribution entity, converting avd_t + * parameters to doubles, and converting the list of probability density + * function table entries, if supplied, into a probablilty function table + */ +static void +randdist_init_one(randdist_t *rndp) +{ + probtabent_t *rdte_hdp, *ptep; + double tablemean, tablemin; + int pteidx; + + /* convert parameters to doubles */ + rndp->rnd_dbl_mean = (double)avd_get_int(rndp->rnd_mean); + rndp->rnd_dbl_gamma = (double)avd_get_int(rndp->rnd_gamma) / 1000.0; + + rndp->rnd_vint_min = avd_get_int(rndp->rnd_min); + rndp->rnd_vint_round = avd_get_int(rndp->rnd_round); + + filebench_log(LOG_DEBUG_IMPL, + "init random var %s: Mean = %6.0llf, Gamma = %6.3llf, Min = %lld", + rndp->rnd_var->var_name, rndp->rnd_dbl_mean, rndp->rnd_dbl_gamma, + rndp->rnd_vint_min); + + /* initialize distribution to apply */ + switch (rndp->rnd_type & RAND_TYPE_MASK) { + case RAND_TYPE_UNIFORM: + rndp->rnd_get = rand_uniform_get; + break; + + case RAND_TYPE_GAMMA: + rndp->rnd_get = rand_gamma_get; + break; + + case RAND_TYPE_TABLE: + rndp->rnd_get = rand_table_get; + break; + + default: + filebench_log(LOG_DEBUG_IMPL, "Random Type not Specified"); + filebench_shutdown(1); + return; + } + + /* initialize source of random numbers */ + if (rndp->rnd_type & RAND_SRC_GENERATOR) { + rndp->rnd_src = rand_src_rand48; + rand_seed_set(rndp); + } else { + rndp->rnd_src = rand_src_urandom; + } + + /* any random distribution table to convert? */ + if ((rdte_hdp = rndp->rnd_probtabs) == NULL) + return; + + /* determine random distribution max and mins and initialize table */ + pteidx = 0; + tablemean = 0.0; + for (ptep = rdte_hdp; ptep; ptep = ptep->pte_next) { + double dmin, dmax; + int entcnt; + + dmax = (double)avd_get_int(ptep->pte_segmax); + dmin = (double)avd_get_int(ptep->pte_segmin); + + /* initialize table minimum on first pass */ + if (pteidx == 0) + tablemin = dmin; + + /* update table minimum */ + if (tablemin > dmin) + tablemin = dmin; + + entcnt = (int)avd_get_int(ptep->pte_percent); + tablemean += (((dmin + dmax)/2.0) * (double)entcnt); + + /* populate the lookup table */ + + for (; entcnt > 0; entcnt--) { + rndp->rnd_rft[pteidx].rf_base = dmin; + rndp->rnd_rft[pteidx].rf_range = dmax - dmin; + pteidx++; + } + } + + /* check to see if probability equals 100% */ + if (pteidx != PF_TAB_SIZE) + filebench_log(LOG_ERROR, + "Prob table only totals %d%%", pteidx); + + /* If table is not supplied with a mean value, set it to table mean */ + if (rndp->rnd_dbl_mean == 0.0) + rndp->rnd_dbl_mean = (double)tablemean / (double)PF_TAB_SIZE; + + /* now normalize the entries for a min value of 0, mean of 1 */ + tablemean = (tablemean / 100.0) - tablemin; + + /* special case if really a constant value */ + if (tablemean == 0.0) { + for (pteidx = 0; pteidx < PF_TAB_SIZE; pteidx++) { + rndp->rnd_rft[pteidx].rf_base = 0.0; + rndp->rnd_rft[pteidx].rf_range = 0.0; + } + return; + } + + for (pteidx = 0; pteidx < PF_TAB_SIZE; pteidx++) { + + rndp->rnd_rft[pteidx].rf_base = + ((rndp->rnd_rft[pteidx].rf_base - tablemin) / tablemean); + rndp->rnd_rft[pteidx].rf_range = + (rndp->rnd_rft[pteidx].rf_range / tablemean); + } +} + +/* + * initialize all the random distribution entities + */ +void +randdist_init(void) +{ + randdist_t *rndp; + + for (rndp = filebench_shm->shm_rand_list; rndp; rndp = rndp->rnd_next) + randdist_init_one(rndp); +} + +/* + * Initialize the urandom random number source + */ +void +fb_random_init(void) +{ + /* open the "urandom" random number device file */ + if ((urandomfd = open("/dev/urandom", O_RDONLY)) < 0) { + filebench_log(LOG_ERROR, "open /dev/urandom failed: %s", + strerror(errno)); + filebench_shutdown(1); + } +} diff --git a/usr/src/cmd/filebench/common/fb_random.h b/usr/src/cmd/filebench/common/fb_random.h new file mode 100644 index 0000000000..027b299d26 --- /dev/null +++ b/usr/src/cmd/filebench/common/fb_random.h @@ -0,0 +1,116 @@ +/* + * 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. + */ + +#ifndef _FB_RANDOM_H +#define _FB_RANDOM_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include "config.h" + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * probability table entry, used while parsing the supplied + * probability table + */ +typedef struct probtabent { + struct probtabent *pte_next; + avd_t pte_percent; + avd_t pte_segmin; + avd_t pte_segmax; +} probtabent_t; + +/* + * The supplied probability table is converted into a probability funtion + * lookup table at initialization time. This is the definition for each + * entry in the table. + */ +typedef struct randfunc { + double rf_base; + double rf_range; +} randfunc_t; + +/* Number of entries in the probability function table */ +#define PF_TAB_SIZE 100 + +/* + * Random Distribution definition object. Includes a pointer to the + * appropriate function to access the distribution defined by the object, + * as well as a function pointer to the specified source of random + * numbers. + */ +typedef struct randdist { + double (*rnd_get)(struct randdist *); + double (*rnd_src)(unsigned short *); + struct randdist *rnd_next; + struct var *rnd_var; + avd_t rnd_seed; + avd_t rnd_mean; + avd_t rnd_gamma; + avd_t rnd_min; + avd_t rnd_round; + double rnd_dbl_mean; + double rnd_dbl_gamma; + fbint_t rnd_vint_min; + fbint_t rnd_vint_round; + probtabent_t *rnd_probtabs; + randfunc_t rnd_rft[PF_TAB_SIZE]; + uint16_t rnd_xi[3]; + uint16_t rnd_type; +} randdist_t; + +#define RAND_TYPE_UNIFORM 0x1 +#define RAND_TYPE_GAMMA 0x2 +#define RAND_TYPE_TABLE 0x3 +#define RAND_TYPE_MASK 0x0fff +#define RAND_SRC_URANDOM 0x0000 +#define RAND_SRC_GENERATOR 0x1000 + +#define RAND_PARAM_TYPE 1 +#define RAND_PARAM_SRC 2 +#define RAND_PARAM_SEED 3 +#define RAND_PARAM_MIN 4 +#define RAND_PARAM_MEAN 5 +#define RAND_PARAM_GAMMA 6 +#define RAND_PARAM_ROUND 7 + +randdist_t *randdist_alloc(void); +void randdist_init(void); +int filebench_randomno32(uint32_t *, uint32_t, uint32_t, avd_t); +int filebench_randomno64(uint64_t *, uint64_t, uint64_t, avd_t); +void fb_random_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _FB_RANDOM_H */ diff --git a/usr/src/cmd/filebench/common/filebench.h b/usr/src/cmd/filebench/common/filebench.h index ae710b587b..e41813f529 100644 --- a/usr/src/cmd/filebench/common/filebench.h +++ b/usr/src/cmd/filebench/common/filebench.h @@ -66,6 +66,14 @@ 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; @@ -90,8 +98,6 @@ void filebench_shutdown(int error); #define filebench_randomno filebench_randomno32 #define FILEBENCH_RANDMAX FILEBENCH_RANDMAX32 #endif -int filebench_randomno32(uint32_t *, uint32_t, uint32_t); -int filebench_randomno64(uint64_t *, uint64_t, uint64_t); #define KB (1024LL) #define MB (KB * KB) @@ -103,7 +109,7 @@ int filebench_randomno64(uint64_t *, uint64_t, uint64_t); #define MIN(x, y) ((x) < (y) ? (x) : (y)) #endif -#define FILEBENCH_VERSION "1.1.1" +#define FILEBENCH_VERSION "1.2.0" #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 0148ff0894..72d6bc856e 100644 --- a/usr/src/cmd/filebench/common/fileset.c +++ b/usr/src/cmd/filebench/common/fileset.c @@ -19,7 +19,7 @@ * 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. */ @@ -41,7 +41,7 @@ * information about collections of files and subdirectories in Filebench. * The fileset, once populated, consists of a tree of fileset entries of * type filesetentry_t which specify files and directories. The fileset - * is rooted in a directory specified by fs_path, and once the populated + * is rooted in a directory specified by fileset_path, and once the populated * fileset has been created, has a tree of directories and files * corresponding to the fileset's filesetentry tree. */ @@ -97,8 +97,12 @@ fileset_usage(void) "define [file name=<name> | fileset name=<name>],path=<pathname>," ",entries=<number>\n"); (void) fprintf(stderr, + " [,filesize=[size]]\n"); + (void) fprintf(stderr, " [,dirwidth=[width]]\n"); (void) fprintf(stderr, + " [,dirdepthrv=$random_variable_name]\n"); + (void) fprintf(stderr, " [,dirgamma=[100-10000]] " "(Gamma * 1000)\n"); (void) fprintf(stderr, @@ -263,9 +267,9 @@ fileset_alloc_file(filesetentry_t *entry) int fd; *path = 0; - (void) strcpy(path, *entry->fse_fileset->fs_path); + (void) strcpy(path, avd_get_str(entry->fse_fileset->fs_path)); (void) strcat(path, "/"); - (void) strcat(path, entry->fse_fileset->fs_name); + (void) strcat(path, avd_get_str(entry->fse_fileset->fs_name)); pathtmp = fileset_resolvepath(entry); (void) strcat(path, pathtmp); @@ -284,7 +288,7 @@ fileset_alloc_file(filesetentry_t *entry) filebench_log(LOG_INFO, "Re-using file %s", path); - if (!integer_isset(entry->fse_fileset->fs_cached)) + if (!avd_get_bool(entry->fse_fileset->fs_cached)) (void) fileset_freemem(fd, entry->fse_size); @@ -300,7 +304,7 @@ fileset_alloc_file(filesetentry_t *entry) (void) ftruncate64(fd, (off64_t)entry->fse_size); - if (!integer_isset(entry->fse_fileset->fs_cached)) + if (!avd_get_bool(entry->fse_fileset->fs_cached)) (void) fileset_freemem(fd, entry->fse_size); @@ -347,7 +351,7 @@ fileset_alloc_file(filesetentry_t *entry) seek += wsize; } - if (!integer_isset(entry->fse_fileset->fs_cached)) + if (!avd_get_bool(entry->fse_fileset->fs_cached)) (void) fileset_freemem(fd, entry->fse_size); (void) close(fd); @@ -403,9 +407,9 @@ fileset_openfile(fileset_t *fileset, int open_attrs = 0; *path = 0; - (void) strcpy(path, *fileset->fs_path); + (void) strcpy(path, avd_get_str(fileset->fs_path)); (void) strcat(path, "/"); - (void) strcat(path, fileset->fs_name); + (void) strcat(path, avd_get_str(fileset->fs_name)); pathtmp = fileset_resolvepath(entry); (void) strcat(path, pathtmp); (void) strcpy(dir, path); @@ -557,14 +561,14 @@ empty: /* * Given a fileset "fileset", create the associated files as * specified in the attributes of the fileset. The fileset is - * rooted in a directory whose pathname is in fs_path. If the + * rooted in a directory whose pathname is in fileset_path. If the * directory exists, meaning that there is already a fileset, - * and the fs_reuse attribute is false, then remove it and all + * and the fileset_reuse attribute is false, then remove it and all * its contained files and subdirectories. Next, the routine * creates a root directory for the fileset. All the file type * filesetentries are cycled through creating as needed * their containing subdirectory trees in the filesystem and - * creating actual files for fs_preallocpercent of them. The + * 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. */ @@ -576,15 +580,24 @@ fileset_create(fileset_t *fileset) struct stat64 sb; int pickflags = FILESET_PICKUNIQUE | FILESET_PICKRESET; hrtime_t start = gethrtime(); + char *fileset_path; + char *fileset_name; + int randno; int preallocated = 0; int reusing = 0; - if (*fileset->fs_path == NULL) { + if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { filebench_log(LOG_ERROR, "%s path not set", fileset_entity_name(fileset)); return (-1); } + if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { + filebench_log(LOG_ERROR, "%s name not set", + fileset_entity_name(fileset)); + return (-1); + } + #ifdef HAVE_RAW_SUPPORT /* treat raw device as special case */ if (fileset->fs_attrs & FILESET_IS_RAW_DEV) @@ -594,19 +607,19 @@ fileset_create(fileset_t *fileset) /* XXX Add check to see if there is enough space */ /* Remove existing */ - (void) strcpy(path, *fileset->fs_path); + (void) strcpy(path, fileset_path); (void) strcat(path, "/"); - (void) strcat(path, fileset->fs_name); + (void) strcat(path, fileset_name); if ((stat64(path, &sb) == 0) && (strlen(path) > 3) && - (strlen(*fileset->fs_path) > 2)) { - if (!integer_isset(fileset->fs_reuse)) { + (strlen(avd_get_str(fileset->fs_path)) > 2)) { + if (!avd_get_bool(fileset->fs_reuse)) { char cmd[MAXPATHLEN]; (void) snprintf(cmd, sizeof (cmd), "rm -rf %s", path); (void) system(cmd); filebench_log(LOG_VERBOSE, "Removed any existing %s %s in %lld seconds", - fileset_entity_name(fileset), fileset->fs_name, + fileset_entity_name(fileset), fileset_name, ((gethrtime() - start) / 1000000000) + 1); } else { /* we are re-using */ @@ -614,7 +627,7 @@ fileset_create(fileset_t *fileset) filebench_log(LOG_VERBOSE, "Re-using %s %s on %s file system.", fileset_entity_name(fileset), - fileset->fs_name, sb.st_fstype); + fileset_name, sb.st_fstype); } } (void) mkdir(path, 0755); @@ -626,22 +639,21 @@ fileset_create(fileset_t *fileset) start = gethrtime(); filebench_log(LOG_VERBOSE, "Creating %s %s...", - fileset_entity_name(fileset), fileset->fs_name); + fileset_entity_name(fileset), fileset_name); - if (!integer_isset(fileset->fs_prealloc)) + if (!avd_get_bool(fileset->fs_prealloc)) goto exit; + randno = ((RAND_MAX * (100 + - avd_get_int(fileset->fs_preallocpercent))) / 100); + while (entry = fileset_pick(fileset, pickflags, 0)) { - int randno; pthread_t tid; pickflags = FILESET_PICKUNIQUE; entry->fse_flags &= ~FSE_EXISTS; - randno = ((RAND_MAX * (100 - *(fileset->fs_preallocpercent))) - / 100); - /* entry doesn't need to be locked during initialization */ (void) ipc_mutex_unlock(&entry->fse_lock); @@ -655,7 +667,7 @@ fileset_create(fileset_t *fileset) else entry->fse_flags &= (~FSE_REUSING); - if (integer_isset(fileset->fs_paralloc)) { + if (avd_get_bool(fileset->fs_paralloc)) { /* fire off a separate allocation thread */ (void) pthread_mutex_lock(¶lloc_lock); @@ -690,9 +702,8 @@ exit: filebench_log(LOG_VERBOSE, "Preallocated %d of %lld of %s %s in %lld seconds", preallocated, - *(fileset->fs_entries), - fileset_entity_name(fileset), - fileset->fs_name, + fileset->fs_constentries, + fileset_entity_name(fileset), fileset_name, ((gethrtime() - start) / 1000000000) + 1); return (0); @@ -733,9 +744,9 @@ fileset_insdirlist(fileset_t *fileset, filesetentry_t *entry) /* * Obtaines a filesetentry entity for a file to be placed in a * (sub)directory of a fileset. The size of the file may be - * specified by fs_meansize, or calculated from a gamma - * distribution of parameter fs_sizegamma and of mean size - * fs_meansize. The filesetentry entity is placed on the file + * specified by fileset_meansize, or calculated from a gamma + * distribution of parameter fileset_sizegamma and of mean size + * fileset_meansize. The filesetentry entity is placed on the file * list in the specified parent filesetentry entity, which may * be a directory filesetentry, or the root filesetentry in the * fileset. It is also placed on the fileset's list of all @@ -748,7 +759,6 @@ fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) char tmpname[16]; filesetentry_t *entry; double drand; - double gamma; if ((entry = (filesetentry_t *)ipc_malloc(FILEBENCH_FILESETENTRY)) == NULL) { @@ -770,13 +780,20 @@ fileset_populate_file(fileset_t *fileset, filesetentry_t *parent, int serial) return (-1); } - gamma = *(fileset->fs_sizegamma) / 1000.0; - - if (gamma > 0) { - drand = gamma_dist_knuth(gamma, fileset->fs_meansize / gamma); - entry->fse_size = (off64_t)drand; + /* see if random variable was supplied for file size */ + if (fileset->fs_meansize == -1) { + entry->fse_size = (off64_t)avd_get_int(fileset->fs_size); } else { - entry->fse_size = (off64_t)fileset->fs_meansize; + double gamma; + + gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; + if (gamma > 0) { + drand = gamma_dist_knuth(gamma, + fileset->fs_meansize / gamma); + entry->fse_size = (off64_t)drand; + } else { + entry->fse_size = (off64_t)fileset->fs_meansize; + } } fileset->fs_bytes += entry->fse_size; @@ -808,7 +825,7 @@ static int fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, int serial, double depth) { - double randepth, drand, ranwidth, gamma; + double randepth, drand, ranwidth; int isleaf = 0; char tmpname[16]; filesetentry_t *entry; @@ -837,21 +854,34 @@ fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, entry->fse_flags |= FSE_DIR | FSE_FREE; fileset_insdirlist(fileset, entry); - gamma = *(fileset->fs_dirgamma) / 1000.0; - if (gamma > 0) { - drand = gamma_dist_knuth(gamma, fileset->fs_meandepth / gamma); - randepth = (int)drand; + if (fileset->fs_dirdepthrv) { + randepth = (int)avd_get_int(fileset->fs_dirdepthrv); } else { - randepth = (int)fileset->fs_meandepth; - } + double gamma; - gamma = *(fileset->fs_sizegamma) / 1000.0; + gamma = avd_get_int(fileset->fs_dirgamma) / 1000.0; + if (gamma > 0) { + drand = gamma_dist_knuth(gamma, + fileset->fs_meandepth / gamma); + randepth = (int)drand; + } else { + randepth = (int)fileset->fs_meandepth; + } + } - if (gamma > 0) { - drand = gamma_dist_knuth(gamma, fileset->fs_meanwidth / gamma); - ranwidth = drand; + if (fileset->fs_meanwidth == -1) { + ranwidth = avd_get_dbl(fileset->fs_dirwidth); } else { - ranwidth = fileset->fs_meanwidth; + double gamma; + + gamma = avd_get_int(fileset->fs_sizegamma) / 1000.0; + if (gamma > 0) { + drand = gamma_dist_knuth(gamma, + fileset->fs_meanwidth / gamma); + ranwidth = drand; + } else { + ranwidth = fileset->fs_meanwidth; + } } if (randepth == 0) @@ -865,9 +895,9 @@ fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, * Create directory of random width according to distribution, or * if root directory, continue until #files required */ - for (i = 1; - ((parent == NULL) || (i < ranwidth + 1)) && - (fileset->fs_realfiles < *(fileset->fs_entries)); i++) { + for (i = 1; ((parent == NULL) || (i < ranwidth + 1)) && + (fileset->fs_realfiles < fileset->fs_constentries); + i++) { int ret = 0; if (parent && isleaf) @@ -883,9 +913,9 @@ fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, /* * Populates a fileset with files and subdirectory entries. Uses - * the supplied fs_dirwidth and fs_entries (number of files) to - * calculate the required fs_meandepth (of subdirectories) and - * initialize the fs_meanwidth and fs_meansize variables. Then + * the supplied fileset_dirwidth and fileset_entries (number of files) to + * calculate the required fileset_meandepth (of subdirectories) and + * initialize the fileset_meanwidth and fileset_meansize variables. Then * calls fileset_populate_subdir() to do the recursive * subdirectory entry creation and leaf file entry creation. All * of the above is skipped if the fileset has already been @@ -895,8 +925,8 @@ fileset_populate_subdir(fileset_t *fileset, filesetentry_t *parent, static int fileset_populate(fileset_t *fileset) { - int nfiles; - int meandirwidth = *(fileset->fs_dirwidth); + int entries = (int)avd_get_int(fileset->fs_entries); + int meandirwidth; int ret; /* Skip if already populated */ @@ -909,6 +939,19 @@ fileset_populate(fileset_t *fileset) return (0); #endif /* HAVE_RAW_SUPPORT */ + /* save value of entries obtained for later, in case it was random */ + fileset->fs_constentries = entries; + + /* is dirwidth a random variable? */ + if (AVD_IS_RANDOM(fileset->fs_dirwidth)) { + meandirwidth = + (int)fileset->fs_dirwidth->avd_val.randptr->rnd_dbl_mean; + fileset->fs_meanwidth = -1; + } else { + meandirwidth = (int)avd_get_int(fileset->fs_dirwidth); + fileset->fs_meanwidth = (double)meandirwidth; + } + /* * Input params are: * # of files @@ -917,10 +960,20 @@ fileset_populate(fileset_t *fileset) * # ave size of file * max size of file */ - nfiles = *(fileset->fs_entries); - fileset->fs_meandepth = log(nfiles) / log(meandirwidth); - fileset->fs_meanwidth = meandirwidth; - fileset->fs_meansize = *(fileset->fs_size); + fileset->fs_meandepth = log(entries) / log(meandirwidth); + + /* Has a random variable been supplied for dirdepth? */ + if (fileset->fs_dirdepthrv) { + /* yes, so set the random variable's mean value to meandepth */ + fileset->fs_dirdepthrv->avd_val.randptr->rnd_dbl_mean = + fileset->fs_meandepth; + } + + /* test for random size variable */ + if (AVD_IS_RANDOM(fileset->fs_size)) + fileset->fs_meansize = -1; + else + fileset->fs_meansize = avd_get_int(fileset->fs_size); if ((ret = fileset_populate_subdir(fileset, NULL, 1, 0)) != 0) return (ret); @@ -929,14 +982,13 @@ fileset_populate(fileset_t *fileset) exists: if (fileset->fs_attrs & FILESET_IS_FILE) { filebench_log(LOG_VERBOSE, "File %s: mbytes=%lld", - fileset->fs_name, + avd_get_str(fileset->fs_name), fileset->fs_bytes / 1024UL / 1024UL); } else { filebench_log(LOG_VERBOSE, "Fileset %s: %lld files, " - "avg dir = %.1lf, avg depth = %.1lf, mbytes=%lld", - fileset->fs_name, - *(fileset->fs_entries), - fileset->fs_meanwidth, + "avg dir = %d, avg depth = %.1lf, mbytes=%lld", + avd_get_str(fileset->fs_name), entries, + meandirwidth, fileset->fs_meandepth, fileset->fs_bytes / 1024UL / 1024UL); } @@ -944,13 +996,13 @@ exists: } /* - * Allocates a fileset instance, initializes fs_dirgamma and - * fs_sizegamma default values, and sets the fileset name to the + * Allocates a fileset instance, initializes fileset_dirgamma and + * fileset_sizegamma default values, and sets the fileset name to the * supplied name string. Puts the allocated fileset on the * master fileset list and returns a pointer to it. */ fileset_t * -fileset_define(char *name) +fileset_define(avd_t name) { fileset_t *fileset; @@ -963,12 +1015,13 @@ fileset_define(char *name) return (NULL); } - filebench_log(LOG_DEBUG_IMPL, "Defining file %s", name); + filebench_log(LOG_DEBUG_IMPL, + "Defining file %s", avd_get_str(name)); (void) ipc_mutex_lock(&filebench_shm->fileset_lock); - fileset->fs_dirgamma = integer_alloc(1500); - fileset->fs_sizegamma = integer_alloc(1500); + fileset->fs_dirgamma = avd_int_alloc(1500); + fileset->fs_sizegamma = avd_int_alloc(1500); /* Add fileset to global list */ if (filebench_shm->filesetlist == NULL) { @@ -981,14 +1034,14 @@ fileset_define(char *name) (void) ipc_mutex_unlock(&filebench_shm->fileset_lock); - (void) strcpy(fileset->fs_name, name); + fileset->fs_name = name; return (fileset); } /* * If supplied with a pointer to a fileset and the fileset's - * fs_prealloc flag is set, calls fileset_populate() to populate + * fileset_prealloc flag is set, calls fileset_populate() to populate * the fileset with filesetentries, then calls fileset_create() * to make actual directories and files for the filesetentries. * Otherwise, it applies fileset_populate() and fileset_create() @@ -1008,11 +1061,12 @@ fileset_createset(fileset_t *fileset) /* set up for possible parallel allocate */ paralloc_count = 0; - if (fileset && integer_isset(fileset->fs_prealloc)) { + if (fileset && avd_get_bool(fileset->fs_prealloc)) { filebench_log(LOG_INFO, "creating/pre-allocating %s %s", - fileset_entity_name(fileset), fileset->fs_name); + fileset_entity_name(fileset), + avd_get_str(fileset->fs_name)); if ((ret = fileset_populate(fileset)) != 0) return (ret); @@ -1061,7 +1115,7 @@ fileset_find(char *name) (void) ipc_mutex_lock(&filebench_shm->fileset_lock); while (fileset) { - if (strcmp(name, fileset->fs_name) == 0) { + if (strcmp(name, avd_get_str(fileset->fs_name)) == 0) { (void) ipc_mutex_unlock(&filebench_shm->fileset_lock); return (fileset); } @@ -1103,9 +1157,24 @@ fileset_iter(int (*cmd)(fileset_t *fileset, int first)) int fileset_print(fileset_t *fileset, int first) { - int pathlength = strlen(*fileset->fs_path) + strlen(fileset->fs_name); - /* 30 spaces */ - char pad[] = " "; + int pathlength; + char *fileset_path; + char *fileset_name; + static char pad[] = " "; /* 30 spaces */ + + if ((fileset_path = avd_get_str(fileset->fs_path)) == NULL) { + filebench_log(LOG_ERROR, "%s path not set", + fileset_entity_name(fileset)); + return (-1); + } + + if ((fileset_name = avd_get_str(fileset->fs_name)) == NULL) { + filebench_log(LOG_ERROR, "%s name not set", + fileset_entity_name(fileset)); + return (-1); + } + + pathlength = strlen(fileset_path) + strlen(fileset_name); if (pathlength > 29) pathlength = 29; @@ -1121,25 +1190,20 @@ fileset_print(fileset_t *fileset, int first) if (fileset->fs_attrs & FILESET_IS_RAW_DEV) { filebench_log(LOG_INFO, "%s/%s%s (Raw Device)", - *fileset->fs_path, - fileset->fs_name, - &pad[pathlength]); + fileset_path, fileset_name, &pad[pathlength]); } else { filebench_log(LOG_INFO, "%s/%s%s%9lld (Single File)", - *fileset->fs_path, - fileset->fs_name, - &pad[pathlength], - *fileset->fs_size); + fileset_path, fileset_name, &pad[pathlength], + avd_get_int(fileset->fs_size)); } } else { filebench_log(LOG_INFO, "%s/%s%s%9lld%12lld%10lld", - *fileset->fs_path, - fileset->fs_name, + fileset_path, fileset_name, &pad[pathlength], - *fileset->fs_size, - *fileset->fs_dirwidth, - *fileset->fs_entries); + avd_get_int(fileset->fs_size), + avd_get_int(fileset->fs_dirwidth), + fileset->fs_constentries); } return (0); } @@ -1159,9 +1223,9 @@ fileset_checkraw(fileset_t *fileset) #ifdef HAVE_RAW_SUPPORT /* check for raw device */ - (void) strcpy(path, *fileset->fs_path); + (void) strcpy(path, avd_get_str(fileset->fs_path)); (void) strcat(path, "/"); - (void) strcat(path, fileset->fs_name); + (void) strcat(path, avd_get_str(fileset->fs_name)); 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 8f81afaac8..fe0b86ec79 100644 --- a/usr/src/cmd/filebench/common/fileset.h +++ b/usr/src/cmd/filebench/common/fileset.h @@ -19,7 +19,7 @@ * 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. */ @@ -92,37 +92,45 @@ typedef struct filesetentry { typedef struct fileset { struct fileset *fs_next; /* Next in list */ - char fs_name[128]; /* Name */ - var_string_t fs_path; /* Pathname prefix in fs */ - var_integer_t fs_entries; /* Set size */ - var_integer_t fs_preallocpercent; /* Prealloc size */ + avd_t fs_name; /* Name */ + avd_t fs_path; /* Pathname prefix in fileset */ + avd_t fs_entries; /* Number of entries attr */ + /* (possibly random) */ + fbint_t fs_constentries; /* Constant version of enties attr */ + avd_t fs_preallocpercent; /* Prealloc size */ int fs_attrs; /* Attributes */ - var_integer_t fs_dirwidth; /* Explicit or 0 for distribution */ - var_integer_t fs_size; /* Explicit or 0 for distribution */ - var_integer_t fs_dirgamma; /* Dirwidth Gamma distribution (* 1000) */ - var_integer_t fs_sizegamma; /* Filesize Gamma distribution (* 1000) */ - var_integer_t fs_create; /* Attr */ - var_integer_t fs_prealloc; /* Attr */ - var_integer_t fs_paralloc; /* Attr */ - var_integer_t fs_cached; /* Attr */ - var_integer_t fs_reuse; /* Attr */ + avd_t fs_dirwidth; /* Explicit or mean for distribution */ + avd_t fs_dirdepthrv; /* random variable for dir depth */ + avd_t fs_size; /* Explicit or mean for distribution */ + avd_t fs_dirgamma; /* Dirdepth Gamma distribution */ + /* (* 1000) defaults to 1500, set */ + /* to 0 for explicit depth */ + avd_t fs_sizegamma; /* Filesize and dirwidth Gamma */ + /* distribution (* 1000), default */ + /* is 1500, set to 0 for explicit */ + avd_t fs_create; /* Attr */ + avd_t fs_prealloc; /* Attr */ + avd_t fs_paralloc; /* Attr */ + avd_t fs_cached; /* Attr */ + avd_t fs_reuse; /* Attr */ double fs_meandepth; /* Computed mean depth */ double fs_meanwidth; /* Specified mean dir width */ double fs_meansize; /* Specified mean file size */ int fs_realfiles; /* Actual files */ - off64_t fs_bytes; /* Space potentially consumed by all files */ + off64_t fs_bytes; /* Total space consumed by files */ 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_filerotor[FSE_MAXTID]; /* next file to */ + /* select */ filesetentry_t *fs_dirrotor; /* Ptr to next directory to select */ } fileset_t; int fileset_createset(fileset_t *); int fileset_openfile(fileset_t *fileset, filesetentry_t *entry, int flag, int mode, int attrs); -fileset_t *fileset_define(char *); +fileset_t *fileset_define(avd_t); fileset_t *fileset_find(char *name); filesetentry_t *fileset_pick(fileset_t *fileset, int flags, int tid); char *fileset_resolvepath(filesetentry_t *entry); diff --git a/usr/src/cmd/filebench/common/flowop.c b/usr/src/cmd/filebench/common/flowop.c index 4140234377..1b86a0c8a4 100644 --- a/usr/src/cmd/filebench/common/flowop.c +++ b/usr/src/cmd/filebench/common/flowop.c @@ -41,8 +41,7 @@ #endif static flowop_t *flowop_define_common(threadflow_t *threadflow, char *name, - flowop_t *inherit, int instance, int type); - + flowop_t *inherit, int instance, int type); /* * A collection of flowop support functions. The actual code that @@ -72,6 +71,22 @@ flowop_printlist(flowop_t *list) return (0); } +/* + * Prints the name and instance number of all flowops on + * the master flowop list to the console and the filebench log. + */ +void +flowop_printall(void) +{ + flowop_t *flowop = filebench_shm->flowoplist; + + while (flowop) { + filebench_log(LOG_VERBOSE, "flowop-list %s-%d", + flowop->fo_name, flowop->fo_instance); + flowop = flowop->fo_next; + } +} + #define TIMESPEC_TO_HRTIME(s, e) (((e.tv_sec - s.tv_sec) * 1000000000LL) + \ (e.tv_nsec - s.tv_nsec)) /* @@ -111,6 +126,7 @@ flowop_beginop(threadflow_t *threadflow, flowop_t *flowop) } flowstat_t controlstats; +pthread_mutex_t controlstats_lock; static int controlstats_zeroed = 0; /* @@ -156,6 +172,7 @@ flowop_endop(threadflow_t *threadflow, flowop_t *flowop, int64_t bytes) flowop->fo_stats.fs_count++; flowop->fo_stats.fs_bytes += bytes; + (void) ipc_mutex_lock(&controlstats_lock); if ((flowop->fo_type & FLOW_TYPE_IO) || (flowop->fo_type & FLOW_TYPE_AIO)) { controlstats.fs_count++; @@ -174,6 +191,7 @@ flowop_endop(threadflow_t *threadflow, flowop_t *flowop, int64_t bytes) controlstats.fs_wbytes += bytes; controlstats.fs_wcount++; } + (void) ipc_mutex_unlock(&controlstats_lock); } /* @@ -183,6 +201,13 @@ flowop_endop(threadflow_t *threadflow, flowop_t *flowop, int64_t bytes) static int 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); + flowop->fo_constwss = avd_get_int(flowop->fo_wss); + if ((*flowop->fo_init)(flowop) < 0) { filebench_log(LOG_ERROR, "flowop %s-%d init failed", flowop->fo_name, flowop->fo_instance); @@ -263,10 +288,12 @@ flowop_start(threadflow_t *threadflow) } #endif + (void) ipc_mutex_lock(&controlstats_lock); if (!controlstats_zeroed) { (void) memset(&controlstats, 0, sizeof (controlstats)); controlstats_zeroed = 1; } + (void) ipc_mutex_unlock(&controlstats_lock); flowop = threadflow->tf_ops; threadflow->tf_stats.fs_stime = gethrtime(); @@ -316,15 +343,17 @@ flowop_start(threadflow_t *threadflow) threadflow->tf_abort = 0; threadflow->tf_running = 1; + memsize = (size_t)threadflow->tf_constmemsize; + /* If we are going to use ISM, allocate later */ if (threadflow->tf_attrs & THREADFLOW_USEISM) { threadflow->tf_mem = - ipc_ismmalloc((size_t)*threadflow->tf_memsize); + ipc_ismmalloc(memsize); } else { - threadflow->tf_mem = malloc((size_t)*threadflow->tf_memsize); + threadflow->tf_mem = + malloc(memsize); } - memsize = *threadflow->tf_memsize; (void) memset(threadflow->tf_mem, 0, memsize); filebench_log(LOG_DEBUG_SCRIPT, "Thread allocated %d bytes", memsize); @@ -337,7 +366,7 @@ flowop_start(threadflow_t *threadflow) /* Main filebench worker loop */ /* CONSTCOND */ while (1) { - int i; + int i, count; /* Abort if asked */ if (threadflow->tf_abort || filebench_shm->f_abort) @@ -353,26 +382,23 @@ flowop_start(threadflow_t *threadflow) if (!filebench_shm->shm_running) (void) sleep(1); - if (flowop->fo_stats.fs_stime == 0) - flowop->fo_stats.fs_stime = gethrtime(); - if (flowop == NULL) { filebench_log(LOG_ERROR, "flowop_read null flowop"); return; } - filebench_log(LOG_DEBUG_SCRIPT, "%s: executing flowop %s-%d", - threadflow->tf_name, flowop->fo_name, flowop->fo_instance); + if (flowop->fo_stats.fs_stime == 0) + flowop->fo_stats.fs_stime = gethrtime(); /* Execute the flowop for fo_iters times */ - for (i = 0; i < *flowop->fo_iters; i++) { + count = avd_get_int(flowop->fo_iters); + for (i = 0; i < count; i++) { + filebench_log(LOG_DEBUG_SCRIPT, "%s: executing flowop " "%s-%d", threadflow->tf_name, flowop->fo_name, flowop->fo_instance); + ret = (*flowop->fo_func)(threadflow, flowop); - filebench_log(LOG_DEBUG_SCRIPT, "%s: executing flowop " - "%s-%d", threadflow->tf_name, flowop->fo_name, - flowop->fo_instance); /* * Return value FILEBENCH_ERROR means "flowop @@ -561,7 +587,7 @@ flowop_delete_all(flowop_t **flowoplist) filebench_log(LOG_DEBUG_IMPL, "Deleting all flowops..."); while (flowop) { - filebench_log(LOG_DEBUG_IMPL, "Deleting all flowops (%s-%d)", + filebench_log(LOG_DEBUG_IMPL, "Deleting flowop (%s-%d)", flowop->fo_name, flowop->fo_instance); flowop = flowop->fo_threadnext; } @@ -631,7 +657,7 @@ flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit, } else { (void) memset(flowop, 0, sizeof (flowop_t)); flowop->fo_fd = -1; - flowop->fo_iters = integer_alloc(1); + flowop->fo_iters = avd_int_alloc(1); flowop->fo_type = type; (void) pthread_mutex_init(&flowop->fo_lock, ipc_mutexattr()); (void) ipc_mutex_lock(&flowop->fo_lock); @@ -682,7 +708,7 @@ flowop_t * flowop_define(threadflow_t *threadflow, char *name, flowop_t *inherit, int instance, int type) { - flowop_t *flowop; + flowop_t *flowop; (void) ipc_mutex_lock(&filebench_shm->flowop_lock); flowop = flowop_define_common(threadflow, name, @@ -721,13 +747,15 @@ flowop_find_barrier(void) flowop_t * flowop_find(char *name) { - flowop_t *flowop = filebench_shm->flowoplist; + flowop_t *flowop; flowop_t *result = NULL; flowop_find_barrier(); (void) ipc_mutex_lock(&filebench_shm->flowop_lock); + flowop = filebench_shm->flowoplist; + while (flowop) { if (strcmp(name, flowop->fo_name) == 0) { @@ -751,21 +779,28 @@ flowop_find(char *name) /* * Returns a pointer to the specified instance of flowop - * "name" from the list returned by flowop_find(). + * "name" from the supplied list. */ flowop_t * flowop_find_one(char *name, int instance) { - flowop_t *result; + flowop_t *test_flowop; + + flowop_find_barrier(); + + (void) ipc_mutex_lock(&filebench_shm->flowop_lock); - result = flowop_find(name); + test_flowop = filebench_shm->flowoplist; - while (result) { - if ((strcmp(name, result->fo_name) == 0) && - (instance == result->fo_instance)) + while (test_flowop) { + if ((strcmp(name, test_flowop->fo_name) == 0) && + (instance == test_flowop->fo_instance)) break; - result = result->fo_next; + + test_flowop = test_flowop->fo_next; } - return (result); + (void) ipc_mutex_unlock(&filebench_shm->flowop_lock); + + return (test_flowop); } diff --git a/usr/src/cmd/filebench/common/flowop.h b/usr/src/cmd/filebench/common/flowop.h index 8aa9b33440..d98b1d0ff8 100644 --- a/usr/src/cmd/filebench/common/flowop.h +++ b/usr/src/cmd/filebench/common/flowop.h @@ -64,28 +64,32 @@ typedef struct flowop { void (*fo_destruct)(); /* Destructor Method */ int fo_type; /* Type */ int fo_attrs; /* Flow op attribute */ + avd_t fo_filename; /* file/fileset name */ fileset_t *fo_fileset; /* Fileset for op */ int fo_fd; /* File descriptor */ int fo_fdnumber; /* User specified file descriptor */ int fo_srcfdnumber; /* User specified src file descriptor */ - var_integer_t fo_iosize; /* Size of operation */ - var_integer_t fo_wss; /* Flow op working set size */ + fbint_t fo_constvalue; /* constant version of fo_value */ + fbint_t fo_constwss; /* constant version of fo_wss */ + avd_t fo_iosize; /* Size of operation */ + avd_t fo_wss; /* Flow op working set size */ char fo_targetname[128]; /* Target, for wakeup etc... */ struct flowop *fo_targets; /* List of targets matching name */ struct flowop *fo_targetnext; /* List of targets matching name */ - var_integer_t fo_iters; /* Number of iterations of op */ - var_integer_t fo_value; /* Attr */ - var_integer_t fo_sequential; /* Attr */ - var_integer_t fo_random; /* Attr */ - var_integer_t fo_stride; /* Attr */ - var_integer_t fo_backwards; /* Attr */ - var_integer_t fo_dsync; /* Attr */ - var_integer_t fo_blocking; /* Attr */ - var_integer_t fo_directio; /* Attr */ - var_integer_t fo_rotatefd; /* Attr */ + avd_t fo_iters; /* Number of iterations of op */ + avd_t fo_value; /* Attr */ + avd_t fo_sequential; /* Attr */ + avd_t fo_random; /* Attr */ + avd_t fo_stride; /* Attr */ + avd_t fo_backwards; /* Attr */ + avd_t fo_dsync; /* Attr */ + avd_t fo_blocking; /* Attr */ + avd_t fo_directio; /* Attr */ + avd_t fo_rotatefd; /* Attr */ flowstat_t fo_stats; /* Flow statistics */ pthread_cond_t fo_cv; /* Block/wakeup cv */ pthread_mutex_t fo_lock; /* Mutex around flowop */ + void *fo_private; /* Flowop private scratch pad area */ char *fo_buf; /* Per-flowop buffer */ uint64_t fo_buf_size; /* current size of buffer */ #ifdef HAVE_SYSV_SEM @@ -94,7 +98,7 @@ typedef struct flowop { #else sem_t fo_sem; /* sem_t for posix semaphores */ #endif /* HAVE_SYSV_SEM */ - var_integer_t fo_highwater; /* value of highwater paramter */ + avd_t fo_highwater; /* value of highwater paramter */ void *fo_idp; /* id, for sems etc */ hrtime_t fo_timestamp; /* for ratecontrol, etc... */ int fo_initted; /* Set to one if initialized */ @@ -125,6 +129,7 @@ typedef struct flowop { #define FLOW_TYPE_OTHER 4 /* Op is a something else */ extern flowstat_t controlstats; +extern pthread_mutex_t controlstats_lock; void flowop_init(void); flowop_t *flowop_define(threadflow_t *, char *name, flowop_t *inherit, @@ -137,6 +142,7 @@ void flowop_delete_all(flowop_t **threadlist); void flowop_endop(threadflow_t *threadflow, flowop_t *flowop, int64_t bytes); void flowop_beginop(threadflow_t *threadflow, flowop_t *flowop); void flowop_destruct_all_flows(threadflow_t *threadflow); +void flowop_printall(void); #ifdef __cplusplus } diff --git a/usr/src/cmd/filebench/common/flowop_library.c b/usr/src/cmd/filebench/common/flowop_library.c index 3124be54b9..cb54bd5c9c 100644 --- a/usr/src/cmd/filebench/common/flowop_library.c +++ b/usr/src/cmd/filebench/common/flowop_library.c @@ -37,6 +37,7 @@ #include <sys/time.h> #include <inttypes.h> #include <fcntl.h> +#include <math.h> #ifdef HAVE_UTILITY_H #include <utility.h> @@ -73,6 +74,7 @@ #include "filebench.h" #include "flowop.h" #include "fileset.h" +#include "fb_random.h" /* * These routines implement the flowops from the f language. Each @@ -135,6 +137,9 @@ static int flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop); static int flowoplib_finishoncount(threadflow_t *threadflow, flowop_t *flowop); static int flowoplib_finishonbytes(threadflow_t *threadflow, flowop_t *flowop); static int flowoplib_fsyncset(threadflow_t *threadflow, flowop_t *flowop); +static int flowoplib_testrandvar(threadflow_t *threadflow, flowop_t *flowop); +static int flowoplib_testrandvar_init(flowop_t *flowop); +static void flowoplib_testrandvar_destruct(flowop_t *flowop); typedef struct flowoplib { int fl_type; @@ -201,7 +206,10 @@ static flowoplib_t flowoplib_funcs[] = { FLOW_TYPE_IO, 0, "deletefile", flowoplib_init_generic, flowoplib_deletefile, flowoplib_destruct_generic, FLOW_TYPE_IO, FLOW_ATTR_WRITE, "writewholefile", flowoplib_init_generic, - flowoplib_writewholefile, flowoplib_destruct_generic + flowoplib_writewholefile, 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 }; /* @@ -279,10 +287,10 @@ flowoplib_fileattrs(flowop_t *flowop) { int attrs = 0; - if (*flowop->fo_directio) + if (avd_get_bool(flowop->fo_directio)) attrs |= FLOW_ATTR_DIRECTIO; - if (*flowop->fo_dsync) + if (avd_get_bool(flowop->fo_dsync)) attrs |= FLOW_ATTR_DSYNC; return (attrs); @@ -312,19 +320,22 @@ flowoplib_fileattrs(flowop_t *flowop) static int flowoplib_fdnum(threadflow_t *threadflow, flowop_t *flowop) { + fbint_t entries; + /* If the script sets the fd explicitly */ if (flowop->fo_fdnumber > 0) return (flowop->fo_fdnumber); /* If the flowop defaults to persistent fd */ - if (!integer_isset(flowop->fo_rotatefd)) + if (!avd_get_bool(flowop->fo_rotatefd)) return (flowop->fo_fdnumber); + entries = flowop->fo_fileset->fs_constentries; + /* Rotate the fd on each flowop invocation */ - if (*(flowop->fo_fileset->fs_entries) > (THREADFLOW_MAXFD / 2)) { + if (entries > (THREADFLOW_MAXFD / 2)) { filebench_log(LOG_ERROR, "Out of file descriptors in flowop %s" - " (too many files : %d", flowop->fo_name, - *(flowop->fo_fileset->fs_entries)); + " (too many files : %d", flowop->fo_name, entries); return (FILEBENCH_ERROR); } @@ -333,8 +344,7 @@ flowoplib_fdnum(threadflow_t *threadflow, flowop_t *flowop) threadflow->tf_fdrotor = THREADFLOW_MAXFD; /* One fd for every file in the set */ - if (*(flowop->fo_fileset->fs_entries) == - (THREADFLOW_MAXFD - threadflow->tf_fdrotor)) + if (entries == (THREADFLOW_MAXFD - threadflow->tf_fdrotor)) threadflow->tf_fdrotor = THREADFLOW_MAXFD; @@ -353,7 +363,7 @@ flowoplib_fdnum(threadflow_t *threadflow, flowop_t *flowop) */ static int flowoplib_filesetup(threadflow_t *threadflow, flowop_t *flowop, - vinteger_t *wssp, int *filedescp) + fbint_t *wssp, int *filedescp) { int fd = flowoplib_fdnum(threadflow, flowop); @@ -373,20 +383,18 @@ flowoplib_filesetup(threadflow_t *threadflow, flowop_t *flowop, } else { filebench_log(LOG_DEBUG_IMPL, "opened device %s/%s", - flowop->fo_fileset->fs_path, - flowop->fo_fileset->fs_name); + avd_get_str(flowop->fo_fileset->fs_path), + avd_get_str(flowop->fo_fileset->fs_name)); } } *filedescp = threadflow->tf_fd[fd]; - if (*flowop->fo_wss == 0) { + if ((*wssp = flowop->fo_constwss) == 0) { if (threadflow->tf_fse[fd]) *wssp = threadflow->tf_fse[fd]->fse_size; else - *wssp = *flowop->fo_fileset->fs_size; - } else { - *wssp = *flowop->fo_wss; + *wssp = avd_get_int(flowop->fo_fileset->fs_size); } return (FILEBENCH_OK); @@ -398,7 +406,7 @@ flowoplib_filesetup(threadflow_t *threadflow, flowop_t *flowop, */ static int flowoplib_iobufsetup(threadflow_t *threadflow, flowop_t *flowop, - caddr_t *iobufp, vinteger_t iosize) + caddr_t *iobufp, fbint_t iosize) { long memsize; size_t memoffset; @@ -409,10 +417,11 @@ flowoplib_iobufsetup(threadflow_t *threadflow, flowop_t *flowop, return (FILEBENCH_ERROR); } - if ((memsize = *threadflow->tf_memsize) != 0) { + if ((memsize = threadflow->tf_constmemsize) != 0) { /* use tf_mem for I/O with random offset */ - if (filebench_randomno(&memoffset, memsize, iosize) == -1) { + if (filebench_randomno(&memoffset, + memsize, iosize, NULL) == -1) { filebench_log(LOG_ERROR, "tf_memsize smaller than IO size for thread %s", flowop->fo_name); @@ -424,9 +433,16 @@ flowoplib_iobufsetup(threadflow_t *threadflow, flowop_t *flowop, /* use private I/O buffer */ if ((flowop->fo_buf != NULL) && (flowop->fo_buf_size < iosize)) { + /* too small, so free up and re-allocate */ free(flowop->fo_buf); flowop->fo_buf = NULL; } + + /* + * Allocate memory for the buffer. The memory is freed + * by flowop_destruct_generic() or by this routine if more + * memory is needed for the buffer. + */ if ((flowop->fo_buf == NULL) && ((flowop->fo_buf = (char *)malloc(iosize)) == NULL)) return (FILEBENCH_ERROR); @@ -444,7 +460,7 @@ flowoplib_iobufsetup(threadflow_t *threadflow, flowop_t *flowop, */ static int flowoplib_iosetup(threadflow_t *threadflow, flowop_t *flowop, - vinteger_t *wssp, caddr_t *iobufp, int *filedescp, vinteger_t iosize) + fbint_t *wssp, caddr_t *iobufp, int *filedescp, fbint_t iosize) { int ret; @@ -479,19 +495,22 @@ static int flowoplib_read(threadflow_t *threadflow, flowop_t *flowop) { caddr_t iobuf; - vinteger_t wss; + fbint_t wss; + fbint_t iosize; int filedesc; int ret; + + iosize = avd_get_int(flowop->fo_iosize); if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf, - &filedesc, *flowop->fo_iosize)) != FILEBENCH_OK) + &filedesc, iosize)) != FILEBENCH_OK) return (ret); - if (*flowop->fo_random) { + if (avd_get_bool(flowop->fo_random)) { uint64_t fileoffset; - if (filebench_randomno64(&fileoffset, wss, - *flowop->fo_iosize) == -1) { + if (filebench_randomno64(&fileoffset, + wss, iosize, NULL) == -1) { filebench_log(LOG_ERROR, "file size smaller than IO size for thread %s", flowop->fo_name); @@ -500,12 +519,12 @@ flowoplib_read(threadflow_t *threadflow, flowop_t *flowop) (void) flowop_beginop(threadflow, flowop); if ((ret = pread64(filedesc, iobuf, - *flowop->fo_iosize, (off64_t)fileoffset)) == -1) { + iosize, (off64_t)fileoffset)) == -1) { (void) flowop_endop(threadflow, flowop, 0); filebench_log(LOG_ERROR, "read file %s failed, offset %lld " "io buffer %zd: %s", - flowop->fo_fileset->fs_name, + avd_get_str(flowop->fo_fileset->fs_name), fileoffset, iobuf, strerror(errno)); flowop_endop(threadflow, flowop, 0); return (FILEBENCH_ERROR); @@ -517,11 +536,11 @@ flowoplib_read(threadflow_t *threadflow, flowop_t *flowop) } else { (void) flowop_beginop(threadflow, flowop); - if ((ret = read(filedesc, iobuf, - *flowop->fo_iosize)) == -1) { + if ((ret = read(filedesc, iobuf, iosize)) == -1) { + (void) flowop_endop(threadflow, flowop, 0); filebench_log(LOG_ERROR, "read file %s failed, io buffer %zd: %s", - flowop->fo_fileset->fs_name, + avd_get_str(flowop->fo_fileset->fs_name), iobuf, strerror(errno)); (void) flowop_endop(threadflow, flowop, 0); return (FILEBENCH_ERROR); @@ -628,21 +647,24 @@ static int flowoplib_aiowrite(threadflow_t *threadflow, flowop_t *flowop) { caddr_t iobuf; - vinteger_t wss; + fbint_t wss; + fbint_t iosize; int filedesc; int ret; + iosize = avd_get_int(flowop->fo_iosize); + if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf, - &filedesc, *flowop->fo_iosize)) != FILEBENCH_OK) + &filedesc, iosize)) != FILEBENCH_OK) return (ret); - if (*flowop->fo_random) { + if (avd_get_bool(flowop->fo_random)) { uint64_t fileoffset; struct aiocb64 *aiocb; aiolist_t *aiolist; if (filebench_randomno64(&fileoffset, - wss, *flowop->fo_iosize) == -1) { + wss, iosize, NULL) == -1) { filebench_log(LOG_ERROR, "file size smaller than IO size for thread %s", flowop->fo_name); @@ -655,13 +677,13 @@ flowoplib_aiowrite(threadflow_t *threadflow, flowop_t *flowop) aiocb->aio_fildes = filedesc; aiocb->aio_buf = iobuf; - aiocb->aio_nbytes = *flowop->fo_iosize; + aiocb->aio_nbytes = (size_t)iosize; aiocb->aio_offset = (off64_t)fileoffset; aiocb->aio_reqprio = 0; filebench_log(LOG_DEBUG_IMPL, "aio fd=%d, bytes=%lld, offset=%lld", - filedesc, *flowop->fo_iosize, fileoffset); + filedesc, iosize, fileoffset); flowop_beginop(threadflow, flowop); if (aio_write64(aiocb) < 0) { @@ -669,7 +691,7 @@ flowoplib_aiowrite(threadflow_t *threadflow, flowop_t *flowop) strerror(errno)); filebench_shutdown(1); } - flowop_endop(threadflow, flowop, *flowop->fo_iosize); + flowop_endop(threadflow, flowop, iosize); } else { return (FILEBENCH_ERROR); } @@ -915,7 +937,7 @@ flowoplib_wakeup(threadflow_t *threadflow, flowop_t *flowop) static int flowoplib_hog(threadflow_t *threadflow, flowop_t *flowop) { - uint64_t value = *flowop->fo_value; + uint64_t value = avd_get_int(flowop->fo_value); int i; filebench_log(LOG_DEBUG_IMPL, "hog enter"); @@ -936,7 +958,7 @@ flowoplib_hog(threadflow_t *threadflow, flowop_t *flowop) static int flowoplib_delay(threadflow_t *threadflow, flowop_t *flowop) { - int value = *flowop->fo_value; + int value = avd_get_int(flowop->fo_value); flowop_beginop(threadflow, flowop); (void) sleep(value); @@ -1013,8 +1035,10 @@ flowoplib_iopslimit(threadflow_t *threadflow, flowop_t *flowop) flowop->fo_initted = 1; } + (void) ipc_mutex_lock(&controlstats_lock); iops = (controlstats.fs_rcount + controlstats.fs_wcount); + (void) ipc_mutex_unlock(&controlstats_lock); /* Is this the first time around */ if (flowop->fo_tputlast == 0) { @@ -1077,7 +1101,9 @@ flowoplib_opslimit(threadflow_t *threadflow, flowop_t *flowop) flowop->fo_initted = 1; } + (void) ipc_mutex_lock(&controlstats_lock); ops = controlstats.fs_count; + (void) ipc_mutex_unlock(&controlstats_lock); /* Is this the first time around */ if (flowop->fo_tputlast == 0) { @@ -1141,8 +1167,10 @@ flowoplib_bwlimit(threadflow_t *threadflow, flowop_t *flowop) flowop->fo_initted = 1; } + (void) ipc_mutex_lock(&controlstats_lock); bytes = (controlstats.fs_rbytes + controlstats.fs_wbytes); + (void) ipc_mutex_unlock(&controlstats_lock); /* Is this the first time around */ if (flowop->fo_tputlast == 0) { @@ -1193,7 +1221,7 @@ flowoplib_bwlimit(threadflow_t *threadflow, flowop_t *flowop) /* * Stop filebench run when specified number of I/O bytes have been - * transferred. Compares controlstats.fs_bytes with *flowop->value, + * transferred. Compares controlstats.fs_bytes with flowop->value, * and if greater returns 1, stopping the run, if not, returns 0 * to continue running. */ @@ -1201,9 +1229,11 @@ static int flowoplib_finishonbytes(threadflow_t *threadflow, flowop_t *flowop) { uint64_t b; - uint64_t bytes = *flowop->fo_value; + uint64_t bytes = flowop->fo_constvalue; /* use constant value */ + (void) ipc_mutex_lock(&controlstats_lock); b = controlstats.fs_bytes; + (void) ipc_mutex_unlock(&controlstats_lock); flowop_beginop(threadflow, flowop); if (b > bytes) { @@ -1225,9 +1255,11 @@ static int flowoplib_finishoncount(threadflow_t *threadflow, flowop_t *flowop) { uint64_t ops; - uint64_t count = *flowop->fo_value; + uint64_t count = flowop->fo_constvalue; /* use constant value */ + (void) ipc_mutex_lock(&controlstats_lock); ops = controlstats.fs_count; + (void) ipc_mutex_unlock(&controlstats_lock); flowop_beginop(threadflow, flowop); if (ops >= count) { @@ -1286,12 +1318,12 @@ flowoplib_semblock_init(flowop_t *flowop) } if ((highwater = flowop->fo_semid_hw) == 0) - highwater = *flowop->fo_value; + highwater = flowop->fo_constvalue; /* use constant value */ filebench_log(LOG_DEBUG_IMPL, "setting highwater to : %d", highwater); sbuf[0].sem_num = (short)highwater; - sbuf[0].sem_op = *flowop->fo_highwater; + sbuf[0].sem_op = avd_get_int(flowop->fo_highwater); sbuf[0].sem_flg = 0; if ((semop(semid, &sbuf[0], 1) == -1) && errno) { filebench_log(LOG_ERROR, "semblock init post failed: %s (%d," @@ -1306,7 +1338,7 @@ flowoplib_semblock_init(flowop_t *flowop) sem_init(&flowop->fo_sem, 1, 0); #endif /* HAVE_SYSV_SEM */ - if (!(*flowop->fo_blocking)) + if (!(avd_get_bool(flowop->fo_blocking))) (void) ipc_mutex_unlock(&flowop->fo_lock); return (FILEBENCH_OK); @@ -1340,7 +1372,7 @@ flowoplib_semblock(threadflow_t *threadflow, flowop_t *flowop) #ifdef HAVE_SYSV_SEM struct sembuf sbuf[2]; - int value = *flowop->fo_value; + int value = avd_get_int(flowop->fo_value); int semid; struct timespec timeout; @@ -1366,7 +1398,7 @@ flowoplib_semblock(threadflow_t *threadflow, flowop_t *flowop) timeout.tv_sec = 600; timeout.tv_nsec = 0; - if (*flowop->fo_blocking) + if (avd_get_bool(flowop->fo_blocking)) (void) ipc_mutex_unlock(&flowop->fo_lock); flowop_beginop(threadflow, flowop); @@ -1379,13 +1411,13 @@ flowoplib_semblock(threadflow_t *threadflow, flowop_t *flowop) (void) semop(semid, &sbuf[1], 1); #endif /* HAVE_SEMTIMEDOP */ - if (*flowop->fo_blocking) + if (avd_get_bool(flowop->fo_blocking)) (void) ipc_mutex_lock(&flowop->fo_lock); flowop_endop(threadflow, flowop, 0); #else - int value = *flowop->fo_value; + int value = avd_get_int(flowop->fo_value); int i; filebench_log(LOG_DEBUG_IMPL, @@ -1471,8 +1503,8 @@ flowoplib_sempost(threadflow_t *threadflow, flowop_t *flowop) #else int i; #endif /* HAVE_SYSV_SEM */ - int value = *flowop->fo_value; struct timespec timeout; + int value = avd_get_int(flowop->fo_value); if (target->fo_instance == FLOW_MASTER) { target = target->fo_targetnext; @@ -1505,7 +1537,7 @@ flowoplib_sempost(threadflow_t *threadflow, flowop_t *flowop) timeout.tv_sec = 600; timeout.tv_nsec = 0; - if (*flowop->fo_blocking) + if (avd_get_bool(flowop->fo_blocking)) blocking = 1; else blocking = 0; @@ -1605,13 +1637,21 @@ static int flowoplib_openfile_common(threadflow_t *threadflow, flowop_t *flowop, int fd) { filesetentry_t *file; + char *fileset_name; int tid = 0; + if ((fileset_name = + avd_get_str(flowop->fo_fileset->fs_name)) == NULL) { + filebench_log(LOG_ERROR, + "flowop %s: fileset has no name", flowop->fo_name); + return (FILEBENCH_ERROR); + } + /* * If the flowop doesn't default to persistent fd * then get unique thread ID for use by fileset_pick */ - if (integer_isset(flowop->fo_rotatefd)) + if (avd_get_bool(flowop->fo_rotatefd)) tid = threadflow->tf_utid; if (threadflow->tf_fd[fd] != 0) { @@ -1631,11 +1671,12 @@ flowoplib_openfile_common(threadflow_t *threadflow, flowop_t *flowop, int fd) int open_attrs = 0; char name[MAXPATHLEN]; - (void) strcpy(name, *flowop->fo_fileset->fs_path); + (void) strcpy(name, + avd_get_str(flowop->fo_fileset->fs_path)); (void) strcat(name, "/"); - (void) strcat(name, flowop->fo_fileset->fs_name); + (void) strcat(name, fileset_name); - if (*flowop->fo_dsync) { + if (avd_get_bool(flowop->fo_dsync)) { #ifdef sun open_attrs |= O_DSYNC; #else @@ -1671,8 +1712,7 @@ flowoplib_openfile_common(threadflow_t *threadflow, flowop_t *flowop, int fd) FILESET_PICKEXISTS, tid)) == NULL) { filebench_log(LOG_DEBUG_SCRIPT, "flowop %s failed to pick file from %s on fd %d", - flowop->fo_name, - flowop->fo_fileset->fs_name, fd); + flowop->fo_name, fileset_name, fd); return (FILEBENCH_NORSC); } @@ -1684,8 +1724,8 @@ flowoplib_openfile_common(threadflow_t *threadflow, flowop_t *flowop, int fd) flowop_endop(threadflow, flowop, 0); if (threadflow->tf_fd[fd] < 0) { - filebench_log(LOG_ERROR, "failed to open file %s", - flowop->fo_name); + filebench_log(LOG_ERROR, "flowop %s failed to open file %s", + flowop->fo_name, file->fse_path); return (FILEBENCH_ERROR); } @@ -1740,7 +1780,8 @@ flowoplib_createfile(threadflow_t *threadflow, flowop_t *flowop) FILESET_PICKNOEXIST, 0)) == NULL) { filebench_log(LOG_DEBUG_SCRIPT, "flowop %s failed to pick file from fileset %s", - flowop->fo_name, flowop->fo_fileset->fs_name); + flowop->fo_name, + avd_get_str(flowop->fo_fileset->fs_name)); return (FILEBENCH_NORSC); } @@ -1804,9 +1845,9 @@ flowoplib_deletefile(threadflow_t *threadflow, flowop_t *flowop) } *path = 0; - (void) strcpy(path, *fileset->fs_path); + (void) strcpy(path, avd_get_str(fileset->fs_path)); (void) strcat(path, "/"); - (void) strcat(path, fileset->fs_name); + (void) strcat(path, avd_get_str(fileset->fs_name)); pathtmp = fileset_resolvepath(file); (void) strcat(path, pathtmp); free(pathtmp); @@ -1962,9 +2003,9 @@ flowoplib_statfile(threadflow_t *threadflow, flowop_t *flowop) } *path = 0; - (void) strcpy(path, *fileset->fs_path); + (void) strcpy(path, avd_get_str(fileset->fs_path)); (void) strcat(path, "/"); - (void) strcat(path, fileset->fs_name); + (void) strcat(path, avd_get_str(fileset->fs_name)); pathtmp = fileset_resolvepath(file); (void) strcat(path, pathtmp); free(pathtmp); @@ -2003,9 +2044,10 @@ flowoplib_readwholefile(threadflow_t *threadflow, flowop_t *flowop) off64_t bytes = 0; int fd = flowop->fo_fdnumber; int filedesc; - int ret; uint64_t wss; - vinteger_t iosize = *flowop->fo_iosize; + fbint_t iosize; + int ret; + char zerordbuf; /* get the file to use */ if ((ret = flowoplib_filesetup(threadflow, flowop, &wss, @@ -2013,11 +2055,23 @@ flowoplib_readwholefile(threadflow_t *threadflow, flowop_t *flowop) return (ret); /* an I/O size of zero means read entire working set with one I/O */ - if (iosize == 0) + if ((iosize = avd_get_int(flowop->fo_iosize)) == 0) iosize = wss; - if (flowoplib_iobufsetup(threadflow, flowop, &iobuf, iosize) != 0) - return (FILEBENCH_ERROR); + /* + * The file may actually be 0 bytes long, in which case skip + * the buffer set up call (which would fail) and substitute + * a small buffer, which won't really be used. + */ + if (iosize == 0) { + iobuf = (caddr_t)&zerordbuf; + filebench_log(LOG_DEBUG_SCRIPT, + "flowop %s read zero length file", flowop->fo_name); + } else { + if (flowoplib_iobufsetup(threadflow, flowop, &iobuf, + iosize) != 0) + return (FILEBENCH_ERROR); + } /* Measure time to read bytes */ flowop_beginop(threadflow, flowop); @@ -2056,19 +2110,21 @@ static int flowoplib_write(threadflow_t *threadflow, flowop_t *flowop) { caddr_t iobuf; - vinteger_t wss; + fbint_t wss; + fbint_t iosize; int filedesc; int ret; + iosize = avd_get_int(flowop->fo_iosize); if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf, - &filedesc, *flowop->fo_iosize)) != FILEBENCH_OK) + &filedesc, iosize)) != FILEBENCH_OK) return (ret); - if (*flowop->fo_random) { + if (avd_get_bool(flowop->fo_random)) { uint64_t fileoffset; if (filebench_randomno64(&fileoffset, - wss, *flowop->fo_iosize) == -1) { + wss, iosize, NULL) == -1) { filebench_log(LOG_ERROR, "file size smaller than IO size for thread %s", flowop->fo_name); @@ -2076,25 +2132,25 @@ flowoplib_write(threadflow_t *threadflow, flowop_t *flowop) } flowop_beginop(threadflow, flowop); if (pwrite64(filedesc, iobuf, - *flowop->fo_iosize, (off64_t)fileoffset) == -1) { + iosize, (off64_t)fileoffset) == -1) { filebench_log(LOG_ERROR, "write failed, " "offset %lld io buffer %zd: %s", fileoffset, iobuf, strerror(errno)); flowop_endop(threadflow, flowop, 0); return (FILEBENCH_ERROR); } - flowop_endop(threadflow, flowop, *flowop->fo_iosize); + flowop_endop(threadflow, flowop, iosize); } else { flowop_beginop(threadflow, flowop); if (write(filedesc, iobuf, - *flowop->fo_iosize) == -1) { + iosize) == -1) { filebench_log(LOG_ERROR, "write failed, io buffer %zd: %s", iobuf, strerror(errno)); flowop_endop(threadflow, flowop, 0); return (FILEBENCH_ERROR); } - flowop_endop(threadflow, flowop, *flowop->fo_iosize); + flowop_endop(threadflow, flowop, iosize); } return (FILEBENCH_OK); @@ -2117,22 +2173,35 @@ flowoplib_writewholefile(threadflow_t *threadflow, flowop_t *flowop) off64_t seek; off64_t bytes = 0; uint64_t wss; + fbint_t iosize; int filedesc; int srcfd = flowop->fo_srcfdnumber; int ret; - vinteger_t iosize = *flowop->fo_iosize; + char zerowrtbuf; /* get the file to use */ if ((ret = flowoplib_filesetup(threadflow, flowop, &wss, &filedesc)) != FILEBENCH_OK) return (ret); - /* an I/O size of zero means read entire working set with one I/O */ - if (iosize == 0) + /* an I/O size of zero means write entire working set with one I/O */ + if ((iosize = avd_get_int(flowop->fo_iosize)) == 0) iosize = wss; - if (flowoplib_iobufsetup(threadflow, flowop, &iobuf, iosize) != 0) - return (FILEBENCH_ERROR); + /* + * The file may actually be 0 bytes long, in which case skip + * the buffer set up call (which would fail) and substitute + * a small buffer, which won't really be used. + */ + if (iosize == 0) { + iobuf = (caddr_t)&zerowrtbuf; + filebench_log(LOG_DEBUG_SCRIPT, + "flowop %s wrote zero length file", flowop->fo_name); + } else { + if (flowoplib_iobufsetup(threadflow, flowop, &iobuf, + iosize) != 0) + return (FILEBENCH_ERROR); + } file = threadflow->tf_fse[srcfd]; if ((srcfd != 0) && (file == NULL)) { @@ -2187,10 +2256,11 @@ flowoplib_appendfile(threadflow_t *threadflow, flowop_t *flowop) { caddr_t iobuf; int filedesc; - vinteger_t wss; - vinteger_t iosize = *flowop->fo_iosize; + fbint_t wss; + fbint_t iosize; int ret; + iosize = avd_get_int(flowop->fo_iosize); if ((ret = flowoplib_iosetup(threadflow, flowop, &wss, &iobuf, &filedesc, iosize)) != FILEBENCH_OK) return (ret); @@ -2205,10 +2275,10 @@ flowoplib_appendfile(threadflow_t *threadflow, flowop_t *flowop) filebench_log(LOG_ERROR, "Failed to write %d bytes on fd %d: %s", iosize, filedesc, strerror(errno)); - flowop_endop(threadflow, flowop, 0); + flowop_endop(threadflow, flowop, ret); return (FILEBENCH_ERROR); } - flowop_endop(threadflow, flowop, iosize); + flowop_endop(threadflow, flowop, ret); return (FILEBENCH_OK); } @@ -2235,10 +2305,17 @@ flowoplib_appendfilerand(threadflow_t *threadflow, flowop_t *flowop) caddr_t iobuf; uint64_t appendsize; int filedesc; - vinteger_t wss; - int ret; + fbint_t wss; + fbint_t iosize; + int ret = 0; + + if ((iosize = avd_get_int(flowop->fo_iosize)) == 0) { + filebench_log(LOG_ERROR, "zero iosize for flowop %s", + flowop->fo_name); + return (FILEBENCH_ERROR); + } - if (filebench_randomno64(&appendsize, *flowop->fo_iosize, 1LL) != 0) + if (filebench_randomno64(&appendsize, iosize, 1LL, NULL) != 0) return (FILEBENCH_ERROR); /* skip if attempting zero length append */ @@ -2272,6 +2349,92 @@ flowoplib_appendfilerand(threadflow_t *threadflow, flowop_t *flowop) return (FILEBENCH_OK); } +typedef struct testrandvar_priv { + uint64_t sample_count; + double val_sum; + double sqr_sum; +} testrandvar_priv_t; + +/* + * flowop to calculate various statistics from the number stream + * produced by a random variable. This allows verification that the + * random distribution used to define the random variable is producing + * the expected distribution of random numbers. + */ +/* ARGSUSED */ +static int +flowoplib_testrandvar(threadflow_t *threadflow, flowop_t *flowop) +{ + testrandvar_priv_t *mystats; + double value; + + if ((mystats = (testrandvar_priv_t *)flowop->fo_private) == NULL) { + filebench_log(LOG_ERROR, "testrandvar not initialized\n"); + filebench_shutdown(1); + return (-1); + } + + value = avd_get_dbl(flowop->fo_value); + + mystats->sample_count++; + mystats->val_sum += value; + mystats->sqr_sum += (value * value); + + return (0); +} + +/* + * Initialize the private data area used to accumulate the statistics + */ +static int +flowoplib_testrandvar_init(flowop_t *flowop) +{ + testrandvar_priv_t *mystats; + + if ((mystats = (testrandvar_priv_t *) + malloc(sizeof (testrandvar_priv_t))) == NULL) { + filebench_log(LOG_ERROR, "could not initialize testrandvar"); + filebench_shutdown(1); + return (-1); + } + + mystats->sample_count = 0; + mystats->val_sum = 0; + mystats->sqr_sum = 0; + flowop->fo_private = (void *)mystats; + + (void) ipc_mutex_unlock(&flowop->fo_lock); + return (0); +} + +/* + * Print out the accumulated statistics, and free the private storage + */ +static void +flowoplib_testrandvar_destruct(flowop_t *flowop) +{ + testrandvar_priv_t *mystats; + double mean, std_dev, dbl_count; + + (void) ipc_mutex_lock(&flowop->fo_lock); + if ((mystats = (testrandvar_priv_t *) + flowop->fo_private) == NULL) { + (void) ipc_mutex_unlock(&flowop->fo_lock); + return; + } + + flowop->fo_private = NULL; + (void) ipc_mutex_unlock(&flowop->fo_lock); + + dbl_count = (double)mystats->sample_count; + mean = mystats->val_sum / dbl_count; + std_dev = sqrt((mystats->sqr_sum / dbl_count) - (mean * mean)) / mean; + + filebench_log(LOG_VERBOSE, + "testrandvar: ops = %lld, mean = %8.2lf, stddev = %8.2lf", + mystats->sample_count, mean, std_dev); + free(mystats); +} /* * Prints usage information for flowop operations. diff --git a/usr/src/cmd/filebench/common/gamma_dist.c b/usr/src/cmd/filebench/common/gamma_dist.c index 06552cbb1e..3ba0a74e8d 100644 --- a/usr/src/cmd/filebench/common/gamma_dist.c +++ b/usr/src/cmd/filebench/common/gamma_dist.c @@ -19,7 +19,7 @@ * 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. */ @@ -34,15 +34,20 @@ * From Knuth Volume 2, 3rd edition, pages 586 - 587. */ static double -gamma_dist_knuth_algG(double a) +gamma_dist_knuth_algG(double a, double (*src)(unsigned short *), + unsigned short *xi) { double p, U, V, X, q; p = M_E/(a + M_E); G2: - U = drand48(); + /* get a random number U */ + U = (*src)(xi); + do { - V = drand48(); + /* get a random number V */ + V = (*src)(xi); + } while (V == 0); if (U < p) { @@ -57,7 +62,10 @@ G2: /* * X now has density g, and q = f(X)/cg(X) */ - U = drand48(); + + /* get a random number U */ + U = (*src)(xi); + if (U >= q) goto G2; return (X); @@ -69,31 +77,66 @@ G2: * From Knuth Volume 2, 3rd edition, page 134. */ static double -gamma_dist_knuth_algA(double a) +gamma_dist_knuth_algA(double a, double (*src)(unsigned short *), + unsigned short *xi) { double U, Y, X, V; A1: - U = drand48(); + /* get a random number U */ + U = (*src)(xi); + Y = tan(M_PI*U); X = (sqrt((2*a) - 1) * Y) + a - 1; if (X <= 0) goto A1; - V = drand48(); - /* V > (1 + Y^2) * exp((a - 1) * log(X / (a - 1)) - sqrt(2a - 1) * Y) */ + /* get a random number V */ + V = (*src)(xi); + if (V > ((1 + (Y*Y)) * exp((a-1) * log(X/(a-1)) - sqrt(2*a -1) * Y))) goto A1; return (X); } +/* + * fetch a uniformly distributed random number using the drand48 generator + */ +/* ARGSUSED */ +static double +default_src(unsigned short *xi) +{ + return (drand48()); +} + +/* + * Sample the gamma distributed random variable with gamma 'a' and + * result mulitplier 'b', which is usually mean/gamma. Uses the default + * drand48 random number generator as input + */ double gamma_dist_knuth(double a, double b) { if (a <= 1.0) - return (b * gamma_dist_knuth_algG(a)); + return (b * gamma_dist_knuth_algG(a, default_src, NULL)); + else + return (b * gamma_dist_knuth_algA(a, default_src, NULL)); +} + +/* + * Sample the gamma distributed random variable with gamma 'a' and + * multiplier 'b', which is mean / gamma adjusted for the specified + * minimum value. The suppled random number source function is + * used to optain the uniformly distributed random numbers. + */ +double +gamma_dist_knuth_src(double a, double b, + double (*src)(unsigned short *), unsigned short *xi) +{ + if (a <= 1.0) + return (b * gamma_dist_knuth_algG(a, src, xi)); else - return (b * gamma_dist_knuth_algA(a)); + return (b * gamma_dist_knuth_algA(a, src, xi)); } diff --git a/usr/src/cmd/filebench/common/gamma_dist.h b/usr/src/cmd/filebench/common/gamma_dist.h index 2773b626af..ff9375fe75 100644 --- a/usr/src/cmd/filebench/common/gamma_dist.h +++ b/usr/src/cmd/filebench/common/gamma_dist.h @@ -19,7 +19,7 @@ * 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. */ @@ -33,6 +33,8 @@ extern "C" { #endif double gamma_dist_knuth(double a, double b); +double gamma_dist_knuth_src(double a, double b, + double (*src)(unsigned short *), unsigned short *xi); #ifdef __cplusplus } diff --git a/usr/src/cmd/filebench/common/ipc.c b/usr/src/cmd/filebench/common/ipc.c index 1311b4ab51..596a47ea87 100644 --- a/usr/src/cmd/filebench/common/ipc.c +++ b/usr/src/cmd/filebench/common/ipc.c @@ -410,14 +410,14 @@ ipc_attach(caddr_t shmaddr) } static int filebench_sizes[] = { - FILEBENCH_NPROCFLOWS, - FILEBENCH_NTHREADFLOWS, - FILEBENCH_NFLOWOPS, - FILEBENCH_NVARS, - FILEBENCH_NVARS, - FILEBENCH_NVARS, - FILEBENCH_NFILESETS, - FILEBENCH_NFILESETENTRIES}; + FILEBENCH_NPROCFLOWS, /* number of procflows */ + FILEBENCH_NTHREADFLOWS, /* number of threadflows */ + FILEBENCH_NFLOWOPS, /* number of flowops */ + (FILEBENCH_NVARS * 2), /* number of attribute value dscrs */ + FILEBENCH_NVARS, /* number of variables */ + FILEBENCH_NFILESETS, /* number of filesets */ + FILEBENCH_NFILESETENTRIES, /* number of fileset entries */ + FILEBENCH_NRANDDISTS}; /* number of random distributions */ /* * Allocates filebench objects from pre allocated region of @@ -480,21 +480,23 @@ ipc_malloc(int type) (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); return ((char *)&filebench_shm->flowop[i]); - case FILEBENCH_INTEGER: - filebench_shm->integer_ptrs[i] = NULL; + case FILEBENCH_AVD: + filebench_shm->shm_avd_ptrs[i].avd_type = AVD_INVALID; + filebench_shm->shm_avd_ptrs[i].avd_val.varptr = NULL; (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); - return ((char *)&filebench_shm->integer_ptrs[i]); - - case FILEBENCH_STRING: - filebench_shm->string_ptrs[i] = NULL; - (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); - return ((char *)&filebench_shm->string_ptrs[i]); + return ((char *)&filebench_shm->shm_avd_ptrs[i]); case FILEBENCH_VARIABLE: (void) memset((char *)&filebench_shm->var[i], 0, sizeof (var_t)); (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); return ((char *)&filebench_shm->var[i]); + + case FILEBENCH_RANDDIST: + (void) memset((char *)&filebench_shm->shm_randdist[i], 0, + sizeof (randdist_t)); + (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); + return ((char *)&filebench_shm->shm_randdist[i]); } filebench_log(LOG_ERROR, "Attempt to ipc_malloc unknown type (%d)!", @@ -548,20 +550,20 @@ ipc_free(int type, char *addr) size = sizeof (flowop_t); break; - case FILEBENCH_INTEGER: - base = (caddr_t)&filebench_shm->integer_ptrs[0]; - size = sizeof (caddr_t); - break; - - case FILEBENCH_STRING: - base = (caddr_t)&filebench_shm->string_ptrs[0]; - size = sizeof (caddr_t); + case FILEBENCH_AVD: + base = (caddr_t)&filebench_shm->shm_avd_ptrs[0]; + size = sizeof (avd_t); break; case FILEBENCH_VARIABLE: base = (caddr_t)&filebench_shm->var[0]; size = sizeof (var_t); break; + + case FILEBENCH_RANDDIST: + base = (caddr_t)&filebench_shm->shm_randdist[0]; + size = sizeof (randdist_t); + break; } offset = ((size_t)addr - (size_t)base); diff --git a/usr/src/cmd/filebench/common/ipc.h b/usr/src/cmd/filebench/common/ipc.h index 8eed540c66..0596d177df 100644 --- a/usr/src/cmd/filebench/common/ipc.h +++ b/usr/src/cmd/filebench/common/ipc.h @@ -35,6 +35,7 @@ #include "threadflow.h" #include "fileset.h" #include "flowop.h" +#include "fb_random.h" #include "filebench.h" #ifdef __cplusplus @@ -50,21 +51,22 @@ extern "C" { #define FILEBENCH_NFILESETS FILEBENCH_MEMSIZE #define FILEBENCH_NFILESETENTRIES (1024 * 1024) #define FILEBENCH_NPROCFLOWS FILEBENCH_MEMSIZE -#define FILEBENCH_NTHREADFLOWS 64 * FILEBENCH_MEMSIZE -#define FILEBENCH_NFLOWOPS 64 * FILEBENCH_MEMSIZE +#define FILEBENCH_NTHREADFLOWS (64 * FILEBENCH_MEMSIZE) +#define FILEBENCH_NFLOWOPS (64 * FILEBENCH_MEMSIZE) #define FILEBENCH_NVARS FILEBENCH_MEMSIZE -#define FILEBENCH_FILESETPATHMEMORY FILEBENCH_NFILESETENTRIES*FSE_MAXPATHLEN -#define FILEBENCH_STRINGMEMORY FILEBENCH_NVARS * 128 +#define FILEBENCH_NRANDDISTS (FILEBENCH_MEMSIZE/4) +#define FILEBENCH_FILESETPATHMEMORY (FILEBENCH_NFILESETENTRIES*FSE_MAXPATHLEN) +#define FILEBENCH_STRINGMEMORY (FILEBENCH_NVARS * 128) #define FILEBENCH_MAXBITMAP FILEBENCH_NFILESETENTRIES #define FILEBENCH_PROCFLOW 0 #define FILEBENCH_THREADFLOW 1 #define FILEBENCH_FLOWOP 2 -#define FILEBENCH_INTEGER 3 -#define FILEBENCH_STRING 4 -#define FILEBENCH_VARIABLE 5 -#define FILEBENCH_FILESET 6 -#define FILEBENCH_FILESETENTRY 7 +#define FILEBENCH_AVD 3 +#define FILEBENCH_VARIABLE 4 +#define FILEBENCH_FILESET 5 +#define FILEBENCH_FILESETENTRY 6 +#define FILEBENCH_RANDDIST 7 #define FILEBENCH_TYPES 8 #define FILEBENCH_NSEMS 128 @@ -95,6 +97,7 @@ typedef struct filebench_shm { procflow_t *proclist; var_t *var_list; var_t *var_dyn_list; + randdist_t *shm_rand_list; int debug_level; hrtime_t epoch; hrtime_t starttime; @@ -130,8 +133,8 @@ typedef struct filebench_shm { threadflow_t threadflow[FILEBENCH_NTHREADFLOWS]; flowop_t flowop[FILEBENCH_NFLOWOPS]; var_t var[FILEBENCH_NVARS]; - vinteger_t integer_ptrs[FILEBENCH_NVARS]; - char *string_ptrs[FILEBENCH_NVARS]; + randdist_t shm_randdist[FILEBENCH_NRANDDISTS]; + struct avd shm_avd_ptrs[FILEBENCH_NVARS * 2]; char strings[FILEBENCH_STRINGMEMORY]; char semids[FILEBENCH_NSEMS]; int bitmap[FILEBENCH_TYPES][FILEBENCH_MAXBITMAP]; diff --git a/usr/src/cmd/filebench/common/misc.c b/usr/src/cmd/filebench/common/misc.c index e611e1e468..820f41c2e9 100644 --- a/usr/src/cmd/filebench/common/misc.c +++ b/usr/src/cmd/filebench/common/misc.c @@ -39,9 +39,8 @@ /* * Routines to access high resolution system time, initialize and - * shutdown filebench, obtain system generated random numbers from - * "urandom", log filebench run progress and errors, and access system - * information strings. + * shutdown filebench, log filebench run progress and errors, and + * access system information strings. */ @@ -115,7 +114,6 @@ parse_cpu_hz(void) break; } } - printf("CPU Mhz %9.6f, sysconf:%ld\n", hertz, sysconf(_SC_CLK_TCK)); hz = hertz * 1000000; return (hz); @@ -142,8 +140,6 @@ gethrtime(void) } #endif -static int urandomfd; - /* * Main filebench initialization. Opens the random number * "device" file or shuts down the run if one is not found. @@ -153,12 +149,8 @@ static int urandomfd; void filebench_init(void) { - /* open the "urandom" random number device file */ - if ((urandomfd = open("/dev/urandom", O_RDONLY)) < 0) { - filebench_log(LOG_ERROR, "open /dev/urandom failed: %s", - strerror(errno)); - filebench_shutdown(1); - } + fb_random_init(); + #if defined(USE_RDTSC) && (LINUX_PORT) cpu_hz = parse_cpu_hz(); if (cpu_hz <= 0) { @@ -170,93 +162,6 @@ filebench_init(void) } -/* - * Reads a 64 bit random number from the urandom "file". - * Shuts down the run if the read fails. Otherwise returns - * the random number after rounding it off by "round". - * Returns 0 on success, -1 on failure. - */ -int -filebench_randomno64(uint64_t *randp, uint64_t max, uint64_t round) -{ - uint64_t random; - - /* check for round value too large */ - if (max <= round) { - *randp = 0; - - /* if it just fits, its ok, otherwise error */ - if (max == round) - return (0); - else - return (-1); - } - - if (read(urandomfd, &random, - sizeof (uint64_t)) != sizeof (uint64_t)) { - filebench_log(LOG_ERROR, "read /dev/urandom failed: %s", - strerror(errno)); - filebench_shutdown(1); - } - - /* clip with max and optionally round */ - max -= round; - random = random / (FILEBENCH_RANDMAX64 / max); - if (round) { - random = random / round; - random *= round; - } - if (random > max) - random = max; - - *randp = random; - return (0); -} - - -/* - * Reads a 32 bit random number from the urandom "file". - * Shuts down the run if the read fails. Otherwise returns - * the random number after rounding it off by "round". - * Returns 0 on success, -1 on failure. - */ -int -filebench_randomno32(uint32_t *randp, uint32_t max, uint32_t round) -{ - uint32_t random; - - /* check for round value too large */ - if (max <= round) { - *randp = 0; - - /* if it just fits, its ok, otherwise error */ - if (max == round) - return (0); - else - return (-1); - } - - if (read(urandomfd, &random, - sizeof (uint32_t)) != sizeof (uint32_t)) { - filebench_log(LOG_ERROR, "read /dev/urandom failed: %s", - strerror(errno)); - filebench_shutdown(1); - } - - /* clip with max and optionally round */ - max -= round; - random = random / (FILEBENCH_RANDMAX32 / max); - if (round) { - random = random / round; - random *= round; - } - if (random > max) - random = max; - - *randp = random; - return (0); -} - extern int lex_lineno; /* @@ -430,7 +335,7 @@ filebench_shutdown(int error) { * Put the hostname in ${hostname}. The system supplied * host name string is copied into an allocated string and * the pointer to the string is placed in the supplied - * variable "var". If var->var_string already points to + * variable "var". If var->var_val.string already points to * a string, the string is freed. The routine always * returns zero (0). */ @@ -438,26 +343,36 @@ var_t * host_var(var_t *var) { char hoststr[128]; + char *strptr; (void) gethostname(hoststr, 128); - if (var->var_string) - free(var->var_string); - var->var_string = fb_stralloc(hoststr); + if (VAR_HAS_STRING(var) && var->var_val.string) + free(var->var_val.string); + + if ((strptr = fb_stralloc(hoststr)) == NULL) { + filebench_log(LOG_ERROR, + "unable to allocate string for host name"); + return (NULL); + } + + VAR_SET_STR(var, strptr); return (0); } /* * Put the date string in ${date}. The system supplied date is * copied into an allocated string and the pointer to the string - * is placed in the supplied var_t's var_string. If - * var->var_string already points to a string, the string - * is freed. The routine always returns a pointer to the - * supplied var_t. + * is placed in the supplied var_t's var_val.string. If + * var->var_val.string already points to a string, the string + * is freed. The routine returns a pointer to the supplied var_t, + * unless it is unable to allocate string for the date, in which + * case it returns NULL. */ var_t * date_var(var_t *var) { char datestr[128]; + char *strptr; #ifdef HAVE_CFTIME time_t t = time(NULL); #else @@ -470,9 +385,16 @@ date_var(var_t *var) (void) strftime(datestr, sizeof (datestr), "%y%m%d%H %M", &t); #endif - if (var->var_string) - free(var->var_string); - var->var_string = fb_stralloc(datestr); + if (VAR_HAS_STRING(var) && var->var_val.string) + free(var->var_val.string); + + if ((strptr = fb_stralloc(datestr)) == NULL) { + filebench_log(LOG_ERROR, + "unable to allocate string for date"); + return (NULL); + } + + VAR_SET_STR(var, strptr); return (var); } @@ -483,15 +405,17 @@ extern char *fscriptname; * Put the script name in ${script}. The path name of the script * used with this filebench run trimmed of the trailing ".f" and * all leading subdirectories. The remaining script name is - * copied into the var_string field of the supplied variable - * "var". The routine always returns a pointer to the supplied - * var_t. + * copied into the var_val.string field of the supplied variable + * "var". The routine returns a pointer to the supplied var_t, + * unless it is unable to allocate string space, in which case it + * returns NULL. */ var_t * script_var(var_t *var) { char *scriptstr; char *f = fb_stralloc(fscriptname); + char *strptr; /* Trim the .f suffix */ for (scriptstr = f + strlen(f) - 1; scriptstr != f; scriptstr--) { @@ -501,7 +425,14 @@ script_var(var_t *var) } } - var->var_string = fb_stralloc(basename(f)); + if ((strptr = fb_stralloc(basename(f))) == NULL) { + filebench_log(LOG_ERROR, + "unable to allocate string for script name"); + free(f); + return (NULL); + } + + VAR_SET_STR(var, strptr); free(f); return (var); diff --git a/usr/src/cmd/filebench/common/parser_gram.y b/usr/src/cmd/filebench/common/parser_gram.y index 4a8a80de57..4f159f436a 100644 --- a/usr/src/cmd/filebench/common/parser_gram.y +++ b/usr/src/cmd/filebench/common/parser_gram.y @@ -1,4 +1,3 @@ - /* * CDDL HEADER START * @@ -92,16 +91,20 @@ static attr_t *get_attr_bool(cmd_t *cmd, int64_t name); static var_t *alloc_var(void); static var_t *get_var(cmd_t *cmd, int64_t name); static list_t *alloc_list(); +static probtabent_t *alloc_probtabent(void); /* Info Commands */ static void parser_list(cmd_t *); +static void parser_flowop_list(cmd_t *); /* Define Commands */ static void parser_proc_define(cmd_t *); static void parser_thread_define(cmd_t *, procflow_t *, int instances); -static void parser_flowop_define(cmd_t *, threadflow_t *); +static void parser_flowop_define(cmd_t *, threadflow_t *, flowop_t **, int); static void parser_file_define(cmd_t *); static void parser_fileset_define(cmd_t *); +static void parser_randvar_define(cmd_t *); +static void parser_randvar_set(cmd_t *); /* Create Commands */ static void parser_proc_create(cmd_t *); @@ -109,6 +112,10 @@ static void parser_thread_create(cmd_t *); static void parser_flowop_create(cmd_t *); static void parser_fileset_create(cmd_t *); +/* set commands */ +static void parser_set_integer(char *, fbint_t); +static void parser_set_var(char *, char *); + /* Shutdown Commands */ static void parser_proc_shutdown(cmd_t *); static void parser_filebench_shutdown(cmd_t *cmd); @@ -139,13 +146,15 @@ static void parser_abort(int arg); %} %union { - int64_t ival; - uchar_t bval; - char * sval; - fs_u val; - cmd_t *cmd; - attr_t *attr; - list_t *list; + int64_t ival; + uchar_t bval; + char * sval; + fs_u val; + avd_t avd; + cmd_t *cmd; + attr_t *attr; + list_t *list; + probtabent_t *rndtb; } %start commands @@ -155,9 +164,10 @@ static void parser_abort(int arg); %token FSC_SYSTEM FSC_FLOWOP FSC_EVENTGEN FSC_ECHO FSC_LOAD FSC_RUN %token FSC_USAGE FSC_HELP FSC_VARS %token FSV_STRING FSV_VAL_INT FSV_VAL_BOOLEAN FSV_VARIABLE FSV_WHITESTRING +%token FSV_RANDUNI FSV_RANDTAB FSV_RANDVAR FSV_URAND FSV_RAND48 %token FST_INT FST_BOOLEAN %token FSE_FILE FSE_PROC FSE_THREAD FSE_CLEAR FSE_ALL FSE_SNAP FSE_DUMP -%token FSE_DIRECTORY FSE_COMMAND FSE_FILESET FSE_XMLDUMP FSE_MODE +%token FSE_DIRECTORY FSE_COMMAND FSE_FILESET FSE_XMLDUMP FSE_RAND FSE_MODE %token FSK_SEPLST FSK_OPENLST FSK_CLOSELST FSK_ASSIGN FSK_IN FSK_QUOTE %token FSK_DIRSEPLST %token FSA_SIZE FSA_PREALLOC FSA_PARALLOC FSA_PATH FSA_REUSE @@ -165,14 +175,18 @@ static void parser_abort(int arg); %token FSA_IOSIZE FSA_FILE FSA_WSS FSA_NAME FSA_RANDOM FSA_INSTANCES %token FSA_DSYNC FSA_TARGET FSA_ITERS FSA_NICE FSA_VALUE FSA_BLOCKING %token FSA_HIGHWATER FSA_DIRECTIO FSA_DIRWIDTH FSA_FD FSA_SRCFD FSA_ROTATEFD -%token FSA_NAMELENGTH FSA_FILESIZE FSA_ENTRIES FSA_FILESIZEGAMMA -%token FSA_DIRGAMMA FSA_USEISM FSA_ALLDONE FSA_FIRSTDONE FSA_TIMEOUT +%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_RANDSEED FSA_RANDGAMMA FSA_RANDMEAN FSA_RANDMIN +%token FSS_TYPE FSS_SEED FSS_GAMMA FSS_MEAN FSS_MIN FSS_SRC FSS_ROUND +%token FSA_ALLDONE FSA_FIRSTDONE FSA_TIMEOUT %type <ival> FSV_VAL_INT %type <bval> FSV_VAL_BOOLEAN %type <sval> FSV_STRING %type <sval> FSV_WHITESTRING %type <sval> FSV_VARIABLE +%type <sval> FSV_RANDVAR %type <sval> FSK_ASSIGN %type <ival> FSC_LIST FSC_DEFINE FSC_SET FSC_LOAD FSC_RUN @@ -182,21 +196,29 @@ static void parser_abort(int arg); %type <ival> entity %type <val> value -%type <cmd> command inner_commands load_command run_command -%type <cmd> list_command define_command debug_command create_command +%type <cmd> command inner_commands load_command run_command list_command +%type <cmd> proc_define_command files_define_command randvar_define_command +%type <cmd> debug_command create_command %type <cmd> sleep_command stats_command set_command shutdown_command %type <cmd> foreach_command log_command system_command flowop_command %type <cmd> eventgen_command quit_command flowop_list thread_list %type <cmd> thread echo_command usage_command help_command vars_command -%type <attr> attr_op attr_ops -%type <attr> attr_value -%type <list> integer_seplist string_seplist string_list var_string_list var_string -%type <list> whitevar_string whitevar_string_list -%type <ival> attrs_define_file attrs_define_thread attrs_flowop attrs_define_fileset -%type <ival> attrs_define_proc attrs_eventgen -%type <ival> attr_name - +%type <attr> files_attr_op files_attr_ops pt_attr_op pt_attr_ops +%type <attr> fo_attr_op fo_attr_ops ev_attr_op ev_attr_ops +%type <attr> randvar_attr_op randvar_attr_ops randvar_attr_typop +%type <attr> randvar_attr_srcop attr_value attr_list_value +%type <list> integer_seplist string_seplist string_list var_string_list +%type <list> var_string whitevar_string whitevar_string_list +%type <ival> attrs_define_file attrs_define_thread attrs_flowop +%type <ival> attrs_define_fileset attrs_define_proc attrs_eventgen +%type <ival> files_attr_name pt_attr_name fo_attr_name ev_attr_name +%type <ival> randvar_attr_name FSA_TYPE randtype_name randvar_attr_param +%type <ival> randsrc_name FSA_RANDSRC randvar_attr_tsp +%type <ival> FSS_TYPE FSS_SEED FSS_GAMMA FSS_MEAN FSS_MIN FSS_SRC + +%type <rndtb> probtabentry_list probtabentry +%type <avd> var_int_val %% commands: commands command @@ -240,7 +262,9 @@ inner_commands: command }; command: - define_command + proc_define_command +| files_define_command +| randvar_define_command | debug_command | eventgen_command | create_command @@ -284,9 +308,8 @@ foreach_command: FSC_FOREACH inner_cmd = inner_cmd->cmd_next) { filebench_log(LOG_DEBUG_IMPL, "packing foreach: %zx %s=%lld, cmd %zx", - $$, - $$->cmd_tgt1, - *list->list_integer, inner_cmd); + $$, $$->cmd_tgt1, + avd_get_int(list->list_integer), inner_cmd); } } }| foreach_command FSV_VARIABLE FSK_IN string_seplist FSK_OPENLST inner_commands FSK_CLOSELST @@ -319,7 +342,7 @@ integer_seplist: FSV_VAL_INT if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_integer = integer_alloc($1); + $$->list_integer = avd_int_alloc($1); } | integer_seplist FSK_SEPLST FSV_VAL_INT { @@ -329,7 +352,7 @@ integer_seplist: FSV_VAL_INT if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_integer = integer_alloc($3); + $$->list_integer = avd_int_alloc($3); /* Find end of list */ for (list = $1; list != NULL; @@ -344,7 +367,7 @@ string_seplist: FSK_QUOTE FSV_WHITESTRING FSK_QUOTE if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($2); + $$->list_string = avd_str_alloc($2); } | string_seplist FSK_SEPLST FSK_QUOTE FSV_WHITESTRING FSK_QUOTE { @@ -354,7 +377,7 @@ string_seplist: FSK_QUOTE FSV_WHITESTRING FSK_QUOTE if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($4); + $$->list_string = avd_str_alloc($4); /* Find end of list */ for (list = $1; list != NULL; @@ -370,7 +393,7 @@ eventgen_command: FSC_EVENTGEN YYERROR; $$->cmd = &parser_eventgen; } -| eventgen_command attr_ops +| eventgen_command ev_attr_ops { $1->cmd_attr_list = $2; }; @@ -414,8 +437,7 @@ string_list: FSV_VARIABLE { if (($$ = alloc_list()) == NULL) YYERROR; - - $$->list_string = string_alloc($1); + $$->list_string = avd_str_alloc($1); } | string_list FSK_SEPLST FSV_VARIABLE { @@ -425,7 +447,7 @@ string_list: FSV_VARIABLE if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($3); + $$->list_string = avd_str_alloc($3); /* Find end of list */ for (list = $1; list != NULL; @@ -440,14 +462,14 @@ var_string: FSV_VARIABLE if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($1); + $$->list_string = avd_str_alloc($1); } | FSV_STRING { if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($1); + $$->list_string = avd_str_alloc($1); }; var_string_list: var_string @@ -462,7 +484,7 @@ var_string_list: var_string if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($2); + $$->list_string = avd_str_alloc($2); /* Find end of list */ for (list = $1; list != NULL; @@ -480,7 +502,7 @@ var_string_list: var_string if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($2); + $$->list_string = avd_str_alloc($2); /* Find end of list */ for (list = $1; list != NULL; @@ -497,7 +519,7 @@ var_string_list: var_string if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($2); + $$->list_string = avd_str_alloc($2); /* Find end of list */ for (list = $1; list != NULL; @@ -515,7 +537,7 @@ var_string_list: var_string if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($2); + $$->list_string = avd_str_alloc($2); /* Find end of list */ for (list = $1; list != NULL; @@ -530,14 +552,14 @@ whitevar_string: FSK_QUOTE FSV_VARIABLE if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($2); + $$->list_string = avd_str_alloc($2); } | FSK_QUOTE FSV_WHITESTRING { if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($2); + $$->list_string = avd_str_alloc($2); }; whitevar_string_list: whitevar_string FSV_WHITESTRING @@ -549,7 +571,7 @@ whitevar_string_list: whitevar_string FSV_WHITESTRING if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($2); + $$->list_string = avd_str_alloc($2); /* Find end of list */ for (list = $1; list != NULL; @@ -567,7 +589,7 @@ whitevar_string_list: whitevar_string FSV_WHITESTRING if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($2); + $$->list_string = avd_str_alloc($2); /* Find end of list */ for (list = $1; list != NULL; @@ -575,7 +597,25 @@ whitevar_string_list: whitevar_string FSV_WHITESTRING list_end = list; list_end->list_next = $$; $$ = $1; -} |whitevar_string_list FSV_WHITESTRING +}| whitevar_string FSV_RANDVAR randvar_attr_tsp +{ + list_t *list = NULL; + list_t *list_end = NULL; + + /* Add variable */ + if (($$ = alloc_list()) == NULL) + YYERROR; + + $$->list_string = avd_str_alloc($2); + $$->list_integer = avd_int_alloc($3); + + /* Find end of list */ + for (list = $1; list != NULL; + list = list->list_next) + list_end = list; + list_end->list_next = $$; + $$ = $1; +}| whitevar_string_list FSV_WHITESTRING { list_t *list = NULL; list_t *list_end = NULL; @@ -584,7 +624,7 @@ whitevar_string_list: whitevar_string FSV_WHITESTRING if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($2); + $$->list_string = avd_str_alloc($2); /* Find end of list */ for (list = $1; list != NULL; @@ -602,7 +642,25 @@ whitevar_string_list: whitevar_string FSV_WHITESTRING if (($$ = alloc_list()) == NULL) YYERROR; - $$->list_string = string_alloc($2); + $$->list_string = avd_str_alloc($2); + + /* Find end of list */ + for (list = $1; list != NULL; + list = list->list_next) + list_end = list; + list_end->list_next = $$; + $$ = $1; +}| whitevar_string_list FSV_RANDVAR randvar_attr_tsp +{ + list_t *list = NULL; + list_t *list_end = NULL; + + /* Add variable */ + if (($$ = alloc_list()) == NULL) + YYERROR; + + $$->list_string = avd_str_alloc($2); + $$->list_integer = avd_int_alloc($3); /* Find end of list */ for (list = $1; list != NULL; @@ -623,6 +681,10 @@ list_command: FSC_LIST if (($$ = alloc_cmd()) == NULL) YYERROR; $$->cmd = &parser_list; +} +| list_command FSC_FLOWOP +{ + $1->cmd = &parser_flowop_list; }; log_command: FSC_LOG whitevar_string_list @@ -654,6 +716,17 @@ set_command: FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VAL_INT } $$->cmd = NULL; } +| FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VAL_BOOLEAN +{ + if (($$ = alloc_cmd()) == NULL) + YYERROR; + var_assign_boolean($2, $4); + if (parentscript) { + $$->cmd_tgt1 = $2; + parser_vars($$); + } + $$->cmd = NULL; +} | FSC_SET FSV_VARIABLE FSK_ASSIGN FSK_QUOTE FSV_WHITESTRING FSK_QUOTE { if (($$ = alloc_cmd()) == NULL) @@ -702,6 +775,33 @@ set_command: FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VAL_INT if (($$ = alloc_cmd()) == NULL) YYERROR; $$->cmd = NULL; +}| FSC_SET FSV_RANDVAR FSS_TYPE FSK_ASSIGN randvar_attr_typop +{ + if (($$ = alloc_cmd()) == NULL) + YYERROR; + $$->cmd = &parser_randvar_set; + $$->cmd_tgt1 = $2; + $$->cmd_qty = FSS_TYPE; + $$->cmd_attr_list = $5; + +}| FSC_SET FSV_RANDVAR FSS_SRC FSK_ASSIGN randvar_attr_srcop +{ + if (($$ = alloc_cmd()) == NULL) + YYERROR; + $$->cmd = &parser_randvar_set; + $$->cmd_tgt1 = $2; + $$->cmd_qty = FSS_SRC; + $$->cmd_attr_list = $5; + +}| FSC_SET FSV_RANDVAR randvar_attr_param FSK_ASSIGN attr_value +{ + if (($$ = alloc_cmd()) == NULL) + YYERROR; + $$->cmd = &parser_randvar_set; + $$->cmd_tgt1 = $2; + $$->cmd_qty = $3; + $$->cmd_attr_list = $5; + }; stats_command: FSC_STATS FSE_SNAP @@ -779,7 +879,7 @@ flowop_list: flowop_command $$ = $1; }; -thread: FSE_THREAD attr_ops FSK_OPENLST flowop_list FSK_CLOSELST +thread: FSE_THREAD pt_attr_ops FSK_OPENLST flowop_list FSK_CLOSELST { /* * Allocate a cmd node per thread, with a @@ -812,7 +912,7 @@ thread_list: thread $$ = $1; }; -define_command: FSC_DEFINE FSE_PROC attr_ops FSK_OPENLST thread_list FSK_CLOSELST +proc_define_command: FSC_DEFINE FSE_PROC pt_attr_ops FSK_OPENLST thread_list FSK_CLOSELST { if (($$ = alloc_cmd()) == NULL) YYERROR; @@ -820,7 +920,13 @@ define_command: FSC_DEFINE FSE_PROC attr_ops FSK_OPENLST thread_list FSK_CLOSELS $$->cmd_list = $5; $$->cmd_attr_list = $3; -}| FSC_DEFINE FSE_FILE +} +| proc_define_command pt_attr_ops +{ + $1->cmd_attr_list = $2; +}; + +files_define_command: FSC_DEFINE FSE_FILE { if (($$ = alloc_cmd()) == NULL) YYERROR; @@ -831,11 +937,19 @@ define_command: FSC_DEFINE FSE_PROC attr_ops FSK_OPENLST thread_list FSK_CLOSELS YYERROR; $$->cmd = &parser_fileset_define; } -| define_command attr_ops +| files_define_command files_attr_ops { $1->cmd_attr_list = $2; }; +randvar_define_command: FSC_DEFINE FSE_RAND randvar_attr_ops +{ + if (($$ = alloc_cmd()) == NULL) + YYERROR; + $$->cmd = &parser_randvar_define; + $$->cmd_attr_list = $3; +}; + create_command: FSC_CREATE entity { if (($$ = alloc_cmd()) == NULL) @@ -879,7 +993,7 @@ sleep_command: FSC_SLEEP FSV_VAL_INT } | FSC_SLEEP FSV_VARIABLE { - vinteger_t *integer; + fbint_t *integer; if (($$ = alloc_cmd()) == NULL) YYERROR; @@ -896,7 +1010,7 @@ run_command: FSC_RUN FSV_VAL_INT } | FSC_RUN FSV_VARIABLE { - vinteger_t *integer; + fbint_t *integer; if (($$ = alloc_cmd()) == NULL) YYERROR; @@ -905,7 +1019,7 @@ run_command: FSC_RUN FSV_VAL_INT } | FSC_RUN { - vinteger_t *integer; + fbint_t *integer; if (($$ = alloc_cmd()) == NULL) YYERROR; @@ -926,7 +1040,7 @@ flowop_command: FSC_FLOWOP name YYERROR; $$->cmd_name = fb_stralloc($2); } -| flowop_command attr_ops +| flowop_command fo_attr_ops { $1->cmd_attr_list = $2; }; @@ -958,6 +1072,7 @@ load_command: FSC_LOAD FSV_STRING yy_switchfileparent(yyin); }; + entity: FSE_PROC {$$ = FSE_PROC;} | FSE_THREAD {$$ = FSE_THREAD;} | FSE_FILESET {$$ = FSE_FILESET;} @@ -969,11 +1084,130 @@ value: FSV_VAL_INT { $$.i = $1;} name: FSV_STRING; -attr_ops: attr_op +/* attribute parsing for define file and define fileset */ +files_attr_ops: files_attr_op +{ + $$ = $1; +} +| files_attr_ops FSK_SEPLST files_attr_op +{ + attr_t *attr = NULL; + attr_t *list_end = NULL; + + for (attr = $1; attr != NULL; + attr = attr->attr_next) + list_end = attr; /* Find end of list */ + + list_end->attr_next = $3; + + $$ = $1; +}; + +files_attr_op: files_attr_name FSK_ASSIGN attr_list_value +{ + $$ = $3; + $$->attr_name = $1; +} +| files_attr_name +{ + if (($$ = alloc_attr()) == NULL) + YYERROR; + $$->attr_name = $1; +}; + +/* attribute parsing for random variables */ +randvar_attr_ops: randvar_attr_op +{ + $$ = $1; +} +| randvar_attr_ops FSK_SEPLST randvar_attr_op +{ + attr_t *attr = NULL; + attr_t *list_end = NULL; + + for (attr = $1; attr != NULL; + attr = attr->attr_next) + list_end = attr; /* Find end of list */ + + list_end->attr_next = $3; + + $$ = $1; +} +| randvar_attr_ops FSK_SEPLST FSA_RANDTABLE FSK_ASSIGN FSK_OPENLST probtabentry_list FSK_CLOSELST +{ + attr_t *attr = NULL; + attr_t *list_end = NULL; + + for (attr = $1; attr != NULL; + attr = attr->attr_next) + list_end = attr; /* Find end of list */ + + + if ((attr = alloc_attr()) == NULL) + YYERROR; + + attr->attr_name = FSA_RANDTABLE; + attr->attr_obj = (void *)$6; + list_end->attr_next = attr; + $$ = $1; +}; + +randvar_attr_op: randvar_attr_name FSK_ASSIGN attr_list_value +{ + $$ = $3; + $$->attr_name = $1; +} +| randvar_attr_name +{ + if (($$ = alloc_attr()) == NULL) + YYERROR; + $$->attr_name = $1; +} +| FSA_TYPE FSK_ASSIGN randvar_attr_typop +{ + $$ = $3; + $$->attr_name = FSA_TYPE; +} +| FSA_RANDSRC FSK_ASSIGN randvar_attr_srcop +{ + $$ = $3; + $$->attr_name = FSA_RANDSRC; +}; + +probtabentry: FSK_OPENLST var_int_val FSK_SEPLST var_int_val FSK_SEPLST var_int_val FSK_CLOSELST +{ + if (($$ = alloc_probtabent()) == NULL) + YYERROR; + $$->pte_percent = $2; + $$->pte_segmin = $4; + $$->pte_segmax = $6; +}; + +/* attribute parsing for prob density function table */ +probtabentry_list: probtabentry { $$ = $1; } -| attr_ops FSK_SEPLST attr_op +| probtabentry_list FSK_SEPLST probtabentry +{ + probtabent_t *pte = NULL; + probtabent_t *ptelist_end = NULL; + + for (pte = $1; pte != NULL; + pte = pte->pte_next) + ptelist_end = pte; /* Find end of prob table entry list */ + + ptelist_end->pte_next = $3; + + $$ = $1; +}; + +/* attribute parsing for define thread and process */ +pt_attr_ops: pt_attr_op +{ + $$ = $1; +} +| pt_attr_ops FSK_SEPLST pt_attr_op { attr_t *attr = NULL; attr_t *list_end = NULL; @@ -987,73 +1221,211 @@ attr_ops: attr_op $$ = $1; }; -attr_op: attr_name FSK_ASSIGN attr_value +pt_attr_op: pt_attr_name FSK_ASSIGN attr_value { $$ = $3; $$->attr_name = $1; } -| attr_name +| pt_attr_name { if (($$ = alloc_attr()) == NULL) YYERROR; $$->attr_name = $1; +}; + +/* attribute parsing for flowops */ +fo_attr_ops: fo_attr_op +{ + $$ = $1; } +| fo_attr_ops FSK_SEPLST fo_attr_op +{ + attr_t *attr = NULL; + attr_t *list_end = NULL; + + for (attr = $1; attr != NULL; + attr = attr->attr_next) + list_end = attr; /* Find end of list */ + + list_end->attr_next = $3; + + $$ = $1; +}; + +fo_attr_op: fo_attr_name FSK_ASSIGN attr_value +{ + $$ = $3; + $$->attr_name = $1; +} +| fo_attr_name +{ + if (($$ = alloc_attr()) == NULL) + YYERROR; + $$->attr_name = $1; +}; + +/* attribute parsing for Event Generator */ +ev_attr_ops: ev_attr_op +{ + $$ = $1; +} +| ev_attr_ops FSK_SEPLST ev_attr_op +{ + attr_t *attr = NULL; + attr_t *list_end = NULL; + + for (attr = $1; attr != NULL; + attr = attr->attr_next) + list_end = attr; /* Find end of list */ + + list_end->attr_next = $3; + + $$ = $1; +}; + +ev_attr_op: ev_attr_name FSK_ASSIGN attr_value +{ + $$ = $3; + $$->attr_name = $1; +} +| ev_attr_name +{ + if (($$ = alloc_attr()) == NULL) + YYERROR; + $$->attr_name = $1; +}; + + +files_attr_name: attrs_define_file +|attrs_define_fileset; + +pt_attr_name: attrs_define_thread +|attrs_define_proc; -attr_name: attrs_define_file -|attrs_define_fileset -|attrs_define_thread -|attrs_define_proc -|attrs_flowop -|attrs_eventgen; +fo_attr_name: attrs_flowop; + +ev_attr_name: attrs_eventgen; attrs_define_proc: -FSA_NICE { $$ = FSA_NICE;} -|FSA_INSTANCES { $$ = FSA_INSTANCES;}; + FSA_NICE { $$ = FSA_NICE;} +| FSA_NAME { $$ = FSA_NAME;} +| FSA_INSTANCES { $$ = FSA_INSTANCES;}; attrs_define_file: -FSA_SIZE { $$ = FSA_SIZE;} + FSA_SIZE { $$ = FSA_SIZE;} +| FSA_NAME { $$ = FSA_NAME;} | FSA_PATH { $$ = FSA_PATH;} | FSA_REUSE { $$ = FSA_REUSE;} | FSA_PREALLOC { $$ = FSA_PREALLOC;} | FSA_PARALLOC { $$ = FSA_PARALLOC;}; attrs_define_fileset: -FSA_SIZE { $$ = FSA_SIZE;} + FSA_SIZE { $$ = FSA_SIZE;} +| FSA_NAME { $$ = FSA_NAME;} | FSA_PATH { $$ = FSA_PATH;} | FSA_DIRWIDTH { $$ = FSA_DIRWIDTH;} +| FSA_DIRDEPTHRV { $$ = FSA_DIRDEPTHRV;} | FSA_PREALLOC { $$ = FSA_PREALLOC;} | FSA_FILESIZEGAMMA { $$ = FSA_FILESIZEGAMMA;} | FSA_DIRGAMMA { $$ = FSA_DIRGAMMA;} | FSA_CACHED { $$ = FSA_CACHED;} | FSA_ENTRIES { $$ = FSA_ENTRIES;}; +randvar_attr_name: + FSA_NAME { $$ = FSA_NAME;} +| FSA_RANDSEED { $$ = FSA_RANDSEED;} +| FSA_RANDGAMMA { $$ = FSA_RANDGAMMA;} +| FSA_RANDMEAN { $$ = FSA_RANDMEAN;} +| FSA_RANDMIN { $$ = FSA_RANDMIN;} +| FSA_RANDROUND { $$ = FSA_RANDROUND;}; + +randvar_attr_tsp: + FSS_TYPE { $$ = FSS_TYPE;} +| FSS_SRC { $$ = FSS_SRC;} +| FSS_SEED { $$ = FSS_SEED;} +| FSS_GAMMA { $$ = FSS_GAMMA;} +| FSS_MEAN { $$ = FSS_MEAN;} +| FSS_MIN { $$ = FSS_MIN;} +| FSS_ROUND { $$ = FSS_ROUND;}; + + +randvar_attr_param: + FSS_SEED { $$ = FSS_SEED;} +| FSS_GAMMA { $$ = FSS_GAMMA;} +| FSS_MEAN { $$ = FSS_MEAN;} +| FSS_MIN { $$ = FSS_MIN;} +| FSS_ROUND { $$ = FSS_ROUND;}; + +randvar_attr_typop: randtype_name +{ + if (($$ = alloc_attr()) == NULL) + YYERROR; + $$->attr_avd = avd_int_alloc($1); +}; + +randtype_name: + FSV_RANDUNI { $$ = FSV_RANDUNI;} +| FSV_RANDTAB { $$ = FSV_RANDTAB;} +| FSA_RANDGAMMA { $$ = FSA_RANDGAMMA;}; + +randvar_attr_srcop: randsrc_name +{ + if (($$ = alloc_attr()) == NULL) + YYERROR; + $$->attr_avd = avd_int_alloc($1); +}; + +randsrc_name: + FSV_URAND { $$ = FSV_URAND;} +| FSV_RAND48 { $$ = FSV_RAND48;}; + attrs_define_thread: -FSA_PROCESS { $$ = FSA_PROCESS;} -|FSA_MEMSIZE { $$ = FSA_MEMSIZE;} -|FSA_USEISM { $$ = FSA_USEISM;} -|FSA_INSTANCES { $$ = FSA_INSTANCES;}; + FSA_PROCESS { $$ = FSA_PROCESS;} +| FSA_NAME { $$ = FSA_NAME;} +| FSA_MEMSIZE { $$ = FSA_MEMSIZE;} +| FSA_USEISM { $$ = FSA_USEISM;} +| FSA_INSTANCES { $$ = FSA_INSTANCES;}; attrs_flowop: -FSA_WSS { $$ = FSA_WSS;} -|FSA_FILE { $$ = FSA_FILE;} -|FSA_NAME { $$ = FSA_NAME;} -|FSA_RANDOM { $$ = FSA_RANDOM;} -|FSA_FD { $$ = FSA_FD;} -|FSA_SRCFD { $$ = FSA_SRCFD;} -|FSA_ROTATEFD { $$ = FSA_ROTATEFD;} -|FSA_DSYNC { $$ = FSA_DSYNC;} -|FSA_DIRECTIO { $$ = FSA_DIRECTIO;} -|FSA_TARGET { $$ = FSA_TARGET;} -|FSA_ITERS { $$ = FSA_ITERS;} -|FSA_VALUE { $$ = FSA_VALUE;} -|FSA_BLOCKING { $$ = FSA_BLOCKING;} -|FSA_HIGHWATER { $$ = FSA_HIGHWATER;} -|FSA_IOSIZE { $$ = FSA_IOSIZE;}; + FSA_WSS { $$ = FSA_WSS;} +| FSA_FILE { $$ = FSA_FILE;} +| FSA_NAME { $$ = FSA_NAME;} +| FSA_RANDOM { $$ = FSA_RANDOM;} +| FSA_FD { $$ = FSA_FD;} +| FSA_SRCFD { $$ = FSA_SRCFD;} +| FSA_ROTATEFD { $$ = FSA_ROTATEFD;} +| FSA_DSYNC { $$ = FSA_DSYNC;} +| FSA_DIRECTIO { $$ = FSA_DIRECTIO;} +| FSA_TARGET { $$ = FSA_TARGET;} +| FSA_ITERS { $$ = FSA_ITERS;} +| FSA_VALUE { $$ = FSA_VALUE;} +| FSA_BLOCKING { $$ = FSA_BLOCKING;} +| FSA_HIGHWATER { $$ = FSA_HIGHWATER;} +| FSA_IOSIZE { $$ = FSA_IOSIZE;}; attrs_eventgen: -FSA_RATE { $$ = FSA_RATE;}; + FSA_RATE { $$ = FSA_RATE;}; -attr_value: var_string_list { +attr_value: FSV_STRING +{ + if (($$ = alloc_attr()) == NULL) + YYERROR; + $$->attr_avd = avd_str_alloc($1); +} | FSV_VAL_INT { + if (($$ = alloc_attr()) == NULL) + YYERROR; + $$->attr_avd = avd_int_alloc($1); +} | FSV_VAL_BOOLEAN { + if (($$ = alloc_attr()) == NULL) + YYERROR; + $$->attr_avd = avd_bool_alloc($1); +} | FSV_VARIABLE { + if (($$ = alloc_attr()) == NULL) + YYERROR; + $$->attr_avd = var_ref_attr($1); +}; + +attr_list_value: var_string_list { if (($$ = alloc_attr()) == NULL) YYERROR; $$->attr_param_list = $1; @@ -1061,16 +1433,27 @@ attr_value: var_string_list { { if (($$ = alloc_attr()) == NULL) YYERROR; - $$->attr_string = string_alloc($1); + $$->attr_avd = avd_str_alloc($1); } | FSV_VAL_INT { if (($$ = alloc_attr()) == NULL) YYERROR; - $$->attr_integer = integer_alloc($1); + $$->attr_avd = avd_int_alloc($1); +} | FSV_VAL_BOOLEAN { + if (($$ = alloc_attr()) == NULL) + YYERROR; + $$->attr_avd = avd_bool_alloc($1); } | FSV_VARIABLE { if (($$ = alloc_attr()) == NULL) YYERROR; - $$->attr_integer = var_ref_integer($1); - $$->attr_string = var_ref_string($1); + $$->attr_avd = var_ref_attr($1); +}; + +var_int_val: FSV_VAL_INT +{ + $$ = avd_int_alloc($1); +} | FSV_VARIABLE +{ + $$ = var_ref_attr($1); }; %% @@ -1210,8 +1593,11 @@ main(int argc, char *argv[]) exit(1); } - if (procflow_exec(procname, instance) < 0) + if (procflow_exec(procname, instance) < 0) { + filebench_log(LOG_ERROR, "Cannot startup process %s", + procname); exit(1); + } exit(0); } @@ -1307,8 +1693,7 @@ parser_list2string(list_t *list) list_t *l; char *string; char *tmp; - vinteger_t *integer; - + fbint_t *integer; if ((string = malloc(MAXPATHLEN)) == NULL) { filebench_log(LOG_ERROR, "Failed to allocate memory"); return (NULL); @@ -1318,16 +1703,69 @@ parser_list2string(list_t *list) /* Format args */ - for (l = list; l != NULL; - l = l->list_next) { + for (l = list; l != NULL; l = l->list_next) { + char *lstr = avd_get_str(l->list_string); + filebench_log(LOG_DEBUG_SCRIPT, - "converting string '%s'", *l->list_string); + "converting string '%s'", lstr); + + /* see if it is a random variable */ + if (l->list_integer) { + fbint_t param_name; + + tmp = NULL; + param_name = avd_get_int(l->list_integer); + switch (param_name) { + case FSS_TYPE: + tmp = var_randvar_to_string(lstr, + RAND_PARAM_TYPE); + break; + + case FSS_SRC: + tmp = var_randvar_to_string(lstr, + RAND_PARAM_SRC); + break; + + case FSS_SEED: + tmp = var_randvar_to_string(lstr, + RAND_PARAM_SEED); + break; + + case FSS_MIN: + tmp = var_randvar_to_string(lstr, + RAND_PARAM_MIN); + break; + + case FSS_MEAN: + tmp = var_randvar_to_string(lstr, + RAND_PARAM_MEAN); + break; + + case FSS_GAMMA: + tmp = var_randvar_to_string(lstr, + RAND_PARAM_GAMMA); + break; - if ((tmp = var_to_string(*l->list_string)) != NULL) { - (void) strcat(string, tmp); - free(tmp); + case FSS_ROUND: + tmp = var_randvar_to_string(lstr, + RAND_PARAM_ROUND); + break; + } + + if (tmp) { + (void) strcat(string, tmp); + free(tmp); + } else { + (void) strcat(string, lstr); + } } else { - (void) strcat(string, *l->list_string); + /* perhaps a normal variable? */ + if ((tmp = var_to_string(lstr)) != NULL) { + (void) strcat(string, tmp); + free(tmp); + } else { + (void) strcat(string, lstr); + } } } return (string); @@ -1340,30 +1778,34 @@ parser_list2string(list_t *list) * containing a copy of that string. On failure either returns NULL * or shuts down the run. */ -var_string_t +avd_t parser_list2varstring(list_t *list) { + char *lstr = avd_get_str(list->list_string); + /* Special case - variable name */ - if ((list->list_next == NULL) && (*(*list->list_string) == '$')) - return (var_ref_string(*list->list_string)); + if ((list->list_next == NULL) && (*lstr == '$')) + return (var_ref_attr(lstr)); - return (string_alloc(parser_list2string(list))); + return (avd_str_alloc(parser_list2string(list))); } /* * Looks for the var named in list_string of the first element of the - * supplied list. If found, returns the var_integer portion of the var. - * If the var is not found, cannot be allocated, the supplied list is - * NULL, or the list_string filed is empty, returns NULL. + * supplied list. If found, returns the var_val portion of the var in + * an attribute value descriptor. If the var is not found, cannot be + * allocated, the supplied list is NULL, or the list_string filed is + * empty, returns NULL. */ -var_integer_t -parser_list2integer(list_t *list) +avd_t +parser_list2avd(list_t *list) { - var_integer_t v; + avd_t avd; + char *lstr; - if (list && (*(list->list_string) != NULL)) { - v = var_ref_integer(*(list->list_string)); - return (v); + if (list && ((lstr = avd_get_str(list->list_string)) != NULL)) { + avd = var_ref_attr(lstr); + return (avd); } return (NULL); @@ -1377,18 +1819,17 @@ static void parser_eventgen(cmd_t *cmd) { attr_t *attr; - vinteger_t rate; + fbint_t rate; /* Get the rate from attribute */ if (attr = get_attr_integer(cmd, FSA_RATE)) { - if (attr->attr_integer) { + if (attr->attr_avd) { + rate = avd_get_int(attr->attr_avd); filebench_log(LOG_VERBOSE, - "Eventgen: %lld per second", - *attr->attr_integer); - eventgen_setrate(*attr->attr_integer); + "Eventgen: %lld per second", rate); + eventgen_setrate(rate); } } - } /* @@ -1406,10 +1847,11 @@ parser_foreach_integer(cmd_t *cmd) cmd_t *inner_cmd; for (; list != NULL; list = list->list_next) { - var_assign_integer(cmd->cmd_tgt1, *list->list_integer); + fbint_t list_int = avd_get_int(list->list_integer); + + var_assign_integer(cmd->cmd_tgt1, list_int); filebench_log(LOG_VERBOSE, "Iterating %s=%lld", - cmd->cmd_tgt1, - *list->list_integer); + cmd->cmd_tgt1, list_int); for (inner_cmd = cmd->cmd_list; inner_cmd != NULL; inner_cmd = inner_cmd->cmd_next) { inner_cmd->cmd(inner_cmd); @@ -1428,13 +1870,13 @@ static void parser_foreach_string(cmd_t *cmd) { list_t *list = cmd->cmd_param_list; - cmd_t *inner_cmd; for (; list != NULL; list = list->list_next) { - var_assign_string(cmd->cmd_tgt1, *list->list_string); + cmd_t *inner_cmd; + char *lstr = avd_get_str(list->list_string); + var_assign_string(cmd->cmd_tgt1, lstr); filebench_log(LOG_VERBOSE, "Iterating %s=%s", - cmd->cmd_tgt1, - *list->list_string); + cmd->cmd_tgt1, lstr); for (inner_cmd = cmd->cmd_list; inner_cmd != NULL; inner_cmd = inner_cmd->cmd_next) { inner_cmd->cmd(inner_cmd); @@ -1453,6 +1895,15 @@ parser_list(cmd_t *cmd) } /* + * Lists the flowop name and instance number for all flowops. + */ +static void +parser_flowop_list(cmd_t *cmd) +{ + flowop_printall(); +} + +/* * Calls procflow_define() to allocate "instances" number of procflow(s) * (processes) with the supplied name. The default number of instances is * one. An optional priority level attribute can be supplied and is stored in @@ -1466,12 +1917,13 @@ parser_proc_define(cmd_t *cmd) procflow_t *procflow, template; char *name; attr_t *attr; - var_integer_t instances = integer_alloc(1); + avd_t var_instances; + fbint_t instances; cmd_t *inner_cmd; /* Get the name of the process */ if (attr = get_attr(cmd, FSA_NAME)) { - name = *attr->attr_string; + name = avd_get_str(attr->attr_avd); } else { filebench_log(LOG_ERROR, "define proc: proc specifies no name"); @@ -1480,13 +1932,23 @@ parser_proc_define(cmd_t *cmd) /* Get the memory size from attribute */ if (attr = get_attr_integer(cmd, FSA_INSTANCES)) { + if (AVD_IS_RANDOM(attr->attr_avd)) { + filebench_log(LOG_ERROR, + "proc_define: Instances attr cannot be random"); + filebench_shutdown(1); + } + var_instances = attr->attr_avd; + instances = avd_get_int(var_instances); + filebench_log(LOG_DEBUG_IMPL, + "Setting instances = %lld", instances); + } else { filebench_log(LOG_DEBUG_IMPL, - "Setting instances = %lld", - *attr->attr_integer); - instances = attr->attr_integer; + "Defaulting to instances = 1"); + var_instances = avd_int_alloc(1); + instances = 1; } - if ((procflow = procflow_define(name, NULL, instances)) == NULL) { + if ((procflow = procflow_define(name, NULL, var_instances)) == NULL) { filebench_log(LOG_ERROR, "Failed to instantiate %d %s process(es)\n", instances, name); @@ -1495,17 +1957,22 @@ parser_proc_define(cmd_t *cmd) /* Get the pri from attribute */ if (attr = get_attr_integer(cmd, FSA_NICE)) { + if (AVD_IS_RANDOM(attr->attr_avd)) { + filebench_log(LOG_ERROR, + "proc_define: priority cannot be random"); + filebench_shutdown(1); + } filebench_log(LOG_DEBUG_IMPL, "Setting pri = %lld", - *attr->attr_integer); - procflow->pf_nice = attr->attr_integer; + avd_get_int(attr->attr_avd)); + procflow->pf_nice = attr->attr_avd; } else - procflow->pf_nice = integer_alloc(0); + procflow->pf_nice = avd_int_alloc(0); /* Create the list of threads for this process */ for (inner_cmd = cmd->cmd_list; inner_cmd != NULL; inner_cmd = inner_cmd->cmd_next) { - parser_thread_define(inner_cmd, procflow, *instances); + parser_thread_define(inner_cmd, procflow, instances); } } @@ -1524,7 +1991,7 @@ parser_thread_define(cmd_t *cmd, procflow_t *procflow, int procinstances) { threadflow_t *threadflow, template; attr_t *attr; - var_integer_t instances = integer_alloc(1); + avd_t instances; cmd_t *inner_cmd; char *name; @@ -1532,7 +1999,7 @@ parser_thread_define(cmd_t *cmd, procflow_t *procflow, int procinstances) /* Get the name of the thread */ if (attr = get_attr(cmd, FSA_NAME)) { - name = *attr->attr_string; + name = avd_get_str(attr->attr_avd); } else { filebench_log(LOG_ERROR, "define thread: thread in process %s specifies no name", @@ -1542,20 +2009,31 @@ parser_thread_define(cmd_t *cmd, procflow_t *procflow, int procinstances) /* Get the number of instances from attribute */ if (attr = get_attr_integer(cmd, FSA_INSTANCES)) { + if (AVD_IS_RANDOM(attr->attr_avd)) { + filebench_log(LOG_ERROR, + "define thread: Instances attr cannot be random"); + filebench_shutdown(1); + } filebench_log(LOG_DEBUG_IMPL, "define thread: Setting instances = %lld", - *attr->attr_integer); - instances = attr->attr_integer; - } + avd_get_int(attr->attr_avd)); + instances = attr->attr_avd; + } else + instances = avd_int_alloc(1); /* Get the memory size from attribute */ if (attr = get_attr_integer(cmd, FSA_MEMSIZE)) { + if (AVD_IS_RANDOM(attr->attr_avd)) { + filebench_log(LOG_ERROR, + "define thread: Memory size cannot be random"); + filebench_shutdown(1); + } filebench_log(LOG_DEBUG_IMPL, "define thread: Setting memsize = %lld", - *attr->attr_integer); - template.tf_memsize = attr->attr_integer; + avd_get_int(attr->attr_avd)); + template.tf_memsize = attr->attr_avd; } else - template.tf_memsize = integer_alloc(0); + template.tf_memsize = avd_int_alloc(0); if ((threadflow = threadflow_define(procflow, name, &template, instances)) == NULL) { @@ -1572,10 +2050,119 @@ parser_thread_define(cmd_t *cmd, procflow_t *procflow, int procinstances) /* Create the list of flowops */ for (inner_cmd = cmd->cmd_list; inner_cmd != NULL; inner_cmd = inner_cmd->cmd_next) { - parser_flowop_define(inner_cmd, threadflow); + parser_flowop_define(inner_cmd, threadflow, + &threadflow->tf_ops, FLOW_MASTER); + } +} + +/* + * Files in the attributes for a newly allocated flowop + */ +static void +parser_flowop_get_attrs(cmd_t *cmd, flowop_t *flowop) +{ + attr_t *attr; + + /* Get the filename from attribute */ + if (attr = get_attr(cmd, FSA_FILE)) { + flowop->fo_filename = attr->attr_avd; + if (flowop->fo_filename == NULL) { + filebench_log(LOG_ERROR, + "define flowop: no filename specfied"); + filebench_shutdown(1); + } + + if ((flowop->fo_filename->avd_type == AVD_VAL_STR) || + (flowop->fo_filename->avd_type == AVD_VARVAL_STR)) { + char *name; + + name = avd_get_str(flowop->fo_filename); + flowop->fo_fileset = fileset_find(name); + + if (flowop->fo_fileset == NULL) { + filebench_log(LOG_ERROR, + "flowop %s: file %s not found", + flowop->fo_name, name); + filebench_shutdown(1); + } + } + } + + /* Get the iosize of the op */ + if (attr = get_attr_integer(cmd, FSA_IOSIZE)) + flowop->fo_iosize = attr->attr_avd; + else + flowop->fo_iosize = avd_int_alloc(0); + + /* Get the working set size of the op */ + if (attr = get_attr_integer(cmd, FSA_WSS)) + flowop->fo_wss = attr->attr_avd; + else + flowop->fo_wss = avd_int_alloc(0); + + /* Random I/O? */ + if (attr = get_attr_bool(cmd, FSA_RANDOM)) + flowop->fo_random = attr->attr_avd; + else + flowop->fo_random = avd_bool_alloc(FALSE); + + /* Sync I/O? */ + if (attr = get_attr_bool(cmd, FSA_DSYNC)) + flowop->fo_dsync = attr->attr_avd; + else + flowop->fo_dsync = avd_bool_alloc(FALSE); + + /* Target, for wakeup etc */ + if (attr = get_attr(cmd, FSA_TARGET)) + (void) strcpy(flowop->fo_targetname, + avd_get_str(attr->attr_avd)); + + /* Value */ + if (attr = get_attr_integer(cmd, FSA_VALUE)) + flowop->fo_value = attr->attr_avd; + else + flowop->fo_value = avd_int_alloc(0); + + /* FD */ + if (attr = get_attr_integer(cmd, FSA_FD)) + flowop->fo_fdnumber = avd_get_int(attr->attr_avd); + + /* Rotatefd? */ + if (attr = get_attr_bool(cmd, FSA_ROTATEFD)) + flowop->fo_rotatefd = attr->attr_avd; + else + flowop->fo_rotatefd = avd_bool_alloc(FALSE); + + /* SRC FD, for copies etc... */ + if (attr = get_attr_integer(cmd, FSA_SRCFD)) + flowop->fo_srcfdnumber = avd_get_int(attr->attr_avd); + + /* Blocking operation? */ + if (attr = get_attr_bool(cmd, FSA_BLOCKING)) + flowop->fo_blocking = attr->attr_avd; + else + flowop->fo_blocking = avd_bool_alloc(FALSE); + + /* Direct I/O Operation */ + if (attr = get_attr_bool(cmd, FSA_DIRECTIO)) + flowop->fo_directio = attr->attr_avd; + else + flowop->fo_directio = avd_bool_alloc(FALSE); + + /* Highwater mark */ + if (attr = get_attr_integer(cmd, FSA_HIGHWATER)) { + flowop->fo_highwater = attr->attr_avd; + if (AVD_IS_RANDOM(attr->attr_avd)) { + filebench_log(LOG_ERROR, + "define flowop: Highwater attr cannot be random"); + filebench_shutdown(1); + } + } else { + flowop->fo_highwater = avd_int_alloc(1); } } + /* * Calls flowop_define() to allocate a flowop with the supplied name. * The allocated flowop inherits attributes from a base flowop of the @@ -1604,7 +2191,8 @@ parser_thread_define(cmd_t *cmd, procflow_t *procflow, int procinstances) * fileobj or fileset cannot be located. */ static void -parser_flowop_define(cmd_t *cmd, threadflow_t *thread) +parser_flowop_define(cmd_t *cmd, threadflow_t *thread, + flowop_t **flowoplist_hdp, int category) { flowop_t *flowop, *flowop_type; char *type = (char *)cmd->cmd_name; @@ -1622,7 +2210,7 @@ parser_flowop_define(cmd_t *cmd, threadflow_t *thread) /* Get the name of the flowop */ if (attr = get_attr(cmd, FSA_NAME)) { - name = *attr->attr_string; + name = avd_get_str(attr->attr_avd); } else { filebench_log(LOG_ERROR, "define flowop: flowop %s specifies no name", @@ -1631,116 +2219,39 @@ parser_flowop_define(cmd_t *cmd, threadflow_t *thread) } if ((flowop = flowop_define(thread, name, - flowop_type, FLOW_MASTER, 0)) == NULL) { + flowop_type, category, 0)) == NULL) { filebench_log(LOG_ERROR, "define flowop: Failed to instantiate flowop %s\n", cmd->cmd_name); filebench_shutdown(1); } - /* Get the filename from attribute */ - if (attr = get_attr(cmd, FSA_FILE)) { - flowop->fo_fileset = fileset_find(*attr->attr_string); - - if ((flowop->fo_fileset == NULL)) { - filebench_log(LOG_ERROR, - "define flowop: file %s not found", - *attr->attr_string); - filebench_shutdown(1); - } - } - - /* Get the iosize of the op */ - if (attr = get_attr_integer(cmd, FSA_IOSIZE)) - flowop->fo_iosize = attr->attr_integer; - else - flowop->fo_iosize = integer_alloc(0); - - /* Get the working set size of the op */ - if (attr = get_attr_integer(cmd, FSA_WSS)) - flowop->fo_wss = attr->attr_integer; - else - flowop->fo_wss = integer_alloc(0); - - /* Random I/O? */ - if (attr = get_attr_bool(cmd, FSA_RANDOM)) - flowop->fo_random = attr->attr_integer; - else - flowop->fo_random = integer_alloc(0); - - /* Sync I/O? */ - if (attr = get_attr_bool(cmd, FSA_DSYNC)) - flowop->fo_dsync = attr->attr_integer; - else - flowop->fo_dsync = integer_alloc(0); - /* Iterations */ if (attr = get_attr_integer(cmd, FSA_ITERS)) - flowop->fo_iters = attr->attr_integer; - else - flowop->fo_iters = integer_alloc(1); - - - /* Target, for wakeup etc */ - if (attr = get_attr(cmd, FSA_TARGET)) - (void) strcpy(flowop->fo_targetname, *attr->attr_string); - - /* Value */ - if (attr = get_attr_integer(cmd, FSA_VALUE)) - flowop->fo_value = attr->attr_integer; - else - flowop->fo_value = integer_alloc(0); - - /* FD */ - if (attr = get_attr_integer(cmd, FSA_FD)) - flowop->fo_fdnumber = *attr->attr_integer; - - /* Rotatefd? */ - if (attr = get_attr_bool(cmd, FSA_ROTATEFD)) - flowop->fo_rotatefd = attr->attr_integer; - else - flowop->fo_rotatefd = integer_alloc(0); - - /* SRC FD, for copies etc... */ - if (attr = get_attr_integer(cmd, FSA_SRCFD)) - flowop->fo_srcfdnumber = *attr->attr_integer; - - /* Blocking operation? */ - if (attr = get_attr_bool(cmd, FSA_BLOCKING)) - flowop->fo_blocking = attr->attr_integer; + flowop->fo_iters = attr->attr_avd; else - flowop->fo_blocking = integer_alloc(0); + flowop->fo_iters = avd_int_alloc(1); - /* Blocking operation? */ - if (attr = get_attr_bool(cmd, FSA_DIRECTIO)) - flowop->fo_directio = attr->attr_integer; - else - flowop->fo_directio = integer_alloc(0); - - /* Highwater mark */ - if (attr = get_attr_integer(cmd, FSA_HIGHWATER)) - flowop->fo_highwater = attr->attr_integer; - else - flowop->fo_highwater = integer_alloc(1); + parser_flowop_get_attrs(cmd, flowop); } /* * Calls fileset_define() to allocate a fileset with the supplied name and - * initializes the fileset's pathname attribute, and optionally the fs_cached, - * fs_reuse, fs_prealloc and fs_size attributes. + * initializes the fileset's pathname attribute, and optionally the + * fileset_cached, fileset_reuse, fileset_prealloc and fileset_size attributes. * */ static fileset_t * parser_fileset_define_common(cmd_t *cmd) { fileset_t *fileset; - char *name; + avd_t name; attr_t *attr; - var_string_t pathname; + avd_t pathname; /* Get the name of the file */ if (attr = get_attr(cmd, FSA_NAME)) { - name = *attr->attr_string; + name = attr->attr_avd; } else { filebench_log(LOG_ERROR, "define fileset: file or fileset specifies no name"); @@ -1750,7 +2261,7 @@ parser_fileset_define_common(cmd_t *cmd) if ((fileset = fileset_define(name)) == NULL) { filebench_log(LOG_ERROR, "define file: failed to instantiate file %s\n", - name); + avd_get_str(name)); return (NULL); } @@ -1770,36 +2281,37 @@ parser_fileset_define_common(cmd_t *cmd) fileset->fs_path = pathname; /* Should we prealloc in parallel? */ - if (attr = get_attr_bool(cmd, FSA_PARALLOC)) { - fileset->fs_paralloc = attr->attr_integer; - } else - fileset->fs_paralloc = integer_alloc(0); + if (attr = get_attr_bool(cmd, FSA_PARALLOC)) + fileset->fs_paralloc = attr->attr_avd; + else + fileset->fs_paralloc = avd_bool_alloc(FALSE); /* Should we reuse the existing file? */ if (attr = get_attr_bool(cmd, FSA_REUSE)) { - fileset->fs_reuse = attr->attr_integer; + fileset->fs_reuse = attr->attr_avd; } else - fileset->fs_reuse = integer_alloc(0); + fileset->fs_reuse = avd_bool_alloc(FALSE); /* Should we leave in cache? */ if (attr = get_attr_bool(cmd, FSA_CACHED)) { - fileset->fs_cached = attr->attr_integer; + fileset->fs_cached = attr->attr_avd; } else - fileset->fs_cached = integer_alloc(0); + fileset->fs_cached = avd_bool_alloc(FALSE); /* Get the mean or absolute size of the file */ if (attr = get_attr_integer(cmd, FSA_SIZE)) { - fileset->fs_size = attr->attr_integer; + fileset->fs_size = attr->attr_avd; } else - fileset->fs_size = integer_alloc(0); + fileset->fs_size = avd_int_alloc(0); return (fileset); } /* * Calls parser_fileset_define_common() to allocate a fileset with - * one entry and optionally the fs_prealloc. Sets the fs_preallocpercent, - * fs_entries, fs_dirwidth, fs_dirgamma, and fs_sizegamma attributes + * one entry and optionally the fileset_prealloc. Sets the + * fileset_preallocpercent, fileset_entries, fileset_dirwidth, + * fileset_dirgamma, and fileset_sizegamma attributes * to appropriate values for emulating the old "fileobj" entity */ static void @@ -1819,39 +2331,40 @@ parser_file_define(cmd_t *cmd) fileset->fs_attrs = FILESET_IS_FILE; /* Set the size of the fileset to 1 */ - fileset->fs_entries = integer_alloc(1); + fileset->fs_entries = avd_int_alloc(1); /* Set the mean dir width to more than 1 */ - fileset->fs_dirwidth = integer_alloc(10); + fileset->fs_dirwidth = avd_int_alloc(10); /* Set the dir and size gammas to 0 */ - fileset->fs_dirgamma = integer_alloc(0); - fileset->fs_sizegamma = integer_alloc(0); + fileset->fs_dirgamma = avd_int_alloc(0); + fileset->fs_sizegamma = avd_int_alloc(0); /* if a raw device, all done */ if (fileset_checkraw(fileset)) { filebench_log(LOG_VERBOSE, "File %s/%s is RAW device", - *fileset->fs_path, fileset->fs_name); + avd_get_str(fileset->fs_path), + avd_get_str(fileset->fs_name)); return; } /* Does file need to be preallocated? */ if (attr = get_attr_bool(cmd, FSA_PREALLOC)) { /* yes */ - fileset->fs_prealloc = attr->attr_integer; - fileset->fs_preallocpercent = integer_alloc(100); + fileset->fs_prealloc = attr->attr_avd; + fileset->fs_preallocpercent = avd_int_alloc(100); } else { /* no */ - fileset->fs_prealloc = integer_alloc(0); - fileset->fs_preallocpercent = integer_alloc(0); + fileset->fs_prealloc = avd_bool_alloc(FALSE); + fileset->fs_preallocpercent = avd_int_alloc(0); } } /* * Calls parser_fileset_define_common() to allocate a fileset with the - * supplied name and initializes the fileset's fs_preallocpercent, - * fs_prealloc, fs_entries, fs_dirwidth, fs_dirgamma, and fs_sizegamma - * attributes. + * supplied name and initializes the fileset's fileset_preallocpercent, + * fileset_prealloc, fileset_entries, fileset_dirwidth, fileset_dirgamma, + * and fileset_sizegamma attributes. */ static void parser_fileset_define(cmd_t *cmd) @@ -1870,54 +2383,82 @@ parser_fileset_define(cmd_t *cmd) if (fileset_checkraw(fileset)) { filebench_log(LOG_ERROR, "Fileset %s/%s: Cannot create a fileset on a RAW device", - *fileset->fs_path, fileset->fs_name); + avd_get_str(fileset->fs_path), + avd_get_str(fileset->fs_name)); filebench_shutdown(0); return; } /* How much should we preallocate? */ if ((attr = get_attr_integer(cmd, FSA_PREALLOC)) && - attr->attr_integer) { - fileset->fs_preallocpercent = attr->attr_integer; - } else if (attr && !attr->attr_integer) { - fileset->fs_preallocpercent = integer_alloc(100); + attr->attr_avd) { + if (AVD_IS_RANDOM(attr->attr_avd)) { + filebench_log(LOG_ERROR, + "define fileset: Prealloc attr cannot be random"); + filebench_shutdown(1); + } + fileset->fs_preallocpercent = attr->attr_avd; + } else if (attr && !attr->attr_avd) { + fileset->fs_preallocpercent = avd_int_alloc(100); } else { - fileset->fs_preallocpercent = integer_alloc(0); + fileset->fs_preallocpercent = avd_int_alloc(0); } /* Should we preallocate? */ if (attr = get_attr_bool(cmd, FSA_PREALLOC)) { - fileset->fs_prealloc = attr->attr_integer; + fileset->fs_prealloc = attr->attr_avd; } else - fileset->fs_prealloc = integer_alloc(0); + fileset->fs_prealloc = avd_bool_alloc(FALSE); /* Get the number of files in the fileset */ if (attr = get_attr_integer(cmd, FSA_ENTRIES)) { - fileset->fs_entries = attr->attr_integer; + fileset->fs_entries = attr->attr_avd; } else { filebench_log(LOG_ERROR, "Fileset has zero entries"); - fileset->fs_entries = integer_alloc(0); + fileset->fs_entries = avd_int_alloc(0); } /* Get the mean dir width of the fileset */ if (attr = get_attr_integer(cmd, FSA_DIRWIDTH)) { - fileset->fs_dirwidth = attr->attr_integer; + fileset->fs_dirwidth = attr->attr_avd; } else { filebench_log(LOG_ERROR, "Fileset has zero directory width"); - fileset->fs_dirwidth = integer_alloc(0); + fileset->fs_dirwidth = avd_int_alloc(0); } - /* Get the gamma value for dir width distributions */ + /* Get the random variable for dir depth, if supplied */ + if (attr = get_attr_integer(cmd, FSA_DIRDEPTHRV)) { + if (!AVD_IS_RANDOM(attr->attr_avd)) { + filebench_log(LOG_ERROR, + "Define fileset: dirdepthrv must be random var"); + filebench_shutdown(1); + } + fileset->fs_dirdepthrv = attr->attr_avd; + } else { + fileset->fs_dirdepthrv = NULL; + } + + /* Get the gamma value for dir depth distributions */ if (attr = get_attr_integer(cmd, FSA_DIRGAMMA)) { - fileset->fs_dirgamma = attr->attr_integer; + if (AVD_IS_RANDOM(attr->attr_avd)) { + filebench_log(LOG_ERROR, + "Define fileset: dirgamma attr cannot be random"); + filebench_shutdown(1); + } + fileset->fs_dirgamma = attr->attr_avd; } else - fileset->fs_dirgamma = integer_alloc(1500); + fileset->fs_dirgamma = avd_int_alloc(1500); /* Get the gamma value for dir width distributions */ if (attr = get_attr_integer(cmd, FSA_FILESIZEGAMMA)) { - fileset->fs_sizegamma = attr->attr_integer; + if (AVD_IS_RANDOM(attr->attr_avd)) { + filebench_log(LOG_ERROR, + "Define fileset: filesizegamma cannot be random"); + filebench_shutdown(1); + } + fileset->fs_sizegamma = attr->attr_avd; } else - fileset->fs_sizegamma = integer_alloc(1500); + fileset->fs_sizegamma = avd_int_alloc(1500); } /* @@ -1972,6 +2513,11 @@ parser_fileset_create(cmd_t *cmd) { if (!filecreate_done) { filecreate_done = 1; + + /* initialize the random number system first */ + randdist_init(); + + /* create all the filesets */ if (fileset_createset(NULL) != 0) { filebench_log(LOG_ERROR, "Failed to create filesets"); filebench_shutdown(1); @@ -2081,7 +2627,7 @@ parser_run(cmd_t *cmd) static void parser_run_variable(cmd_t *cmd) { - vinteger_t *integer = var_ref_integer(cmd->cmd_tgt1); + avd_t integer = var_ref_attr(cmd->cmd_tgt1); int runtime; if (integer == NULL) { @@ -2090,7 +2636,7 @@ parser_run_variable(cmd_t *cmd) return; } - runtime = *integer; + runtime = avd_get_int(integer); /* check for startup errors */ if (filebench_shm->f_abort) @@ -2199,13 +2745,35 @@ parser_sleep(cmd_t *cmd) } /* + * used by the set command to set the integer part of a regular + * variable, or the appropriate field of a random variable + */ +static void +parser_set_integer(char *name, fbint_t integer) +{ + var_assign_integer(name, integer); +} + +/* + * used by the set command to set the integer part of a regular + * variable from another variable, or the appropriate field of a + * random variable from another variable + */ +static void +parser_set_var(char *dst_name, char *src_name) +{ + var_assign_var(dst_name, src_name); +} + + +/* * Same as parser_sleep, except the sleep time is obtained from a variable * whose name is passed to it as an argument on the command line. */ static void parser_sleep_variable(cmd_t *cmd) { - vinteger_t *integer = var_ref_integer(cmd->cmd_tgt1); + avd_t integer = var_ref_attr(cmd->cmd_tgt1); int sleeptime; if (integer == NULL) { @@ -2214,7 +2782,7 @@ parser_sleep_variable(cmd_t *cmd) return; } - sleeptime = *integer; + sleeptime = avd_get_int(integer); /* check for startup errors */ if (filebench_shm->f_abort) @@ -2575,6 +3143,205 @@ parser_abort(int arg) } /* + * define a random variable and initialize the distribution parameters + */ +static void +parser_randvar_define(cmd_t *cmd) +{ + var_t *var; + randdist_t *rndp; + attr_t *attr; + char *name; + + /* Get the name for the random variable */ + if (attr = get_attr(cmd, FSA_NAME)) { + name = avd_get_str(attr->attr_avd); + } else { + filebench_log(LOG_ERROR, + "define randvar: no name specified"); + return; + } + + if ((var = var_define_randvar(name)) == NULL) { + filebench_log(LOG_ERROR, + "define randvar: failed for random variable %s", + name); + return; + } + + rndp = var->var_val.randptr; + rndp->rnd_type = 0; + + /* Get the source of the random numbers */ + if (attr = get_attr_integer(cmd, FSA_RANDSRC)) { + int randsrc = (int)avd_get_int(attr->attr_avd); + + switch (randsrc) { + case FSV_URAND: + rndp->rnd_type |= RAND_SRC_URANDOM; + break; + case FSV_RAND48: + rndp->rnd_type |= RAND_SRC_GENERATOR; + break; + } + } else { + /* default to rand48 random number generator */ + rndp->rnd_type |= RAND_SRC_GENERATOR; + } + + /* Get the min value of the random distribution */ + if (attr = get_attr_integer(cmd, FSA_RANDMIN)) + rndp->rnd_min = attr->attr_avd; + else + rndp->rnd_min = avd_int_alloc(0); + + /* Get the mean value of the random distribution */ + if (attr = get_attr_integer(cmd, FSA_RANDMEAN)) + rndp->rnd_mean = attr->attr_avd; + else + rndp->rnd_mean = avd_int_alloc(0); + + /* Get the roundoff value for the random distribution */ + if (attr = get_attr_integer(cmd, FSA_RANDROUND)) + rndp->rnd_round = attr->attr_avd; + else + rndp->rnd_round = avd_int_alloc(0); + + /* Get a tablular probablility distribution if there is one */ + if (attr = get_attr(cmd, FSA_RANDTABLE)) { + rndp->rnd_probtabs = (probtabent_t *)(attr->attr_obj); + rndp->rnd_type |= RAND_TYPE_TABLE; + + /* no need for the rest of the attributes */ + return; + } else { + rndp->rnd_probtabs = NULL; + } + + /* Get the type for the random variable */ + if (attr = get_attr(cmd, FSA_TYPE)) { + int disttype = (int)avd_get_int(attr->attr_avd); + + switch (disttype) { + case FSV_RANDUNI: + rndp->rnd_type |= RAND_TYPE_UNIFORM; + break; + case FSA_RANDGAMMA: + rndp->rnd_type |= RAND_TYPE_GAMMA; + break; + case FSV_RANDTAB: + filebench_log(LOG_ERROR, + "Table distribution type without prob table"); + break; + } + } else { + /* default to gamma distribution type */ + rndp->rnd_type |= RAND_TYPE_GAMMA; + } + + /* Get the seed for the random variable */ + if (attr = get_attr_integer(cmd, FSA_RANDSEED)) + rndp->rnd_seed = attr->attr_avd; + else + rndp->rnd_seed = avd_int_alloc(0); + + /* Get the gamma value of the random distribution */ + if (attr = get_attr_integer(cmd, FSA_RANDGAMMA)) + rndp->rnd_gamma = attr->attr_avd; + else + rndp->rnd_gamma = avd_int_alloc(1500); +} + +/* + * Set a specified random distribution parameter in a random variable. + */ +static void +parser_randvar_set(cmd_t *cmd) +{ + var_t *src_var, *randvar; + randdist_t *rndp; + avd_t value; + + if ((randvar = var_find_randvar(cmd->cmd_tgt1)) == NULL) { + filebench_log(LOG_ERROR, + "set randvar: failed", + cmd->cmd_tgt1); + return; + } + + rndp = randvar->var_val.randptr; + value = cmd->cmd_attr_list->attr_avd; + + switch (cmd->cmd_qty) { + case FSS_TYPE: + { + int disttype = (int)avd_get_int(value); + + printf("parser_randvar_set: changing type to %d\n", + disttype); + rndp->rnd_type &= (~RAND_TYPE_MASK); + + switch (disttype) { + case FSV_RANDUNI: + rndp->rnd_type |= RAND_TYPE_UNIFORM; + break; + case FSA_RANDGAMMA: + rndp->rnd_type |= RAND_TYPE_GAMMA; + break; + case FSV_RANDTAB: + rndp->rnd_type |= RAND_TYPE_TABLE; + break; + } + break; + } + + case FSS_SRC: + { + int randsrc = (int)avd_get_int(value); + + printf("parser_randvar_set: changing source to %d\n", + randsrc); + + rndp->rnd_type &= + (~(RAND_SRC_URANDOM | RAND_SRC_GENERATOR)); + + switch (randsrc) { + case FSV_URAND: + rndp->rnd_type |= RAND_SRC_URANDOM; + break; + case FSV_RAND48: + rndp->rnd_type |= RAND_SRC_GENERATOR; + break; + } + break; + } + + case FSS_SEED: + rndp->rnd_seed = value; + break; + + case FSS_GAMMA: + rndp->rnd_gamma = value; + break; + + case FSS_MEAN: + rndp->rnd_mean = value; + break; + + case FSS_MIN: + rndp->rnd_min = value; + break; + + case FSS_ROUND: + rndp->rnd_round = value; + break; + + default: + filebench_log(LOG_ERROR, "setrandvar: undefined attribute"); + } +} + +/* * alloc_cmd() allocates the required resources for a cmd_t. On failure, a * filebench_log is issued and NULL is returned. */ @@ -2622,12 +3389,29 @@ alloc_attr() } /* + * Allocates a probtabent_t structure and zeros it. Returns NULL on failure, or + * a pointer to the probtabent_t. + */ +static probtabent_t * +alloc_probtabent(void) +{ + probtabent_t *rte; + + if ((rte = malloc(sizeof (probtabent_t))) == NULL) { + return (NULL); + } + + (void) memset(rte, 0, sizeof (probtabent_t)); + return (rte); +} + +/* * Searches the attribute list for the command for the named attribute type. * The attribute list is created by the parser from the list of attributes * supplied with certain commands, such as the define and flowop commands. * Returns a pointer to the attribute structure if the named attribute is * found, otherwise returns NULL. If the attribute includes a parameter list, - * the list is converted to a string and stored in the attr_string field of + * the list is converted to a string and stored in the attr_avd field of * the returned attr_t struct. */ static attr_t * @@ -2643,7 +3427,7 @@ get_attr(cmd_t *cmd, int64_t name) "attr %d = %d %llx?", attr->attr_name, name, - attr->attr_integer); + attr->attr_avd); if (attr->attr_name == name) rtn = attr; @@ -2656,7 +3440,7 @@ get_attr(cmd_t *cmd, int64_t name) filebench_log(LOG_DEBUG_SCRIPT, "attr is param list"); string = parser_list2string(rtn->attr_param_list); if (string != NULL) { - rtn->attr_string = string_alloc(string); + rtn->attr_avd = avd_str_alloc(string); filebench_log(LOG_DEBUG_SCRIPT, "attr string %s", string); } @@ -2667,7 +3451,7 @@ get_attr(cmd_t *cmd, int64_t name) /* * Similar to get_attr, but converts the parameter string supplied with the - * named attribute to an integer and stores the integer in the attr_integer + * named attribute to an integer and stores the integer in the attr_avd * portion of the returned attr_t struct. */ static attr_t * @@ -2685,16 +3469,15 @@ get_attr_integer(cmd_t *cmd, int64_t name) if (rtn == NULL) return (NULL); - if (rtn->attr_param_list) { - rtn->attr_integer = parser_list2integer(rtn->attr_param_list); - } + if (rtn->attr_param_list) + rtn->attr_avd = parser_list2avd(rtn->attr_param_list); return (rtn); } /* * Similar to get_attr, but converts the parameter string supplied with the - * named attribute to an integer and stores the integer in the attr_integer + * named attribute to an integer and stores the integer in the attr_avd * portion of the returned attr_t struct. If no parameter string is supplied * then it defaults to TRUE (1). */ @@ -2714,9 +3497,18 @@ get_attr_bool(cmd_t *cmd, int64_t name) return (NULL); if (rtn->attr_param_list) { - rtn->attr_integer = parser_list2integer(rtn->attr_param_list); - } else if (rtn->attr_integer == 0) { - rtn->attr_integer = integer_alloc(1); + rtn->attr_avd = parser_list2avd(rtn->attr_param_list); + + } else if (rtn->attr_avd == NULL) { + rtn->attr_avd = avd_bool_alloc(TRUE); + } + + /* boolean attributes cannot point to random variables */ + if (AVD_IS_RANDOM(rtn->attr_avd)) { + filebench_log(LOG_ERROR, + "define flowop: Boolean attr %s cannot be random", name); + filebench_shutdown(1); + return (NULL); } return (rtn); diff --git a/usr/src/cmd/filebench/common/parser_lex.l b/usr/src/cmd/filebench/common/parser_lex.l index 78b3a94718..064b5eb453 100644 --- a/usr/src/cmd/filebench/common/parser_lex.l +++ b/usr/src/cmd/filebench/common/parser_lex.l @@ -25,7 +25,7 @@ */ %{ -#pragma ident "%Z%%M% %I% %E% SMI" +#pragma ident "%Z%%M% %I% %E% SMI" %} %{ @@ -92,6 +92,7 @@ directory { return FSE_DIRECTORY; } command { return FSE_COMMAND; } process[es]* { return FSE_PROC; } thread { return FSE_THREAD; } +randvar { return FSE_RAND; } clear { return FSE_CLEAR; } snap { return FSE_SNAP; } dump { return FSE_DUMP; } @@ -101,9 +102,10 @@ mode { return FSE_MODE; } cached { return FSA_CACHED; } dirwidth { return FSA_DIRWIDTH; } +dirdepthrv { return FSA_DIRDEPTHRV; } dirgamma { return FSA_DIRGAMMA; } namelength { return FSA_NAMELENGTH; } -filesize { return FSA_FILESIZE; } +filesize { return FSA_SIZE; } filesizegamma { return FSA_FILESIZEGAMMA; } directio { return FSA_DIRECTIO; } dsync { return FSA_DSYNC; } @@ -136,6 +138,26 @@ highwater { return FSA_HIGHWATER; } alldone { return FSA_ALLDONE; } firstdone { return FSA_FIRSTDONE; } timeout { return FSA_TIMEOUT; } +type { return FSA_TYPE; } +seed { return FSA_RANDSEED; } +gamma { return FSA_RANDGAMMA; } +mean { return FSA_RANDMEAN; } +min { return FSA_RANDMIN; } +round { return FSA_RANDROUND; } +randsrc { return FSA_RANDSRC; } +randtable { return FSA_RANDTABLE; } +uniform { return FSV_RANDUNI; } +tabular { return FSV_RANDTAB; } +"."type { return FSS_TYPE; } +"."seed { return FSS_SEED; } +"."gamma { return FSS_GAMMA; } +"."mean { return FSS_MEAN; } +"."min { return FSS_MIN; } +"."round { return FSS_ROUND; } +"."randsrc { return FSS_SRC; } +urandom { return FSV_URAND; } +rand48 { return FSV_RAND48; } + <INITIAL>\" { BEGIN WHITESTRINGSTATE; @@ -228,24 +250,42 @@ timeout { return FSA_TIMEOUT; } return FSV_VAL_INT; } -<INITIAL>true|false { - if (strcmp(yytext, "true") == 0) - yylval.bval = 1; - else - yylval.bval = 0; +<INITIAL>true { + yylval.bval = TRUE; return FSV_VAL_BOOLEAN; } +<INITIAL>false { + yylval.bval = FALSE; + return FSV_VAL_BOOLEAN; + } - -$[({A-Za-z][A-Za-z0-9._]*[A-Za-z0-9][)}]* { +$[({A-Za-z][A-Za-z0-9_]*[A-Za-z0-9][)}]* { if ((yylval.sval = strdup(yytext)) == NULL) { yyerror("Out of memory"); filebench_shutdown(E_ERROR); } + return FSV_VARIABLE; } + +$[({A-Za-z][A-Za-z0-9_]*"."[A-Za-z0-9][)}]* { + int backtrack; + + if ((backtrack = + var_is_set4_randvar(yytext)) != 0) + yyless(yyleng - backtrack); + + if ((yylval.sval = strdup(yytext)) == NULL) { + yyerror("Out of memory"); + filebench_shutdown(E_ERROR); + } + + return FSV_RANDVAR; + } + + <INITIAL>[/A-Za-z-][/A-Za-z0-9._-]* { if ((yylval.sval = strdup(yytext)) == NULL) { yyerror("Out of memory"); @@ -254,6 +294,7 @@ $[({A-Za-z][A-Za-z0-9._]*[A-Za-z0-9][)}]* { return FSV_STRING; } + . { yyerror("Illegal character"); } diff --git a/usr/src/cmd/filebench/common/parsertypes.h b/usr/src/cmd/filebench/common/parsertypes.h index a7ceaca379..d0d8db0842 100644 --- a/usr/src/cmd/filebench/common/parsertypes.h +++ b/usr/src/cmd/filebench/common/parsertypes.h @@ -19,7 +19,7 @@ * 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. */ @@ -47,17 +47,17 @@ typedef unsigned char uchar_t; #define FSE_SYSTEM 1 typedef struct list { - struct list *list_next; - var_string_t list_string; - var_integer_t list_integer; + struct list *list_next; + avd_t list_string; + avd_t list_integer; } list_t; typedef struct attr { - int attr_name; + int attr_name; struct attr *attr_next; - var_string_t attr_string; - var_integer_t attr_integer; + avd_t attr_avd; list_t *attr_param_list; + void *attr_obj; } attr_t; typedef struct cmd { diff --git a/usr/src/cmd/filebench/common/procflow.c b/usr/src/cmd/filebench/common/procflow.c index 2a7e412c58..9bf3bba057 100644 --- a/usr/src/cmd/filebench/common/procflow.c +++ b/usr/src/cmd/filebench/common/procflow.c @@ -233,13 +233,14 @@ procflow_create_all_procs(void) int ret = 0; while (procflow) { - int i; + int i, instances; - filebench_log(LOG_INFO, "Starting %lld %s instances", - *(procflow->pf_instances), procflow->pf_name); + instances = (int)avd_get_int(procflow->pf_instances); + filebench_log(LOG_INFO, "Starting %d %s instances", + instances, procflow->pf_name); /* Create instances of procflow */ - for (i = 0; (i < *procflow->pf_instances) && (ret == 0); i++) { + for (i = 0; (i < instances) && (ret == 0); i++) { procflow_t *newproc; /* Create processes */ @@ -305,7 +306,7 @@ procflow_exec(char *name, int instance) filebench_log(LOG_DEBUG_IMPL, "nice = %llx", procflow->pf_nice); - proc_nice = *procflow->pf_nice; + proc_nice = avd_get_int(procflow->pf_nice); filebench_log(LOG_DEBUG_IMPL, "Setting pri of %s-%d to %d", name, instance, nice(proc_nice + 10)); @@ -414,7 +415,7 @@ procflow_init(void) filebench_log(LOG_DEBUG_IMPL, "procflow_init %s, %lld", - procflow->pf_name, *(procflow->pf_instances)); + procflow->pf_name, avd_get_int(procflow->pf_instances)); #ifdef USE_PROCESS_MODEL if ((ret = pthread_cond_init(&procflow_procs_created, NULL)) != 0) @@ -707,7 +708,7 @@ procflow_define_common(procflow_t **list, char *name, * parser_proc_define(). */ procflow_t * -procflow_define(char *name, procflow_t *inherit, var_integer_t instances) +procflow_define(char *name, procflow_t *inherit, avd_t instances) { procflow_t *procflow; diff --git a/usr/src/cmd/filebench/common/procflow.h b/usr/src/cmd/filebench/common/procflow.h index 7b8134be65..f60450a626 100644 --- a/usr/src/cmd/filebench/common/procflow.h +++ b/usr/src/cmd/filebench/common/procflow.h @@ -19,7 +19,7 @@ * 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. */ @@ -40,19 +40,18 @@ extern "C" { typedef struct procflow { char pf_name[128]; int pf_instance; - var_integer_t pf_instances; + avd_t pf_instances; int pf_running; struct procflow *pf_next; pid_t pf_pid; pthread_t pf_tid; struct threadflow *pf_threads; int pf_attrs; - var_integer_t pf_nice; + avd_t pf_nice; flowstat_t pf_stats; } procflow_t; -procflow_t *procflow_define(char *name, procflow_t *inherit, - var_integer_t instances); +procflow_t *procflow_define(char *name, procflow_t *inherit, avd_t instances); int procflow_init(void); void procflow_shutdown(void); int procflow_exec(char *name, int instance); diff --git a/usr/src/cmd/filebench/common/stats.c b/usr/src/cmd/filebench/common/stats.c index 1b23bc21c4..95af3f2165 100644 --- a/usr/src/cmd/filebench/common/stats.c +++ b/usr/src/cmd/filebench/common/stats.c @@ -67,7 +67,7 @@ static kstat_t *sysinfo_ksp = NULL; * a local pointer to the sysinfo kstat, and returns the sum of user and * kernel time for all the cpus. */ -static vinteger_t +static fbint_t kstats_read_cpu(void) { int ncpus; @@ -134,7 +134,7 @@ kstats_read_cpu(void) #else /* HAVE_LIBKSTAT */ #ifdef HAVE_PROC_STAT static FILE *statfd = 0; -vinteger_t +fbint_t kstats_read_cpu(void) { /* @@ -166,7 +166,7 @@ kstats_read_cpu(void) } #else /* HAVE_PROC_STAT */ -vinteger_t +fbint_t kstats_read_cpu(void) { return (0); @@ -238,7 +238,7 @@ gl_stats_ohead(void) } /* - * Places the value represented by "name" into the var_integer field of the + * Places the value represented by "name" into the var_val.integer field of the * supplied var_t. Compares the supplied "name" with a set of predefined * names and calculates the value from the appropriate globalstats field(s). */ @@ -255,86 +255,117 @@ stats_findvar(var_t *var, char *name) globalstats = malloc(FLOW_TYPES * sizeof (flowstat_t)); if (strcmp(name, "iocount") == 0) { - var->var_integer = iostat->fs_count + - aiostat->fs_count; + fbint_t stat; + + stat = iostat->fs_count + aiostat->fs_count; + VAR_SET_INT(var, stat); filebench_log(LOG_DEBUG_IMPL, "reading stats %s = %lld", - name, var->var_integer); + name, stat); return (var); } if (strcmp(name, "iorate") == 0) { + fbint_t stat; + /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */ - var->var_integer = (iostat->fs_count + aiostat->fs_count) / + stat = (iostat->fs_count + aiostat->fs_count) / ((globalstats->fs_etime - globalstats->fs_stime) / FSECS); + VAR_SET_INT(var, stat); return (var); } if (strcmp(name, "ioreadrate") == 0) { + fbint_t stat; + /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */ - var->var_integer = (iostat->fs_rcount + aiostat->fs_rcount) / + stat = (iostat->fs_rcount + aiostat->fs_rcount) / ((globalstats->fs_etime - globalstats->fs_stime) / FSECS); + VAR_SET_INT(var, stat); return (var); } if (strcmp(name, "iowriterate") == 0) { + fbint_t stat; + /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */ - var->var_integer = (iostat->fs_wcount + aiostat->fs_wcount) / + stat = (iostat->fs_wcount + aiostat->fs_wcount) / ((globalstats->fs_etime - globalstats->fs_stime) / FSECS); + VAR_SET_INT(var, stat); return (var); } if (strcmp(name, "iobandwidth") == 0) { + fbint_t stat; + /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */ - var->var_integer = + stat = ((iostat->fs_bytes + aiostat->fs_bytes) / (1024 * 1024)) / ((globalstats->fs_etime - globalstats->fs_stime) / FSECS); + VAR_SET_INT(var, stat); return (var); } if (strcmp(name, "iolatency") == 0) { - var->var_integer = iostat->fs_count ? - iostat->fs_mstate[FLOW_MSTATE_LAT] / + fbint_t stat; + + stat = iostat->fs_count ? iostat->fs_mstate[FLOW_MSTATE_LAT] / (iostat->fs_count * 1000UL) : 0; + VAR_SET_INT(var, stat); return (var); } if (strcmp(name, "iocpu") == 0) { - var->var_integer = (iostat->fs_count + aiostat->fs_count) ? + fbint_t stat; + + stat = (iostat->fs_count + aiostat->fs_count) ? (iostat->fs_mstate[FLOW_MSTATE_CPU] + aiostat->fs_mstate[FLOW_MSTATE_CPU]) / ((iostat->fs_count + aiostat->fs_count) * 1000UL) : 0; + VAR_SET_INT(var, stat); return (var); } if (strcmp(name, "oheadcpu") == 0) { - var->var_integer = (iostat->fs_count + aiostat->fs_count) ? + fbint_t stat; + + stat = (iostat->fs_count + aiostat->fs_count) ? io_stats_ohead() / ((iostat->fs_count + aiostat->fs_count) * 1000UL) : 0; + VAR_SET_INT(var, stat); return (var); } if (strcmp(name, "iowait") == 0) { - var->var_integer = iostat->fs_count ? + fbint_t stat; + + stat = iostat->fs_count ? iostat->fs_mstate[FLOW_MSTATE_WAIT] / (iostat->fs_count * 1000UL) : 0; + VAR_SET_INT(var, stat); return (var); } if (strcmp(name, "syscpu") == 0) { + fbint_t stat; + /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */ - var->var_integer = glstat->fs_syscpu / 1000.0; + stat = glstat->fs_syscpu / 1000.0; + VAR_SET_INT(var, stat); return (var); } if (strcmp(name, "iocpusys") == 0) { - var->var_integer = (iostat->fs_count + aiostat->fs_count) ? + fbint_t stat; + + stat = (iostat->fs_count + aiostat->fs_count) ? iostat->fs_syscpu / ((iostat->fs_count + aiostat->fs_count) * 1000UL) : 0; + VAR_SET_INT(var, stat); return (var); } @@ -421,13 +452,12 @@ stats_snap(void) while (flowop) { flowop_t *flowop_master; - if (flowop->fo_instance == FLOW_MASTER) { + if (flowop->fo_instance <= FLOW_DEFINITION) { flowop = flowop->fo_next; continue; } - flowop_master = flowop_find_one(flowop->fo_name, - FLOW_MASTER); + flowop_master = flowop_find_one(flowop->fo_name, FLOW_MASTER); /* Roll up per-flowop into global stats */ stats_add(&globalstats[flowop->fo_type], diff --git a/usr/src/cmd/filebench/common/threadflow.c b/usr/src/cmd/filebench/common/threadflow.c index 11351fdf17..4feaa3147b 100644 --- a/usr/src/cmd/filebench/common/threadflow.c +++ b/usr/src/cmd/filebench/common/threadflow.c @@ -82,12 +82,15 @@ threadflow_usage(void) static int threadflow_createthread(threadflow_t *threadflow) { + fbint_t memsize; + memsize = avd_get_int(threadflow->tf_memsize); + threadflow->tf_constmemsize = memsize; + filebench_log(LOG_DEBUG_SCRIPT, "Creating thread %s, memory = %ld", - threadflow->tf_name, - *threadflow->tf_memsize); + threadflow->tf_name, memsize); if (threadflow->tf_attrs & THREADFLOW_USEISM) - filebench_shm->shm_required += (*threadflow->tf_memsize); + filebench_shm->shm_required += memsize; if (pthread_create(&threadflow->tf_tid, NULL, (void *(*)(void*))flowop_start, threadflow) != 0) { @@ -161,14 +164,15 @@ threadflow_init(procflow_t *procflow) while (threadflow) { threadflow_t *newthread; + int instances; int i; + instances = avd_get_int(threadflow->tf_instances); filebench_log(LOG_VERBOSE, "Starting %lld %s threads", - *(threadflow->tf_instances), - threadflow->tf_name); + instances, threadflow->tf_name); - for (i = 1; i < *threadflow->tf_instances; i++) { + for (i = 1; i < instances; i++) { /* Create threads */ newthread = threadflow_define_common(procflow, @@ -257,9 +261,8 @@ threadflow_delete(threadflow_t **threadlist, threadflow_t *threadflow, threadflow->tf_name, threadflow->tf_instance); - if (threadflow->tf_attrs & THREADFLOW_USEISM) { - filebench_shm->shm_required -= (*threadflow->tf_memsize); - } + if (threadflow->tf_attrs & THREADFLOW_USEISM) + filebench_shm->shm_required -= threadflow->tf_constmemsize; if (threadflow == *threadlist) { /* First on list */ @@ -442,7 +445,7 @@ threadflow_define_common(procflow_t *procflow, char *name, */ threadflow_t * threadflow_define(procflow_t *procflow, char *name, - threadflow_t *inherit, var_integer_t instances) + threadflow_t *inherit, avd_t instances) { threadflow_t *threadflow; diff --git a/usr/src/cmd/filebench/common/threadflow.h b/usr/src/cmd/filebench/common/threadflow.h index 3e5feefe09..119c368a1b 100644 --- a/usr/src/cmd/filebench/common/threadflow.h +++ b/usr/src/cmd/filebench/common/threadflow.h @@ -80,11 +80,12 @@ typedef struct threadflow { struct procflow *tf_process; /* Back pointer to process */ pthread_t tf_tid; /* Thread id */ pthread_mutex_t tf_lock; /* Mutex around threadflow */ - var_integer_t tf_instances; /* Number of instances for this flow */ + avd_t tf_instances; /* Number of instances for this flow */ struct threadflow *tf_next; /* Next on proc list */ struct flowop *tf_ops; /* Flowop list */ caddr_t tf_mem; /* Private Memory */ - var_integer_t tf_memsize; /* Private Memory size */ + avd_t tf_memsize; /* Private Memory size attribute */ + fbint_t tf_constmemsize; /* constant copy of memory size */ int tf_fd[THREADFLOW_MAXFD + 1]; /* Thread local fd's */ filesetentry_t *tf_fse[THREADFLOW_MAXFD + 1]; /* Thread local files */ int tf_fdrotor; /* Rotating fd within set */ @@ -104,8 +105,8 @@ typedef struct threadflow { /* Thread attrs */ #define THREADFLOW_DEFAULTMEM 1024*1024LL; -threadflow_t *threadflow_define(procflow_t *, char *name, threadflow_t *inherit, - var_integer_t instances); +threadflow_t *threadflow_define(procflow_t *, char *name, + threadflow_t *inherit, avd_t instances); threadflow_t *threadflow_find(threadflow_t *, char *); int threadflow_init(procflow_t *); void flowop_start(threadflow_t *threadflow); diff --git a/usr/src/cmd/filebench/common/vars.c b/usr/src/cmd/filebench/common/vars.c index 6145547cff..ae00ee53f9 100644 --- a/usr/src/cmd/filebench/common/vars.c +++ b/usr/src/cmd/filebench/common/vars.c @@ -19,7 +19,7 @@ * 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. */ @@ -36,84 +36,466 @@ #include "stats.h" #include "eventgen.h" #include "filebench.h" +#include "fb_random.h" static var_t *var_find_dynamic(char *name); /* - * The filebench variables consist of var_integers (var_integer_t) - * and var_strings (var_string_t), which are pointers to integers and - * strings respectively, and vars (var_t), which are named, typed - * entities which contain either an integer or a string and can be - * placed on a linked list. All three of these objects are allocated + * The filebench variables system has attribute value descriptors (avd_t) + * where an avd contains a boolean, integer, double, string, random + * distribution object ptr, boolean ptr, integer ptr, double ptr, + * string ptr, or variable ptr. The system also has the variables + * themselves, (var_t), which are named, typed entities which can be + * allocated, selected and changed using the "set" command and used in + * attribute assignments. The variables contain either a boolean, an + * integer, a double, a string or pointer to an associated random + * distribution object. Both avd_t and var_t entities are allocated * from interprocess shared memory space. * + * The attribute descriptors implement delayed binding to variable values, + * which is necessary because the values of variables may be changed + * between the time the workload file is loaded and it is actually run, + * either by further "set" commands in the file or from the command line + * interface. For random variables, they actually point to the random + * distribution object, allowing FileBench to invoke the appropriate + * random distribution function on each access to the attribute. However, + * for static attributes, the value is just loaded in the descriptor + * directly, avoiding the need to allocate a variable to hold the static + * value. + * * The routines in this module are used to allocate, locate, and - * manipulate the var_integers, var_strings, and vars. Routines are - * also included to convert between the component strings and integers - * of vars, and var_strings and var_integers. + * manipulate the attribute descriptors, and vars. Routines are + * also included to convert between the component strings, doubles + * and integers of vars, and said components of avd_t. */ /* - * Returns the int pointed to by the supplied var_integer_t "v". + * returns a pointer to a string indicating the type of data contained + * in the supplied attribute variable descriptor. */ -int -integer_isset(var_integer_t v) +static char * +avd_get_type_string(avd_t avd) +{ + switch (avd->avd_type) { + case AVD_INVALID: + return ("uninitialized"); + + case AVD_VAL_BOOL: + return ("boolean value"); + + case AVD_VARVAL_BOOL: + return ("points to boolean in var_t"); + + case AVD_VAL_INT: + return ("integer value"); + + case AVD_VARVAL_INT: + return ("points to integer in var_t"); + + case AVD_VAL_STR: + return ("string"); + + case AVD_VARVAL_STR: + return ("points to string in var_t"); + + case AVD_VAL_DBL: + return ("double float value"); + + case AVD_VARVAL_DBL: + return ("points to double float in var_t"); + + case AVD_IND_VAR: + return ("points to a var_t"); + + case AVD_IND_RANDVAR: + return ("points to var_t's random distribution object"); + + default: + return ("illegal avd type"); + } +} + +/* + * returns a pointer to a string indicating the type of data contained + * in the supplied variable. + */ +static char * +var_get_type_string(var_t *ivp) +{ + switch (ivp->var_type & VAR_TYPE_SET_MASK) { + case VAR_TYPE_BOOL_SET: + return ("boolean"); + + case VAR_TYPE_INT_SET: + return ("integer"); + + case VAR_TYPE_STR_SET: + return ("string"); + + case VAR_TYPE_DBL_SET: + return ("double float"); + + case VAR_TYPE_RAND_SET: + return ("random"); + + default: + return ("empty"); + } +} + +/* + * Returns the fbint_t pointed to by the supplied avd_t "avd". + */ +fbint_t +avd_get_int(avd_t avd) +{ + var_t *ivp; + randdist_t *rndp; + + if (avd == NULL) + return (0); + + switch (avd->avd_type) { + case AVD_VAL_INT: + return (avd->avd_val.intval); + + case AVD_VARVAL_INT: + if (avd->avd_val.intptr) + return (*(avd->avd_val.intptr)); + else + return (0); + + case AVD_IND_VAR: + if ((ivp = avd->avd_val.varptr) == NULL) + return (0); + + if (VAR_HAS_INTEGER(ivp)) + return (ivp->var_val.integer); + + if (VAR_HAS_RANDDIST(ivp)) { + if ((rndp = ivp->var_val.randptr) != NULL) + return ((fbint_t)rndp->rnd_get(rndp)); + } + + filebench_log(LOG_ERROR, + "Attempt to get integer from %s var $%s", + var_get_type_string(ivp), ivp->var_name); + return (0); + + case AVD_IND_RANDVAR: + if ((rndp = avd->avd_val.randptr) == NULL) + return (0); + else + return ((fbint_t)rndp->rnd_get(rndp)); + + default: + filebench_log(LOG_ERROR, + "Attempt to get integer from %s avd", + avd_get_type_string(avd)); + return (0); + } +} + +/* + * Returns the floating point value of a variable pointed to by the + * supplied avd_t "avd". Intended to get the actual (double) value + * supplied by the random variable. + */ +double +avd_get_dbl(avd_t avd) { - if (v == NULL) + var_t *ivp; + randdist_t *rndp; + + if (avd == NULL) + return (0.0); + + switch (avd->avd_type) { + case AVD_VAL_INT: + return ((double)avd->avd_val.intval); + + case AVD_VAL_DBL: + return (avd->avd_val.dblval); + + case AVD_VARVAL_INT: + if (avd->avd_val.intptr) + return ((double)(*(avd->avd_val.intptr))); + else + return (0.0); + + case AVD_VARVAL_DBL: + if (avd->avd_val.dblptr) + return (*(avd->avd_val.dblptr)); + else + return (0.0); + + case AVD_IND_VAR: + ivp = avd->avd_val.varptr; + + if (ivp && VAR_HAS_INTEGER(ivp)) + return ((double)ivp->var_val.integer); + + if (ivp && VAR_HAS_DOUBLE(ivp)) + return (ivp->var_val.dbl_flt); + + if (ivp && VAR_HAS_RANDDIST(ivp)) { + if ((rndp = ivp->var_val.randptr) != NULL) + return (rndp->rnd_get(rndp)); + } + filebench_log(LOG_ERROR, + "Attempt to get double float from %s var $%s", + var_get_type_string(ivp), ivp->var_name); + return (0.0); + + case AVD_IND_RANDVAR: + if ((rndp = avd->avd_val.randptr) == NULL) { + return (0.0); + } else + return (rndp->rnd_get(rndp)); + + default: + filebench_log(LOG_ERROR, + "Attempt to get floating point from %s avd", + avd_get_type_string(avd)); + return (0.0); + } +} + +/* + * Returns the boolean pointed to by the supplied avd_t "avd". + */ +boolean_t +avd_get_bool(avd_t avd) +{ + var_t *ivp; + + if (avd == NULL) return (0); - return (*v); + switch (avd->avd_type) { + case AVD_VAL_BOOL: + return (avd->avd_val.boolval); + + case AVD_VARVAL_BOOL: + if (avd->avd_val.boolptr) + return (*(avd->avd_val.boolptr)); + else + return (FALSE); + + /* for backwards compatibility with old workloads */ + case AVD_VAL_INT: + if (avd->avd_val.intval != 0) + return (TRUE); + else + return (FALSE); + + case AVD_VARVAL_INT: + if (avd->avd_val.intptr) + if (*(avd->avd_val.intptr) != 0) + return (TRUE); + + return (FALSE); + + case AVD_IND_VAR: + if ((ivp = avd->avd_val.varptr) == NULL) + return (0); + + if (VAR_HAS_BOOLEAN(ivp)) + return (ivp->var_val.boolean); + + if (VAR_HAS_INTEGER(ivp)) { + if (ivp->var_val.boolean) + return (TRUE); + else + return (FALSE); + } + + filebench_log(LOG_ERROR, + "Attempt to get boolean from %s var $%s", + var_get_type_string(ivp), ivp->var_name); + return (FALSE); + + default: + filebench_log(LOG_ERROR, + "Attempt to get boolean from %s avd", + avd_get_type_string(avd)); + return (FALSE); + } } /* - * Allocates a var_integer_t from ipc memory space and - * pre-loads it with the vinteger_t "integer". Returns - * the var_integer_t on success, NULL on failure. + * Returns the string pointed to by the supplied avd_t "avd". */ -var_integer_t -integer_alloc(vinteger_t integer) +char * +avd_get_str(avd_t avd) { - var_integer_t rtn; + var_t *ivp; + + if (avd == NULL) + return (NULL); + + switch (avd->avd_type) { + case AVD_VAL_STR: + return (avd->avd_val.strval); + + case AVD_VARVAL_STR: + if (avd->avd_val.strptr) + return (*avd->avd_val.strptr); + else + return (NULL); + + case AVD_IND_VAR: + ivp = avd->avd_val.varptr; + + if (ivp && VAR_HAS_STRING(ivp)) + return (ivp->var_val.string); - if ((rtn = (vinteger_t *)ipc_malloc(FILEBENCH_INTEGER)) == NULL) { - filebench_log(LOG_ERROR, "Alloc integer failed"); + filebench_log(LOG_ERROR, + "Attempt to get string from %s var $%s", + var_get_type_string(ivp), ivp->var_name); + return (NULL); + + default: + filebench_log(LOG_ERROR, + "Attempt to get string from %s avd", + avd_get_type_string(avd)); return (NULL); } +} + +/* + * Allocates a avd_t from ipc memory space. + * logs an error and returns NULL on failure. + */ +static avd_t +avd_alloc_cmn(void) +{ + avd_t rtn; + + if ((rtn = (avd_t)ipc_malloc(FILEBENCH_AVD)) == NULL) + filebench_log(LOG_ERROR, "Avd alloc failed"); + + return (rtn); +} - *rtn = integer; +/* + * pre-loads the allocated avd_t with the boolean_t "bool". + * Returns the avd_t on success, NULL on failure. + */ +avd_t +avd_bool_alloc(boolean_t bool) +{ + avd_t avd; + + if ((avd = avd_alloc_cmn()) == NULL) + return (NULL); + + avd->avd_type = AVD_VAL_BOOL; + avd->avd_val.boolval = bool; + + filebench_log(LOG_DEBUG_IMPL, "Alloc boolean %d", bool); + + return (avd); +} + +/* + * pre-loads the allocated avd_t with the fbint_t "integer". + * Returns the avd_t on success, NULL on failure. + */ +avd_t +avd_int_alloc(fbint_t integer) +{ + avd_t avd; + + if ((avd = avd_alloc_cmn()) == NULL) + return (NULL); + + avd->avd_type = AVD_VAL_INT; + avd->avd_val.intval = integer; filebench_log(LOG_DEBUG_IMPL, "Alloc integer %lld", integer); - return (rtn); + return (avd); +} + +/* + * Gets a avd_t and points it to the var that + * it will eventually be filled from + */ +static avd_t +avd_alloc_var_ptr(var_t *var) +{ + avd_t avd; + + if (var == NULL) + return (NULL); + + if ((avd = avd_alloc_cmn()) == NULL) + return (NULL); + + switch (var->var_type & VAR_TYPE_SET_MASK) { + case VAR_TYPE_BOOL_SET: + avd->avd_type = AVD_VARVAL_BOOL; + avd->avd_val.boolptr = (&var->var_val.boolean); + break; + + case VAR_TYPE_INT_SET: + avd->avd_type = AVD_VARVAL_INT; + avd->avd_val.intptr = (&var->var_val.integer); + break; + + case VAR_TYPE_STR_SET: + avd->avd_type = AVD_VARVAL_STR; + avd->avd_val.strptr = &(var->var_val.string); + break; + + case VAR_TYPE_DBL_SET: + avd->avd_type = AVD_VARVAL_DBL; + avd->avd_val.dblptr = &(var->var_val.dbl_flt); + break; + + case VAR_TYPE_RAND_SET: + avd->avd_type = AVD_IND_RANDVAR; + avd->avd_val.randptr = var->var_val.randptr; + break; + + default: + avd->avd_type = AVD_IND_VAR; + avd->avd_val.varptr = var; + break; + } + return (avd); } /* - * Allocates a string pointer in interprocess shared memory, - * then allocates and initializes a piece of shared string memory, - * putting the pointer to it into the just allocated string - * pointer location. The routine returns a pointer to the - * string pointer location or returns NULL on error. + * Gets a avd_t, then allocates and initializes a piece of + * shared string memory, putting the pointer to it into the just + * allocated string pointer location. The routine returns a pointer + * to the string pointer location or returns NULL on error. */ -var_string_t -string_alloc(char *string) +avd_t +avd_str_alloc(char *string) { - char **rtn; + avd_t avd; - if ((rtn = (char **)ipc_malloc(FILEBENCH_STRING)) == NULL) { - filebench_log(LOG_ERROR, "Alloc string failed"); + if (string == NULL) { + filebench_log(LOG_ERROR, "No string supplied\n"); return (NULL); } - *rtn = ipc_stralloc(string); + if ((avd = avd_alloc_cmn()) == NULL) + return (NULL); + + avd->avd_type = AVD_VAL_STR; + avd->avd_val.strval = ipc_stralloc(string); filebench_log(LOG_DEBUG_IMPL, "Alloc string %s ptr %zx", - string, rtn); + string, avd); - return (rtn); + return (avd); } - /* * Allocates a var (var_t) from interprocess shared memory. * Places the allocated var on the end of the globally shared @@ -123,8 +505,9 @@ string_alloc(char *string) * newly allocated var. */ static var_t * -var_alloc(char *name) +var_alloc_cmn(char *name, int var_type) { + var_t **var_listp; var_t *var = NULL; var_t *prev = NULL; var_t *newvar; @@ -134,60 +517,64 @@ var_alloc(char *name) return (NULL); } (void) memset(newvar, 0, sizeof (newvar)); - - for (var = filebench_shm->var_list; var != NULL; var = var->var_next) - prev = var; /* Find end of list */ - if (prev != NULL) - prev->var_next = newvar; - else - filebench_shm->var_list = newvar; + newvar->var_type = var_type; if ((newvar->var_name = ipc_stralloc(name)) == NULL) { filebench_log(LOG_ERROR, "Out of memory for variables"); return (NULL); } - return (newvar); -} + switch (var_type & VAR_TYPE_MASK) { + case VAR_TYPE_RANDOM: + case VAR_TYPE_GLOBAL: + var_listp = &filebench_shm->var_list; + break; -/* - * Allocates a var (var_t) from interprocess shared memory. - * Places the allocated var on the end of the globally shared - * var_dyn_list. Finally, the routine allocates a string - * containing a copy of the supplied "name" string. If any - * allocations fails, returns NULL, otherwise it returns a - * pointer to the newly allocated var. - */ -static var_t * -var_alloc_dynamic(char *name) -{ - var_t *var = NULL; - var_t *prev = NULL; - var_t *newvar; + case VAR_TYPE_DYNAMIC: + var_listp = &filebench_shm->var_dyn_list; + break; - if ((newvar = (var_t *)ipc_malloc(FILEBENCH_VARIABLE)) == NULL) { - filebench_log(LOG_ERROR, "Out of memory for variables"); - return (NULL); + default: + var_listp = &filebench_shm->var_list; + break; } - (void) memset(newvar, 0, sizeof (newvar)); - for (var = filebench_shm->var_dyn_list; var != NULL; - var = var->var_next) + /* add to the end of list */ + for (var = *var_listp; var != NULL; var = var->var_next) prev = var; /* Find end of list */ if (prev != NULL) prev->var_next = newvar; else - filebench_shm->var_dyn_list = newvar; - - if ((newvar->var_name = ipc_stralloc(name)) == NULL) { - filebench_log(LOG_ERROR, "Out of memory for variables"); - return (NULL); - } + *var_listp = newvar; return (newvar); } /* + * Allocates a var (var_t) from interprocess shared memory and + * places the allocated var on the end of the globally shared + * var_list. If the allocation fails, returns NULL, otherwise + * it returns a pointer to the newly allocated var. + */ +static var_t * +var_alloc(char *name) +{ + return (var_alloc_cmn(name, VAR_TYPE_GLOBAL)); +} + +/* + * Allocates a var (var_t) from interprocess shared memory. + * Places the allocated var on the end of the globally shared + * var_dyn_list. If the allocation fails, returns NULL, otherwise + * it returns a pointer to the newly allocated var. + */ +static var_t * +var_alloc_dynamic(char *name) +{ + return (var_alloc_cmn(name, VAR_TYPE_DYNAMIC)); +} + +/* * Searches for var_t with name "name" in the master var_list. * If successful, returns a pointer to the var_t, otherwise * returns NULL. @@ -207,21 +594,73 @@ var_find(char *name) /* * Searches for the named var, and, if found, sets its + * var_val.boolean's value to that of the supplied boolean. + * If not found, the routine allocates a new var and sets + * its var_val.boolean's value to that of the supplied + * boolean. If the named var cannot be found or allocated + * the routine returns -1, otherwise it returns 0. + */ +int +var_assign_boolean(char *name, boolean_t bool) +{ + var_t *var; + + if (name == NULL) { + filebench_log(LOG_ERROR, + "var_assign_boolean: Name not supplied"); + return (0); + } + + name += 1; + + if ((var = var_find(name)) == NULL) { + var = var_alloc(name); + } + + if (var == NULL) { + filebench_log(LOG_ERROR, "Cannot assign variable %s", + name); + return (-1); + } + + if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { + filebench_log(LOG_ERROR, + "Cannot assign integer to random variable %s", name); + return (-1); + } + + VAR_SET_BOOL(var, bool); + + filebench_log(LOG_DEBUG_SCRIPT, "Assign boolean %s=%d", + name, bool); + + return (0); +} + +/* + * Searches for the named var, and, if found, sets its * var_integer's value to that of the supplied integer. * If not found, the routine allocates a new var and sets * its var_integers's value to that of the supplied * integer. If the named var cannot be found or allocated - * the routine returns -1, otherwise it returns 0. + * the routine returns -1, otherwise it returns 0. */ int -var_assign_integer(char *name, vinteger_t integer) +var_assign_integer(char *name, fbint_t integer) { var_t *var; + if (name == NULL) { + filebench_log(LOG_ERROR, + "var_assign_integer: Name not supplied"); + return (0); + } + name += 1; - if ((var = var_find(name)) == NULL) - var = var_alloc(name); + if ((var = var_find(name)) == NULL) { + var = var_alloc(name); + } if (var == NULL) { filebench_log(LOG_ERROR, "Cannot assign variable %s", @@ -229,7 +668,13 @@ var_assign_integer(char *name, vinteger_t integer) return (-1); } - var->var_integer = integer; + if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { + filebench_log(LOG_ERROR, + "Cannot assign integer to random variable %s", name); + return (-1); + } + + VAR_SET_INT(var, integer); filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%lld", name, integer); @@ -238,14 +683,82 @@ var_assign_integer(char *name, vinteger_t integer) } /* - * Searches for the named var, and if found returns a pointer - * to the var's var_integer. If not found, attempts to allocate - * a var named "name" and returns a pointer to it's (zeroed) - * var_integer. If the var cannot be found or allocated, an + * Find a variable, and set it to random type. + * If it does not have a random extension, allocate one + */ +var_t * +var_find_randvar(char *name) +{ + var_t *newvar; + + name += 1; + + if ((newvar = var_find(name)) == NULL) { + filebench_log(LOG_ERROR, + "failed to locate random variable $%s\n", name); + return (NULL); + } + + /* set randdist pointer unless it is already set */ + if (((newvar->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) || + !VAR_HAS_RANDDIST(newvar)) { + filebench_log(LOG_ERROR, + "Found variable $%s not random\n", name); + return (NULL); + } + + return (newvar); +} + +/* + * Allocate a variable, and set it to random type. Then + * allocate a random extension. + */ +var_t * +var_define_randvar(char *name) +{ + var_t *newvar; + randdist_t *rndp = NULL; + + name += 1; + + /* make sure variable doesn't already exist */ + if (var_find(name) != NULL) { + filebench_log(LOG_ERROR, + "variable name already in use\n"); + return (NULL); + } + + /* allocate a random variable */ + if ((newvar = var_alloc_cmn(name, VAR_TYPE_RANDOM)) == NULL) { + filebench_log(LOG_ERROR, + "failed to alloc random variable\n"); + return (NULL); + } + + /* set randdist pointer */ + if ((rndp = randdist_alloc()) == NULL) { + filebench_log(LOG_ERROR, + "failed to alloc random distribution object\n"); + return (NULL); + } + + rndp->rnd_var = newvar; + VAR_SET_RAND(newvar, rndp); + + return (newvar); +} + +/* + * Searches for the named var, and if found returns an avd_t + * pointing to the var's var_integer, var_string or var_double + * as appropriate. If not found, attempts to allocate + * a var named "name" and returns an avd_t to it with + * no value set. If the var cannot be found or allocated, an * error is logged and the run is terminated. */ -vinteger_t * -var_ref_integer(char *name) +avd_t +var_ref_attr(char *name) { var_t *var; @@ -263,14 +776,16 @@ var_ref_integer(char *name) filebench_shutdown(1); } - return (&var->var_integer); - + /* allocate pointer to var and return */ + return (avd_alloc_var_ptr(var)); } + /* - * Searches for the named var, and if found copies the var_string, - * if it exists, or a decimal number string representation of - * var_integer, into a malloc'd bit of memory using fb_stralloc(). + * Searches for the named var, and if found copies the var_val.string, + * if it exists, a decimal number string representation of + * var_val.integer, the state of var_val.boolean, or the type of random + * distribution employed, into a malloc'd bit of memory using fb_stralloc(). * Returns a pointer to the created string, or NULL on failure. */ char * @@ -287,20 +802,68 @@ var_to_string(char *name) if (var == NULL) return (NULL); - if (var->var_string) - return (fb_stralloc(var->var_string)); + if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { + switch (var->var_val.randptr->rnd_type & RAND_TYPE_MASK) { + case RAND_TYPE_UNIFORM: + return (fb_stralloc("uniform random var")); + case RAND_TYPE_GAMMA: + return (fb_stralloc("gamma random var")); + case RAND_TYPE_TABLE: + return (fb_stralloc("tabular random var")); + default: + return (fb_stralloc("unitialized random var")); + } + } + + if (VAR_HAS_STRING(var) && var->var_val.string) + return (fb_stralloc(var->var_val.string)); - (void) snprintf(tmp, sizeof (tmp), "%lld", var->var_integer); + if (VAR_HAS_BOOLEAN(var)) { + if (var->var_val.boolean) + return (fb_stralloc("true")); + else + return (fb_stralloc("false")); + } + + if (VAR_HAS_INTEGER(var)) { + (void) snprintf(tmp, sizeof (tmp), "%lld", + var->var_val.integer); + return (fb_stralloc(tmp)); + } - return (fb_stralloc(tmp)); + return (fb_stralloc("No default")); } /* * Searches for the named var, and if found returns the value, - * of var_integer. If the var is not found, or the var_integer's - * value is 0, logs an error and returns 0. + * of var_val.boolean. If the var is not found, or a boolean + * value has not been set, logs an error and returns 0. */ -vinteger_t +boolean_t +var_to_boolean(char *name) +{ + var_t *var; + + name += 1; + + if ((var = var_find(name)) == NULL) + var = var_find_dynamic(name); + + if ((var != NULL) && VAR_HAS_BOOLEAN(var)) + return (var->var_val.boolean); + + filebench_log(LOG_ERROR, + "Variable %s referenced before set", name); + + return (0); +} + +/* + * Searches for the named var, and if found returns the value, + * of var_val.integer. If the var is not found, or the an + * integer value has not been set, logs an error and returns 0. + */ +fbint_t var_to_integer(char *name) { var_t *var; @@ -310,8 +873,8 @@ var_to_integer(char *name) if ((var = var_find(name)) == NULL) var = var_find_dynamic(name); - if ((var != NULL) && (var->var_integer)) - return (var->var_integer); + if ((var != NULL) && VAR_HAS_INTEGER(var)) + return (var->var_val.integer); filebench_log(LOG_ERROR, "Variable %s referenced before set", name); @@ -320,6 +883,79 @@ var_to_integer(char *name) } /* + * Searches for the named random var, and if found, converts the + * requested parameter into a string or a decimal number string + * representation, into a malloc'd bit of memory using fb_stralloc(). + * Returns a pointer to the created string, or calls var_to_string() + * if a random variable isn't found. + */ +char * +var_randvar_to_string(char *name, int param_name) +{ + var_t *var; + fbint_t value; + + if ((var = var_find(name + 1)) == NULL) + return (var_to_string(name)); + + if (((var->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) || + !VAR_HAS_RANDDIST(var)) + return (var_to_string(name)); + + switch (param_name) { + case RAND_PARAM_TYPE: + switch (var->var_val.randptr->rnd_type & RAND_TYPE_MASK) { + case RAND_TYPE_UNIFORM: + return (fb_stralloc("uniform")); + case RAND_TYPE_GAMMA: + return (fb_stralloc("gamma")); + case RAND_TYPE_TABLE: + return (fb_stralloc("tabular")); + default: + return (fb_stralloc("uninitialized")); + } + + case RAND_PARAM_SRC: + if (var->var_val.randptr->rnd_type & RAND_SRC_GENERATOR) + return (fb_stralloc("rand48")); + else + return (fb_stralloc("urandom")); + + case RAND_PARAM_SEED: + value = avd_get_int(var->var_val.randptr->rnd_seed); + break; + + case RAND_PARAM_MIN: + value = avd_get_int(var->var_val.randptr->rnd_min); + break; + + case RAND_PARAM_MEAN: + value = avd_get_int(var->var_val.randptr->rnd_mean); + break; + + case RAND_PARAM_GAMMA: + value = avd_get_int(var->var_val.randptr->rnd_gamma); + break; + + case RAND_PARAM_ROUND: + value = avd_get_int(var->var_val.randptr->rnd_round); + break; + + default: + return (NULL); + + } + + /* just an integer value if we got here */ + { + char tmp[128]; + + (void) snprintf(tmp, sizeof (tmp), "%lld", value); + return (fb_stralloc(tmp)); + } +} + +/* * Searches for the var named "name", and if not found * allocates it. The then extracts the var_string from * the var named "string" and copies it into the var_string @@ -329,31 +965,66 @@ var_to_integer(char *name) * be found, the routine returns -1, otherwise it returns 0. */ int -var_assign_var(char *name, char *string) +var_assign_var(char *name, char *src_name) { - var_t *var; - var_string_t str; + var_t *dst_var, *src_var; name += 1; + src_name += 1; - if ((var = var_find(name)) == NULL) - var = var_alloc(name); + if ((src_var = var_find(src_name)) == NULL) { + filebench_log(LOG_ERROR, + "Cannot find source variable %s", src_name); + return (-1); + } - if (var == NULL) { + if ((dst_var = var_find(name)) == NULL) + dst_var = var_alloc(name); + + if (dst_var == NULL) { filebench_log(LOG_ERROR, "Cannot assign variable %s", name); return (-1); } - if ((str = var_ref_string(string)) == NULL) + if ((dst_var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { + filebench_log(LOG_ERROR, + "Cannot assign var to Random variable %s", name); return (-1); + } - if ((var->var_string = ipc_stralloc(*str)) == NULL) { - filebench_log(LOG_ERROR, "Cannot assign variable %s", - name); - return (-1); + if (VAR_HAS_BOOLEAN(src_var)) { + VAR_SET_BOOL(dst_var, src_var->var_val.boolean); + filebench_log(LOG_VERBOSE, + "Assign var %s=%d", name, src_var->var_val.boolean); + } + + if (VAR_HAS_INTEGER(src_var)) { + VAR_SET_INT(dst_var, src_var->var_val.integer); + filebench_log(LOG_VERBOSE, + "Assign var %s=%lld", name, src_var->var_val.integer); + } + + if (VAR_HAS_DOUBLE(src_var)) { + VAR_SET_DBL(dst_var, src_var->var_val.dbl_flt); + filebench_log(LOG_VERBOSE, + "Assign var %s=%lf", name, src_var->var_val.dbl_flt); + } + + if (VAR_HAS_STRING(src_var)) { + char *strptr; + + if ((strptr = + ipc_stralloc(src_var->var_val.string)) == NULL) { + filebench_log(LOG_ERROR, + "Cannot assign variable %s", + name); + return (-1); + } + VAR_SET_STR(dst_var, strptr); + filebench_log(LOG_VERBOSE, + "Assign var %s=%s", name, src_var->var_val.string); } - filebench_log(LOG_VERBOSE, "Assign string %s=%s", name, string); return (0); } @@ -371,6 +1042,7 @@ int var_assign_string(char *name, char *string) { var_t *var; + char *strptr; name += 1; @@ -383,44 +1055,67 @@ var_assign_string(char *name, char *string) return (-1); } - if ((var->var_string = ipc_stralloc(string)) == NULL) { + if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { + filebench_log(LOG_ERROR, + "Cannot assign string to random variable %s", name); + return (-1); + } + + if ((strptr = ipc_stralloc(string)) == NULL) { filebench_log(LOG_ERROR, "Cannot assign variable %s", name); return (-1); } + VAR_SET_STR(var, strptr); - filebench_log(LOG_DEBUG_SCRIPT, "Assign string %s=%s", name, string); + filebench_log(LOG_DEBUG_SCRIPT, + "Var assign string $%s=%s", name, string); return (0); } /* - * Searches for the named var, and if found returns a pointer - * to the var's var_string. If not found, attempts to allocate - * a var named "name" and returns a pointer to it's (empty) - * var_string. If the var cannot be found or allocated, an - * error is logged and the run is terminated. + * Tests to see if the supplied variable name without the portion after + * the last period is that of a random variable. If it is, it returns + * the number of characters to backspace to skip the period and field + * name. Otherwise it returns 0. */ -char ** -var_ref_string(char *name) +int +var_is_set4_randvar(char *name) { var_t *var; + char varname[128]; + int namelength; + char *sp; - name += 1; + (void) strncpy(varname, name, 128); + namelength = strlen(varname); + sp = varname + namelength; - if ((var = var_find(name)) == NULL) - var = var_find_dynamic(name); + while (sp != varname) { + int c = *sp; - if (var == NULL) - var = var_alloc(name); + *sp = 0; + if (c == '.') + break; - if (var == NULL) { - filebench_log(LOG_ERROR, "Cannot reference variable %s", - name); - filebench_shutdown(1); + sp--; } - return (&var->var_string); + /* not a variable name + field? */ + if (sp == varname) + return (0); + + /* first part not a variable name? */ + if ((var = var_find(varname+1)) == NULL) + return (0); + + /* Make sure it is a random variable */ + if ((var->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) + return (0); + + /* calculate offset from end of random variable name */ + return (namelength - (sp - varname)); } /* @@ -468,7 +1163,7 @@ var_find_internal(var_t *var) /* * Calls the C library routine getenv() to obtain the value * for the environment variable specified by var->var_name. - * If found, the value string is returned in var->var_string. + * If found, the value string is returned in var->var_val.string. * If the requested value is not found, NULL is returned. */ static var_t * @@ -476,14 +1171,18 @@ var_find_environment(var_t *var) { char *n = fb_stralloc(var->var_name); char *name = n; + char *strptr; name++; - if (name[strlen(name) - 1] != ')') + if (name[strlen(name) - 1] != ')') { + free(n); return (NULL); + } name[strlen(name) - 1] = 0; - if ((var->var_string = getenv(name)) != NULL) { + if ((strptr = getenv(name)) != NULL) { free(n); + VAR_SET_STR(var, strptr); return (var); } else { free(n); diff --git a/usr/src/cmd/filebench/common/vars.h b/usr/src/cmd/filebench/common/vars.h index 7b394a0ec8..af12a801fc 100644 --- a/usr/src/cmd/filebench/common/vars.h +++ b/usr/src/cmd/filebench/common/vars.h @@ -19,7 +19,7 @@ * 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. */ @@ -40,30 +40,136 @@ extern "C" { #endif -typedef uint64_t vinteger_t; -typedef vinteger_t *var_integer_t; -typedef char **var_string_t; +/* Attribute Value Descriptor types */ +typedef enum avd_type { + AVD_INVALID = 0, /* avd is empty */ + AVD_VAL_BOOL, /* avd contains a boolean_t */ + AVD_VARVAL_BOOL, /* avd points to the boolean_t in a var_t */ + AVD_VAL_INT, /* avd contains an fbint_t */ + AVD_VARVAL_INT, /* avd points to the fbint_t in a var_t */ + AVD_VAL_STR, /* avd contains a sting (*char) */ + AVD_VARVAL_STR, /* avd points to a string in a var_t */ + AVD_VAL_DBL, /* avd contains a double float */ + AVD_VARVAL_DBL, /* avd points to the double in a var_t */ + AVD_IND_VAR, /* avd points a var_t */ + AVD_IND_RANDVAR /* avd points to the randdist_t associated */ + /* with a random type var_t */ +} avd_type_t; + +typedef uint64_t fbint_t; + +/* Attribute Value Descriptor */ +typedef struct avd { + avd_type_t avd_type; + union { + boolean_t boolval; + boolean_t *boolptr; + fbint_t intval; + fbint_t *intptr; + double dblval; + double *dblptr; + char *strval; + char **strptr; + struct randdist *randptr; + struct var *varptr; + } avd_val; +} *avd_t; + +#define AVD_IS_RANDOM(vp) ((vp)->avd_type == AVD_IND_RANDVAR) typedef struct var { char *var_name; int var_type; struct var *var_next; - char *var_string; - vinteger_t var_integer; + union { + boolean_t boolean; + fbint_t integer; + double dbl_flt; + char *string; + struct randdist *randptr; + } var_val; } var_t; -#define VAR_TYPE_DYNAMIC 1 +#define VAR_TYPE_GLOBAL 0x00 /* global variable */ +#define VAR_TYPE_DYNAMIC 0x01 /* Dynamic variable */ +#define VAR_TYPE_RANDOM 0x02 /* random variable */ +#define VAR_TYPE_MASK 0x0f +#define VAR_TYPE_BOOL_SET 0x10 /* var contains a boolean */ +#define VAR_TYPE_INT_SET 0x20 /* var contains an integer */ +#define VAR_TYPE_STR_SET 0x30 /* var contains a string */ +#define VAR_TYPE_DBL_SET 0x40 /* var contains a double */ +#define VAR_TYPE_RAND_SET 0x50 /* var contains a randdist pointer */ +#define VAR_TYPE_SET_MASK 0xf0 + +#define VAR_HAS_BOOLEAN(vp) \ + (((vp)->var_type & VAR_TYPE_SET_MASK) == VAR_TYPE_BOOL_SET) + +#define VAR_HAS_INTEGER(vp) \ + (((vp)->var_type & VAR_TYPE_SET_MASK) == VAR_TYPE_INT_SET) + +#define VAR_HAS_DOUBLE(vp) \ + (((vp)->var_type & VAR_TYPE_SET_MASK) == VAR_TYPE_DBL_SET) + +#define VAR_HAS_STRING(vp) \ + (((vp)->var_type & VAR_TYPE_SET_MASK) == VAR_TYPE_STR_SET) + +#define VAR_HAS_RANDDIST(vp) \ + (((vp)->var_type & VAR_TYPE_SET_MASK) == VAR_TYPE_RAND_SET) + +#define VAR_SET_BOOL(vp, val) \ + { \ + (vp)->var_val.boolean = (val); \ + (vp)->var_type = \ + (((vp)->var_type & (~VAR_TYPE_SET_MASK)) | VAR_TYPE_BOOL_SET);\ + } + +#define VAR_SET_INT(vp, val) \ + { \ + (vp)->var_val.integer = (val); \ + (vp)->var_type = \ + (((vp)->var_type & (~VAR_TYPE_SET_MASK)) | VAR_TYPE_INT_SET); \ + } + +#define VAR_SET_DBL(vp, val) \ + { \ + (vp)->var_val.dbl_flt = (val); \ + (vp)->var_type = \ + (((vp)->var_type & (~VAR_TYPE_SET_MASK)) | VAR_TYPE_DBL_SET); \ + } + +#define VAR_SET_STR(vp, val) \ + { \ + (vp)->var_val.string = (val); \ + (vp)->var_type = \ + (((vp)->var_type & (~VAR_TYPE_SET_MASK)) | VAR_TYPE_STR_SET); \ + } + +#define VAR_SET_RAND(vp, val) \ + { \ + (vp)->var_val.randptr = (val); \ + (vp)->var_type = \ + (((vp)->var_type & (~VAR_TYPE_SET_MASK)) | VAR_TYPE_RAND_SET);\ + } -vinteger_t *integer_alloc(vinteger_t integer); -char **string_alloc(char *string); -int var_assign_integer(char *name, vinteger_t integer); -vinteger_t *var_ref_integer(char *name); +avd_t avd_bool_alloc(boolean_t bool); +avd_t avd_int_alloc(fbint_t integer); +avd_t avd_str_alloc(char *string); +avd_t var_ref_attr(char *name); +int var_assign_boolean(char *name, boolean_t bool); +int var_assign_integer(char *name, fbint_t integer); int var_assign_string(char *name, char *string); int var_assign_var(char *name, char *string); -char **var_ref_string(char *name); +var_t *var_define_randvar(char *name); +var_t *var_find_randvar(char *name); +boolean_t var_to_boolean(char *name); +fbint_t var_to_integer(char *name); char *var_to_string(char *name); -vinteger_t var_to_integer(char *name); -int integer_isset(var_integer_t); +char *var_randvar_to_string(char *name, int param); +boolean_t avd_get_bool(avd_t); +fbint_t avd_get_int(avd_t); +double avd_get_dbl(avd_t); +char *avd_get_str(avd_t); +int var_is_set4_randvar(char *name); #ifdef __cplusplus } diff --git a/usr/src/cmd/filebench/workloads/filemicro_rread.f b/usr/src/cmd/filebench/workloads/filemicro_rread.f index 9a3b44599a..6d9b04c80f 100644 --- a/usr/src/cmd/filebench/workloads/filemicro_rread.f +++ b/usr/src/cmd/filebench/workloads/filemicro_rread.f @@ -19,7 +19,7 @@ # 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. # # ident "%Z%%M% %I% %E% SMI" @@ -30,6 +30,7 @@ set $iosize=2k set $bytes=128m set $iters=1 set $filesize=1g +set $cached=false define file name=bigfile1,path=$dir,size=$filesize,prealloc,reuse,cached=$cached @@ -42,11 +43,12 @@ define process name=filereader,instances=1 } } -echo "FileMicro-ReadRand Version 2.0 personality successfully loaded" +echo "FileMicro-ReadRand Version 2.1 personality successfully loaded" usage "Usage: set \$dir=<dir>" -usage " set \$filesize=<size> defaults to $filesize" -usage " set \$iosize=<size> defaults to $iosize" -usage " set \$bytes=<value> defaults to $bytes" -usage " set \$nthreads=<value> defaults to $nthreads" +usage " set \$bytes=<value> defaults to $bytes" +usage " set \$cached=<bool> defaults to $cached" +usage " set \$filesize=<size> defaults to $filesize" +usage " set \$iosize=<size> defaults to $iosize" +usage " set \$nthreads=<value> defaults to $nthreads" usage " " usage " run runtime (e.g. run 60)" diff --git a/usr/src/cmd/filebench/workloads/filemicro_seqwrite.f b/usr/src/cmd/filebench/workloads/filemicro_seqwrite.f index 588dcb78be..21accc9e33 100644 --- a/usr/src/cmd/filebench/workloads/filemicro_seqwrite.f +++ b/usr/src/cmd/filebench/workloads/filemicro_seqwrite.f @@ -19,7 +19,7 @@ # 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. # # ident "%Z%%M% %I% %E% SMI" @@ -28,9 +28,11 @@ # 5- Sequential write(32K) of a 1G file, uncached set $dir=/tmp -set $nthreads=1 -set $iosize=1m set $cached=0 +set $count=1000 +set $iosize=1m +set $nthreads=1 +set $sync=false define fileset name=bigfileset,path=$dir,size=0,entries=$nthreads,dirwidth=1024,prealloc=100,cached=$cached @@ -44,10 +46,12 @@ define process name=filewriter,instances=1 } } -echo "FileMicro-SeqWrite Version 2.0 personality successfully loaded" +echo "FileMicro-SeqWrite Version 2.1 personality successfully loaded" usage "Usage: set \$dir=<dir>" +usage " set \$cached=<bool> defaults to $cached" +usage " set \$count=<value> defaults to $count" usage " set \$iosize=<size> defaults to $iosize" usage " set \$nthreads=<value> defaults to $nthreads" -usage " set \$cached=<bool> defaults to $cached" +usage " set \$sync=<bool> defaults to $sync" usage " " usage " run runtime (e.g. run 60)" diff --git a/usr/src/cmd/filebench/workloads/filemicro_seqwriterandvargam.f b/usr/src/cmd/filebench/workloads/filemicro_seqwriterandvargam.f new file mode 100644 index 0000000000..f863021068 --- /dev/null +++ b/usr/src/cmd/filebench/workloads/filemicro_seqwriterandvargam.f @@ -0,0 +1,63 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" + +# Sequential write() of a 1G file, size picked from a gamma distribution +# min of 1k and a mean of 5.5K, followed by close(), cached. + + + +set $dir=/tmp +set $nthreads=1 +set $cached=false +set $sync=false +set $count=128k + +define randvar name=$iosize, type=gamma, min=1k, mean=5632, gamma=1500 + +define fileset name=bigfileset,path=$dir,size=0,entries=$nthreads,dirwidth=1024,prealloc=100,cached=$cached + +define process name=filewriter,instances=1 +{ + thread name=filewriterthread,memsize=10m,instances=$nthreads + { + flowop appendfile name=write-file,dsync=$sync,filesetname=bigfileset,iosize=$iosize,fd=1,iters=$count + flowop closefile name=close,fd=1 + flowop finishoncount name=finish,value=1 + } +} + +echo "FileMicro-SeqWriteRandVarGam Version 1.0 personality successfully loaded" +usage "Usage: set \$dir=<dir>" +usage " set \$cached=<bool> defaults to $cached" +usage " set \$count=<value> defaults to $count" +usage " set \$iosize.type=<type> defaults to $iosize.type" +usage " set \$iosize.randsrc=<src> defaults to $iosize.randsrc" +usage " set \$iosize.mean=<mean> defaults to $iosize.mean" +usage " set \$iosize.gamma=<gamma> defaults to $iosize.gamma" +usage " set \$nthreads=<value> defaults to $nthreads" +usage " set \$sync=<bool> defaults to $sync" +usage " " +usage " run runtime (e.g. run 60)" diff --git a/usr/src/cmd/filebench/workloads/filemicro_seqwriterandvartab.f b/usr/src/cmd/filebench/workloads/filemicro_seqwriterandvartab.f new file mode 100644 index 0000000000..e01618e0ab --- /dev/null +++ b/usr/src/cmd/filebench/workloads/filemicro_seqwriterandvartab.f @@ -0,0 +1,66 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" + +# Sequential write() of a 1G file, size picked from a table in +# the [1K,64K] range with a mean of 5.5K, followed by close(), cached. + + + +set $dir=/tmp +set $nthreads=1 +set $cached=false +set $sync=false +set $count=128k + +define randvar name=$iosize, type=tabular, min=1k, randtable = +{{ 80, 1k, 4k}, + { 15, 4k, 16k}, + { 05, 16k, 64k}} + +define fileset name=bigfileset,path=$dir,size=0,entries=$nthreads,dirwidth=1024,prealloc=100,cached=$cached + +define process name=filewriter,instances=1 +{ + thread name=filewriterthread,memsize=10m,instances=$nthreads + { + flowop appendfile name=write-file,dsync=$sync,filesetname=bigfileset,iosize=$iosize,fd=1,iters=$count + flowop closefile name=close,fd=1 + flowop finishoncount name=finish,value=1 + } +} + +echo "FileMicro-SeqWriteRandVarTab Version 1.0 personality successfully loaded" +usage "Usage: set \$dir=<dir>" +usage " set \$cached=<bool> defaults to $cached" +usage " set \$count=<value> defaults to $count" +usage " set \$iosize.type=<type> defaults to $iosize.type" +usage " set \$iosize.randsrc=<src> defaults to $iosize.randsrc" +usage " set \$iosize.mean=<mean> defaults to $iosize.mean" +usage " set \$iosize.gamma=<gamma> defaults to $iosize.gamma" +usage " set \$nthreads=<value> defaults to $nthreads" +usage " set \$sync=<bool> defaults to $sync" +usage " " +usage " run runtime (e.g. run 60)" |