summaryrefslogtreecommitdiff
path: root/usr/src/cmd/filebench/common
diff options
context:
space:
mode:
authoraw148015 <none@none>2008-05-05 10:16:55 -0700
committeraw148015 <none@none>2008-05-05 10:16:55 -0700
commit7c71bafd4f4418f93653e4ac62d7599e583ebb99 (patch)
tree19d40d1a1671f5317a6ddd775df1867cc1b97428 /usr/src/cmd/filebench/common
parent9d5d194537eaddd9cf553f2a5b18fd51a4e74afc (diff)
downloadillumos-joyent-7c71bafd4f4418f93653e4ac62d7599e583ebb99.tar.gz
6652464 FileBench needs an f-language definable composite flowop feature
Diffstat (limited to 'usr/src/cmd/filebench/common')
-rw-r--r--usr/src/cmd/filebench/common/filebench.h2
-rw-r--r--usr/src/cmd/filebench/common/flowop.c346
-rw-r--r--usr/src/cmd/filebench/common/flowop.h20
-rw-r--r--usr/src/cmd/filebench/common/flowop_library.c4
-rw-r--r--usr/src/cmd/filebench/common/ipc.h1
-rw-r--r--usr/src/cmd/filebench/common/parser_gram.y373
-rw-r--r--usr/src/cmd/filebench/common/threadflow.c4
-rw-r--r--usr/src/cmd/filebench/common/threadflow.h2
-rw-r--r--usr/src/cmd/filebench/common/vars.c445
-rw-r--r--usr/src/cmd/filebench/common/vars.h41
10 files changed, 1081 insertions, 157 deletions
diff --git a/usr/src/cmd/filebench/common/filebench.h b/usr/src/cmd/filebench/common/filebench.h
index 5386425303..80e0d4156e 100644
--- a/usr/src/cmd/filebench/common/filebench.h
+++ b/usr/src/cmd/filebench/common/filebench.h
@@ -109,7 +109,7 @@ void filebench_shutdown(int error);
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif
-#define FILEBENCH_VERSION "1.2.4"
+#define FILEBENCH_VERSION "1.3.0"
#define FILEBENCHDIR "/usr/benchmarks/filebench"
#define FILEBENCH_PROMPT "filebench> "
#define MAX_LINE_LEN 1024
diff --git a/usr/src/cmd/filebench/common/flowop.c b/usr/src/cmd/filebench/common/flowop.c
index 1394152dd2..5ba66529cb 100644
--- a/usr/src/cmd/filebench/common/flowop.c
+++ b/usr/src/cmd/filebench/common/flowop.c
@@ -41,7 +41,10 @@
#endif
static flowop_t *flowop_define_common(threadflow_t *threadflow, char *name,
- flowop_t *inherit, int instance, int type);
+ flowop_t *inherit, flowop_t **flowoplist_hdp, int instance, int type);
+static int flowop_composite(threadflow_t *threadflow, flowop_t *flowop);
+static int flowop_composite_init(flowop_t *flowop);
+static void flowop_composite_destruct(flowop_t *flowop);
/*
* A collection of flowop support functions. The actual code that
@@ -51,9 +54,54 @@ static flowop_t *flowop_define_common(threadflow_t *threadflow, char *name,
* flowops, cyclically invoking the flowops on each threadflow's flowop
* list, collecting statistics about flowop execution, and other
* housekeeping duties are included in this file.
+ *
+ * User Defined Composite Flowops
+ * The ability to define new flowops as lists of built-in or previously
+ * defined flowops has been added to Filebench. In a sense they are like
+ * in-line subroutines, which can have default attributes set at definition
+ * time and passed arguments at invocation time. Like other flowops (and
+ * unlike conventional subroutines) you can invoke them with an iteration
+ * count (the "iter" attribute), and they will loop through their associated
+ * list of flowops for "iter" number of times each time they are encountered
+ * in the thread or outer composite flowop which invokes them.
+ *
+ * Composite flowops are created with a "define" command, are given a name,
+ * optional default attributes, and local variable definitions on the
+ * "define" command line, followed by a brace enclosed list of flowops
+ * to execute. The enclosed flowops may include attributes that reference
+ * the local variables, as well as constants and global variables.
+ *
+ * Composite flowops are used pretty much like regular flowops, but you can
+ * also set local variables to constants or global variables ($local_var =
+ * [$var | $random_var | string | boolean | integer | double]) as part of
+ * the invocation. Thus each invocation can pass customized values to its
+ * inner flowops, greatly increasing their generality.
+ *
+ * All flowops are placed on a global, singly linked list, with fo_next
+ * being the link pointer for this list. The are also placed on a private
+ * list for the thread or composite flowop they are part of. The tf_thrd_fops
+ * pointer in the thread will point to the list of top level flowops in the
+ * thread, which are linked together by fo_exec_next. If any of these flowops
+ * are composite flowops, they will have a list of second level flowops rooted
+ * at the composite flowop's fo_comp_fops pointer. So, there is one big list
+ * of all flowops, and an n-arry tree of threads, composite flowops, and
+ * flowops, with composite flowops being the branch nodes in the tree.
+ *
+ * To illustrate, if we have three first level flowops, the first of which is
+ * a composite flowop consisting of two other flowops, we get:
+ *
+ * Thread->tf_thrd_fops -> flowop->fo_exec_next -> flowop->fo_exec_next
+ * flowop->fo_comp_fops |
+ * | V
+ * | flowop->fo_exec_next
+ * |
+ * V
+ * flowop->fo_exec_next -> flowop->fo_exec_next
+ *
+ * And all five flowops (plus others from any other threads) are on a global
+ * list linked with fo_next.
*/
-
/*
* Prints the name and instance number of each flowop in
* the supplied list to the filebench log.
@@ -66,7 +114,7 @@ flowop_printlist(flowop_t *list)
while (flowop) {
filebench_log(LOG_DEBUG_IMPL, "flowop-list %s-%d",
flowop->fo_name, flowop->fo_instance);
- flowop = flowop->fo_threadnext;
+ flowop = flowop->fo_exec_next;
}
return (0);
}
@@ -216,6 +264,47 @@ flowop_initflow(flowop_t *flowop)
return (0);
}
+static int
+flowop_create_runtime_flowops(threadflow_t *threadflow, flowop_t **ops_list_ptr)
+{
+ flowop_t *flowop = *ops_list_ptr;
+
+ while (flowop) {
+ flowop_t *newflowop;
+
+ if (flowop == *ops_list_ptr)
+ *ops_list_ptr = NULL;
+
+ newflowop = flowop_define_common(threadflow, flowop->fo_name,
+ flowop, ops_list_ptr, 1, 0);
+ if (newflowop == NULL)
+ return (FILEBENCH_ERROR);
+
+ /* check for fo_filename attribute, and resolve if present */
+ if (flowop->fo_filename) {
+ char *name;
+
+ name = avd_get_str(flowop->fo_filename);
+ newflowop->fo_fileset = fileset_find(name);
+
+ if (newflowop->fo_fileset == NULL) {
+ filebench_log(LOG_ERROR,
+ "flowop %s: file %s not found",
+ newflowop->fo_name, name);
+ filebench_shutdown(1);
+ }
+ }
+
+ if (flowop_initflow(newflowop) < 0) {
+ filebench_log(LOG_ERROR, "Flowop init of %s failed",
+ newflowop->fo_name);
+ }
+
+ flowop = flowop->fo_exec_next;
+ }
+ return (FILEBENCH_OK);
+}
+
/*
* Calls the flowop's destruct function, pointed to by
* flowop->fo_destruct.
@@ -245,13 +334,13 @@ flowop_destruct_all_flows(threadflow_t *threadflow)
return;
}
- flowop = threadflow->tf_ops;
+ flowop = threadflow->tf_thrd_fops;
threadflow->tf_running = 0;
(void) ipc_mutex_unlock(&threadflow->tf_lock);
while (flowop) {
flowop_destructflow(flowop);
- flowop = flowop->fo_threadnext;
+ flowop = flowop->fo_exec_next;
}
}
@@ -295,7 +384,7 @@ flowop_start(threadflow_t *threadflow)
}
(void) ipc_mutex_unlock(&controlstats_lock);
- flowop = threadflow->tf_ops;
+ flowop = threadflow->tf_thrd_fops;
threadflow->tf_stats.fs_stime = gethrtime();
flowop->fo_stats.fs_stime = gethrtime();
@@ -317,36 +406,11 @@ flowop_start(threadflow_t *threadflow)
/* Create the runtime flowops from those defined by the script */
(void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock);
- while (flowop) {
- flowop_t *newflowop;
-
- if (flowop == threadflow->tf_ops)
- threadflow->tf_ops = NULL;
- newflowop = flowop_define_common(threadflow, flowop->fo_name,
- flowop, 1, 0);
- if (newflowop == NULL)
- return;
-
- /* check for fo_filename attribute, and resolve if present */
- if (flowop->fo_filename) {
- char *name;
-
- name = avd_get_str(flowop->fo_filename);
- newflowop->fo_fileset = fileset_find(name);
-
- if (newflowop->fo_fileset == NULL) {
- filebench_log(LOG_ERROR,
- "flowop %s: file %s not found",
- newflowop->fo_name, name);
- filebench_shutdown(1);
- }
- }
-
- if (flowop_initflow(newflowop) < 0) {
- filebench_log(LOG_ERROR, "Flowop init of %s failed",
- newflowop->fo_name);
- }
- flowop = flowop->fo_threadnext;
+ if (flowop_create_runtime_flowops(threadflow, &threadflow->tf_thrd_fops)
+ != FILEBENCH_OK) {
+ (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock);
+ filebench_shutdown(1);
+ return;
}
(void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock);
@@ -354,7 +418,7 @@ flowop_start(threadflow_t *threadflow)
(void) pthread_rwlock_unlock(&filebench_shm->shm_flowop_find_lock);
/* Set to the start of the new flowop list */
- flowop = threadflow->tf_ops;
+ flowop = threadflow->tf_thrd_fops;
threadflow->tf_abort = 0;
threadflow->tf_running = 1;
@@ -409,7 +473,7 @@ flowop_start(threadflow_t *threadflow)
flowop->fo_stats.fs_stime = gethrtime();
/* Execute the flowop for fo_iters times */
- count = avd_get_int(flowop->fo_iters);
+ count = (int)avd_get_int(flowop->fo_iters);
for (i = 0; i < count; i++) {
filebench_log(LOG_DEBUG_SCRIPT, "%s: executing flowop "
@@ -497,11 +561,11 @@ flowop_start(threadflow_t *threadflow)
}
/* advance to next flowop */
- flowop = flowop->fo_threadnext;
+ flowop = flowop->fo_exec_next;
/* but if at end of list, start over from the beginning */
if (flowop == NULL) {
- flowop = threadflow->tf_ops;
+ flowop = threadflow->tf_thrd_fops;
threadflow->tf_stats.fs_count++;
}
}
@@ -539,31 +603,31 @@ flowop_delete(flowop_t **flowoplist, flowop_t *flowop)
/* Delete from thread's flowop list */
if (flowop == *flowoplist) {
/* First on list */
- *flowoplist = flowop->fo_threadnext;
+ *flowoplist = flowop->fo_exec_next;
filebench_log(LOG_DEBUG_IMPL,
"Delete0 flowop: (%s-%d)",
flowop->fo_name,
flowop->fo_instance);
} else {
- while (entry->fo_threadnext) {
+ while (entry->fo_exec_next) {
filebench_log(LOG_DEBUG_IMPL,
"Delete0 flowop: (%s-%d) == (%s-%d)",
- entry->fo_threadnext->fo_name,
- entry->fo_threadnext->fo_instance,
+ entry->fo_exec_next->fo_name,
+ entry->fo_exec_next->fo_instance,
flowop->fo_name,
flowop->fo_instance);
- if (flowop == entry->fo_threadnext) {
+ if (flowop == entry->fo_exec_next) {
/* Delete */
filebench_log(LOG_DEBUG_IMPL,
"Deleted0 flowop: (%s-%d)",
- entry->fo_threadnext->fo_name,
- entry->fo_threadnext->fo_instance);
- entry->fo_threadnext =
- entry->fo_threadnext->fo_threadnext;
+ entry->fo_exec_next->fo_name,
+ entry->fo_exec_next->fo_instance);
+ entry->fo_exec_next =
+ entry->fo_exec_next->fo_exec_next;
break;
}
- entry = entry->fo_threadnext;
+ entry = entry->fo_exec_next;
}
}
@@ -620,25 +684,19 @@ flowop_delete_all(flowop_t **flowoplist)
{
flowop_t *flowop = *flowoplist;
- filebench_log(LOG_DEBUG_IMPL, "Deleting all flowops...");
+ (void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock);
+
while (flowop) {
filebench_log(LOG_DEBUG_IMPL, "Deleting flowop (%s-%d)",
flowop->fo_name, flowop->fo_instance);
- flowop = flowop->fo_threadnext;
- }
- flowop = *flowoplist;
-
- (void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock);
-
- while (flowop) {
if (flowop->fo_instance &&
(flowop->fo_instance == FLOW_MASTER)) {
- flowop = flowop->fo_threadnext;
+ flowop = flowop->fo_exec_next;
continue;
}
flowop_delete(flowoplist, flowop);
- flowop = flowop->fo_threadnext;
+ flowop = flowop->fo_exec_next;
}
(void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock);
@@ -647,21 +705,21 @@ flowop_delete_all(flowop_t **flowoplist)
/*
* Allocates a flowop entity and initializes it with inherited
* contents from the "inherit" flowop, if it is supplied, or
- * with zeros otherwise. In either case the file descriptor
- * (fo_fd) is set to -1, and the fo_next and fo_threadnext
+ * with zeros otherwise. In either case the fo_next and fo_exec_next
* pointers are set to NULL, and fo_thread is set to point to
* the owning threadflow. The initialized flowop is placed at
* the head of the global flowop list, and also placed on the
- * tail of thethreadflow's tf_ops list. The routine locks the
- * flowop's fo_lock and leaves it held on return. If successful,
- * it returns a pointer to the allocated and initialized flowop,
- * otherwise NULL.
+ * tail of the supplied local flowop list, which will either
+ * be a threadflow's tf_thrd_fops list or a composite flowop's
+ * fo_comp_fops list. The routine locks the flowop's fo_lock and
+ * leaves it held on return. If successful, it returns a pointer
+ * to the allocated and initialized flowop, otherwise it returns NULL.
*
* filebench_shm->shm_flowop_lock must be held by caller.
*/
static flowop_t *
flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit,
- int instance, int type)
+ flowop_t **flowoplist_hdp, int instance, int type)
{
flowop_t *flowop;
@@ -685,7 +743,7 @@ flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit,
(void) pthread_mutex_init(&flowop->fo_lock, ipc_mutexattr());
(void) ipc_mutex_lock(&flowop->fo_lock);
flowop->fo_next = NULL;
- flowop->fo_threadnext = NULL;
+ flowop->fo_exec_next = NULL;
filebench_log(LOG_DEBUG_IMPL,
"flowop %s-%d calling init", name, instance);
} else {
@@ -711,22 +769,22 @@ flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit,
(void) strcpy(flowop->fo_name, name);
flowop->fo_instance = instance;
- if (threadflow == NULL)
+ if (flowoplist_hdp == NULL)
return (flowop);
/* Add flowop to thread op list */
- if (threadflow->tf_ops == NULL) {
- threadflow->tf_ops = flowop;
- flowop->fo_threadnext = NULL;
+ if (*flowoplist_hdp == NULL) {
+ *flowoplist_hdp = flowop;
+ flowop->fo_exec_next = NULL;
} else {
flowop_t *flowend;
/* Find the end of the thread list */
- flowend = threadflow->tf_ops;
- while (flowend->fo_threadnext != NULL)
- flowend = flowend->fo_threadnext;
- flowend->fo_threadnext = flowop;
- flowop->fo_threadnext = NULL;
+ flowend = *flowoplist_hdp;
+ while (flowend->fo_exec_next != NULL)
+ flowend = flowend->fo_exec_next;
+ flowend->fo_exec_next = flowop;
+ flowop->fo_exec_next = NULL;
}
return (flowop);
@@ -739,18 +797,43 @@ flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit,
*/
flowop_t *
flowop_define(threadflow_t *threadflow, char *name, flowop_t *inherit,
- int instance, int type)
+ flowop_t **flowoplist_hdp, int instance, int type)
{
flowop_t *flowop;
(void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock);
flowop = flowop_define_common(threadflow, name,
- inherit, instance, type);
+ inherit, flowoplist_hdp, instance, type);
+ (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock);
+
+ if (flowop == NULL)
+ return (NULL);
+
+ (void) ipc_mutex_unlock(&flowop->fo_lock);
+ return (flowop);
+}
+
+/*
+ * Calls flowop_define_common() to allocate and initialize a
+ * composite flowop, and holds the shared flowop_lock during the call.
+ * It releases the created flowop's fo_lock when done.
+ */
+flowop_t *
+flowop_new_composite_define(char *name)
+{
+ flowop_t *flowop;
+
+ (void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock);
+ flowop = flowop_define_common(NULL, name,
+ NULL, NULL, 0, FLOW_TYPE_COMPOSITE);
(void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock);
if (flowop == NULL)
return (NULL);
+ flowop->fo_func = flowop_composite;
+ flowop->fo_init = flowop_composite_init;
+ flowop->fo_destruct = flowop_composite_destruct;
(void) ipc_mutex_unlock(&flowop->fo_lock);
return (flowop);
@@ -837,3 +920,108 @@ flowop_find_one(char *name, int instance)
return (test_flowop);
}
+
+/*
+ * Composite flowop method. Does one pass through its list of
+ * inner flowops per iteration.
+ */
+static int
+flowop_composite(threadflow_t *threadflow, flowop_t *flowop)
+{
+ flowop_t *inner_flowop;
+
+ /* get the first flowop in the list */
+ inner_flowop = flowop->fo_comp_fops;
+
+ /* make a pass through the list of sub flowops */
+ while (inner_flowop) {
+ int i, count;
+
+ /* Abort if asked */
+ if (threadflow->tf_abort || filebench_shm->shm_f_abort)
+ return (FILEBENCH_DONE);
+
+ if (inner_flowop->fo_stats.fs_stime == 0)
+ inner_flowop->fo_stats.fs_stime = gethrtime();
+
+ /* Execute the flowop for fo_iters times */
+ count = (int)avd_get_int(inner_flowop->fo_iters);
+ for (i = 0; i < count; i++) {
+
+ filebench_log(LOG_DEBUG_SCRIPT, "%s: executing flowop "
+ "%s-%d", threadflow->tf_name,
+ inner_flowop->fo_name,
+ inner_flowop->fo_instance);
+
+ switch ((*inner_flowop->fo_func)(threadflow,
+ inner_flowop)) {
+
+ /* all done */
+ case FILEBENCH_DONE:
+ return (FILEBENCH_DONE);
+
+ /* quit if inner flowop limit reached */
+ case FILEBENCH_NORSC:
+ return (FILEBENCH_NORSC);
+
+ /* quit on inner flowop error */
+ case FILEBENCH_ERROR:
+ filebench_log(LOG_ERROR,
+ "inner flowop %s failed",
+ inner_flowop->fo_name);
+ return (FILEBENCH_ERROR);
+
+ /* otherwise keep going */
+ default:
+ break;
+ }
+
+ }
+
+ /* advance to next flowop */
+ inner_flowop = inner_flowop->fo_exec_next;
+ }
+
+ /* finished with this pass */
+ return (FILEBENCH_OK);
+}
+
+/*
+ * Composite flowop initialization. Creates runtime inner flowops
+ * from prototype inner flowops.
+ */
+static int
+flowop_composite_init(flowop_t *flowop)
+{
+ int err;
+
+ err = flowop_create_runtime_flowops(flowop->fo_thread,
+ &flowop->fo_comp_fops);
+ if (err != FILEBENCH_OK)
+ return (err);
+
+ (void) ipc_mutex_unlock(&flowop->fo_lock);
+ return (0);
+}
+
+/*
+ * clean up inner flowops
+ */
+static void
+flowop_composite_destruct(flowop_t *flowop)
+{
+ flowop_t *inner_flowop = flowop->fo_comp_fops;
+
+ while (inner_flowop) {
+ filebench_log(LOG_DEBUG_IMPL, "Deleting inner flowop (%s-%d)",
+ inner_flowop->fo_name, inner_flowop->fo_instance);
+
+ if (inner_flowop->fo_instance &&
+ (inner_flowop->fo_instance == FLOW_MASTER)) {
+ inner_flowop = inner_flowop->fo_exec_next;
+ continue;
+ }
+ flowop_delete(&flowop->fo_comp_fops, inner_flowop);
+ inner_flowop = inner_flowop->fo_exec_next;
+ }
+}
diff --git a/usr/src/cmd/filebench/common/flowop.h b/usr/src/cmd/filebench/common/flowop.h
index d98b1d0ff8..5d6c83810e 100644
--- a/usr/src/cmd/filebench/common/flowop.h
+++ b/usr/src/cmd/filebench/common/flowop.h
@@ -56,8 +56,10 @@ typedef struct flowop {
char fo_name[128]; /* Name */
int fo_instance; /* Instance number */
struct flowop *fo_next; /* Next in global list */
- struct flowop *fo_threadnext; /* Next in thread's list */
+ struct flowop *fo_exec_next; /* Next in thread's or compfo's list */
struct flowop *fo_resultnext; /* List of flowops in result */
+ struct flowop *fo_comp_fops; /* List of flowops in composite fo */
+ var_t *fo_lvar_list; /* List of composite local vars */
struct threadflow *fo_thread; /* Backpointer to thread */
int (*fo_func)(); /* Method */
int (*fo_init)(); /* Init Method */
@@ -118,22 +120,29 @@ typedef struct flowop {
#define FLOW_ATTR_READ 0x80
#define FLOW_ATTR_WRITE 0x100
-#define FLOW_MASTER -1 /* Declaration of thread from script */
+/* Flowop Instance Numbers */
+ /* Worker flowops have instance numbers > 0 */
#define FLOW_DEFINITION 0 /* Prototype definition of flowop from library */
+#define FLOW_INNER_DEF -1 /* Constructed proto flowops within composite */
+#define FLOW_MASTER -2 /* Master flowop based on flowop declaration */
+ /* supplied within a thread definition */
-#define FLOW_TYPES 5
+/* Flowop type definitions */
+
+#define FLOW_TYPES 6
#define FLOW_TYPE_GLOBAL 0 /* Rolled up statistics */
#define FLOW_TYPE_IO 1 /* Op is an I/O, reflected in iops and lat */
#define FLOW_TYPE_AIO 2 /* Op is an async I/O, reflected in iops */
#define FLOW_TYPE_SYNC 3 /* Op is a sync event */
-#define FLOW_TYPE_OTHER 4 /* Op is a something else */
+#define FLOW_TYPE_COMPOSITE 4 /* Op is a composite flowop */
+#define FLOW_TYPE_OTHER 5 /* 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,
- int instance, int type);
+ flowop_t **flowoplist_hdp, int instance, int type);
flowop_t *flowop_find(char *name);
flowop_t *flowop_find_one(char *name, int instance);
void flowoplib_usage(void);
@@ -142,6 +151,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);
+flowop_t *flowop_new_composite_define(char *name);
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 e13692b569..9a2bb8c192 100644
--- a/usr/src/cmd/filebench/common/flowop_library.c
+++ b/usr/src/cmd/filebench/common/flowop_library.c
@@ -233,7 +233,7 @@ flowoplib_init()
fl = &flowoplib_funcs[i];
if ((flowop = flowop_define(NULL,
- fl->fl_name, NULL, 0, fl->fl_type)) == 0) {
+ fl->fl_name, NULL, NULL, 0, fl->fl_type)) == 0) {
filebench_log(LOG_ERROR,
"failed to create flowop %s\n",
fl->fl_name);
@@ -1503,7 +1503,7 @@ flowoplib_sempost(threadflow_t *threadflow, flowop_t *flowop)
int i;
#endif /* HAVE_SYSV_SEM */
struct timespec timeout;
- int value = avd_get_int(flowop->fo_value);
+ int value = (int)avd_get_int(flowop->fo_value);
if (target->fo_instance == FLOW_MASTER) {
target = target->fo_targetnext;
diff --git a/usr/src/cmd/filebench/common/ipc.h b/usr/src/cmd/filebench/common/ipc.h
index e60416f3ee..38d3a01202 100644
--- a/usr/src/cmd/filebench/common/ipc.h
+++ b/usr/src/cmd/filebench/common/ipc.h
@@ -98,6 +98,7 @@ typedef struct filebench_shm {
var_t *shm_var_list;
var_t *shm_var_dyn_list;
randdist_t *shm_rand_list;
+ var_t *shm_var_loc_list;
int shm_debug_level;
hrtime_t shm_epoch;
hrtime_t shm_starttime;
diff --git a/usr/src/cmd/filebench/common/parser_gram.y b/usr/src/cmd/filebench/common/parser_gram.y
index cbfe0bae52..c8edfd5812 100644
--- a/usr/src/cmd/filebench/common/parser_gram.y
+++ b/usr/src/cmd/filebench/common/parser_gram.y
@@ -85,13 +85,16 @@ extern void yyerror(char *s);
static void terminate(void);
static cmd_t *alloc_cmd(void);
static attr_t *alloc_attr(void);
+static attr_t *alloc_lvar_attr(var_t *var);
static attr_t *get_attr(cmd_t *cmd, int64_t name);
static attr_t *get_attr_integer(cmd_t *cmd, int64_t name);
static attr_t *get_attr_bool(cmd_t *cmd, int64_t name);
+static void get_attr_lvars(cmd_t *cmd, flowop_t *flowop);
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);
+static void add_lvar_to_list(var_t *newlvar, var_t **lvar_list);
/* Info Commands */
static void parser_list(cmd_t *);
@@ -105,6 +108,7 @@ 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 *);
+static void parser_composite_flowop_define(cmd_t *);
/* Create Commands */
static void parser_proc_create(cmd_t *);
@@ -179,6 +183,7 @@ static void parser_abort(int arg);
%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 FSV_SET_LOCAL_VAR FSA_LVAR_ASSIGN
%token FSA_ALLDONE FSA_FIRSTDONE FSA_TIMEOUT
%type <ival> FSV_VAL_INT
@@ -188,6 +193,7 @@ static void parser_abort(int arg);
%type <sval> FSV_VARIABLE
%type <sval> FSV_RANDVAR
%type <sval> FSK_ASSIGN
+%type <sval> FSV_SET_LOCAL_VAR
%type <ival> FSC_LIST FSC_DEFINE FSC_SET FSC_LOAD FSC_RUN
%type <ival> FSE_FILE FSE_PROC FSE_THREAD FSE_CLEAR FSC_HELP
@@ -198,7 +204,7 @@ static void parser_abort(int arg);
%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> fo_define_command 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
@@ -208,10 +214,11 @@ static void parser_abort(int arg);
%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 <attr> comp_lvar_def comp_attr_op comp_attr_ops
%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> attrs_define_fileset attrs_define_proc attrs_eventgen attrs_define_comp
%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
@@ -265,6 +272,7 @@ command:
proc_define_command
| files_define_command
| randvar_define_command
+| fo_define_command
| debug_command
| eventgen_command
| create_command
@@ -951,6 +959,19 @@ randvar_define_command: FSC_DEFINE FSE_RAND randvar_attr_ops
$$->cmd_attr_list = $3;
};
+fo_define_command: FSC_DEFINE FSC_FLOWOP comp_attr_ops FSK_OPENLST flowop_list FSK_CLOSELST
+{
+ if (($$ = alloc_cmd()) == NULL)
+ YYERROR;
+ $$->cmd = &parser_composite_flowop_define;
+ $$->cmd_list = $5;
+ $$->cmd_attr_list = $3;
+}
+| fo_define_command comp_attr_ops
+{
+ $1->cmd_attr_list = $2;
+};
+
create_command: FSC_CREATE entity
{
if (($$ = alloc_cmd()) == NULL)
@@ -1251,6 +1272,19 @@ fo_attr_ops: fo_attr_op
list_end->attr_next = $3;
$$ = $1;
+}
+| fo_attr_ops FSK_SEPLST comp_lvar_def
+{
+ 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
@@ -1296,7 +1330,6 @@ ev_attr_op: ev_attr_name FSK_ASSIGN attr_value
$$->attr_name = $1;
};
-
files_attr_name: attrs_define_file
|attrs_define_fileset;
@@ -1407,6 +1440,79 @@ attrs_flowop:
attrs_eventgen:
FSA_RATE { $$ = FSA_RATE;};
+comp_attr_ops: comp_attr_op
+{
+ $$ = $1;
+}
+| comp_attr_ops FSK_SEPLST comp_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;
+}
+| comp_attr_ops FSK_SEPLST comp_lvar_def
+{
+ 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;
+};
+
+comp_attr_op: attrs_define_comp FSK_ASSIGN attr_value
+{
+ $$ = $3;
+ $$->attr_name = $1;
+};
+
+comp_lvar_def: FSV_VARIABLE FSK_ASSIGN FSV_VAL_BOOLEAN
+{
+ if (($$ = alloc_lvar_attr(var_lvar_assign_boolean($1, $3))) == NULL)
+ YYERROR;
+}
+| FSV_VARIABLE FSK_ASSIGN FSV_VAL_INT
+{
+ if (($$ = alloc_lvar_attr(var_lvar_assign_integer($1, $3))) == NULL)
+ YYERROR;
+}
+| FSV_VARIABLE FSK_ASSIGN FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
+{
+ if (($$ = alloc_lvar_attr(var_lvar_assign_string($1, $4))) == NULL)
+ YYERROR;
+}
+| FSV_VARIABLE FSK_ASSIGN FSV_STRING
+{
+ if (($$ = alloc_lvar_attr(var_lvar_assign_string($1, $3))) == NULL)
+ YYERROR;
+}
+| FSV_VARIABLE FSK_ASSIGN FSV_VARIABLE
+{
+ if (($$ = alloc_lvar_attr(var_lvar_assign_var($1, $3))) == NULL)
+ YYERROR;
+}
+| FSV_VARIABLE
+{
+ if (($$ = alloc_lvar_attr(var_lvar_alloc_local($1))) == NULL)
+ YYERROR;
+};
+
+
+attrs_define_comp:
+ FSA_NAME { $$ = FSA_NAME;}
+| FSA_ITERS { $$ = FSA_ITERS;};
+
attr_value: FSV_STRING
{
if (($$ = alloc_attr()) == NULL)
@@ -2053,7 +2159,7 @@ parser_thread_define(cmd_t *cmd, procflow_t *procflow, int procinstances)
for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
inner_cmd = inner_cmd->cmd_next) {
parser_flowop_define(inner_cmd, threadflow,
- &threadflow->tf_ops, FLOW_MASTER);
+ &threadflow->tf_thrd_fops, FLOW_MASTER);
}
}
@@ -2149,6 +2255,123 @@ parser_flowop_get_attrs(cmd_t *cmd, flowop_t *flowop)
}
}
+/*
+ * defines the FLOW_MASTER flowops within a FLOW_MASTER instance of
+ * a composit flowop. Default attributes from the FLOW_INNER_DEF instances
+ * of the composit flowop's inner flowops are used if set. Otherwise
+ * default attributes from the FLOW_MASTER instance of the composit flowop
+ * are used, which may include defaults from the original FLOW_DEFINITION
+ * of the composit flowop.
+ */
+static void
+parser_inner_flowop_define(threadflow_t *thread, flowop_t *comp0_flow,
+ flowop_t *comp_mstr_flow)
+{
+ flowop_t *inner_flowtype, *inner_flowop;
+
+ /* follow flowop list, creating composit names */
+ inner_flowtype = comp0_flow->fo_comp_fops;
+ comp_mstr_flow->fo_comp_fops = NULL;
+
+ while (inner_flowtype) {
+ char fullname[MAXPATHLEN];
+
+ /* create composite_name.name for new flowop */
+ (void) strlcpy(fullname, comp_mstr_flow->fo_name, MAXPATHLEN);
+ (void) strlcat(fullname, ".", MAXPATHLEN);
+ (void) strlcat(fullname, inner_flowtype->fo_name,
+ MAXPATHLEN);
+
+ if ((inner_flowop = flowop_define(thread, fullname,
+ inner_flowtype, &comp_mstr_flow->fo_comp_fops,
+ FLOW_MASTER, 0)) == NULL) {
+ filebench_log(LOG_ERROR,
+ "define flowop: Failed to instantiate flowop %s\n",
+ fullname);
+ filebench_shutdown(1);
+ }
+
+ /* if applicable, update filename attribute */
+ if (inner_flowop->fo_filename) {
+ char *name;
+
+ /* fix up avd_t */
+ avd_update(&inner_flowop->fo_filename,
+ comp_mstr_flow->fo_lvar_list);
+
+ /* see if ready to get the file or fileset */
+ name = avd_get_str(inner_flowop->fo_filename);
+ if (name) {
+
+ inner_flowop->fo_fileset = fileset_find(name);
+
+ if (inner_flowop->fo_fileset == NULL) {
+ filebench_log(LOG_ERROR,
+ "inr flowop %s: file %s not found",
+ inner_flowop->fo_name, name);
+ filebench_shutdown(1);
+ }
+ }
+ }
+
+ /* update attributes from local variables */
+ avd_update(&inner_flowop->fo_iters,
+ comp_mstr_flow->fo_lvar_list);
+
+ /* if the inner flowop is a composit flowop, recurse */
+ if (inner_flowtype->fo_type == FLOW_TYPE_COMPOSITE) {
+ var_t *newlvar, *proto_lvars, *lvar_ptr;
+
+ proto_lvars = inner_flowop->fo_lvar_list;
+ inner_flowop->fo_lvar_list = 0;
+
+ for (lvar_ptr = inner_flowtype->fo_lvar_list; lvar_ptr;
+ lvar_ptr = lvar_ptr->var_next) {
+
+ if ((newlvar = var_lvar_alloc_local(
+ lvar_ptr->var_name)) != NULL) {
+
+ add_lvar_to_list(newlvar,
+ &inner_flowop->fo_lvar_list);
+
+ var_update_comp_lvars(newlvar,
+ proto_lvars,
+ comp_mstr_flow->fo_lvar_list);
+ }
+ }
+
+ parser_inner_flowop_define(thread,
+ inner_flowtype,
+ inner_flowop);
+
+ inner_flowtype = inner_flowtype->fo_exec_next;
+ continue;
+ }
+
+ avd_update(&inner_flowop->fo_iosize,
+ comp_mstr_flow->fo_lvar_list);
+ avd_update(&inner_flowop->fo_wss,
+ comp_mstr_flow->fo_lvar_list);
+ avd_update(&inner_flowop->fo_iters,
+ comp_mstr_flow->fo_lvar_list);
+ avd_update(&inner_flowop->fo_value,
+ comp_mstr_flow->fo_lvar_list);
+ avd_update(&inner_flowop->fo_random,
+ comp_mstr_flow->fo_lvar_list);
+ avd_update(&inner_flowop->fo_dsync,
+ comp_mstr_flow->fo_lvar_list);
+ avd_update(&inner_flowop->fo_rotatefd,
+ comp_mstr_flow->fo_lvar_list);
+ avd_update(&inner_flowop->fo_blocking,
+ comp_mstr_flow->fo_lvar_list);
+ avd_update(&inner_flowop->fo_directio,
+ comp_mstr_flow->fo_lvar_list);
+ avd_update(&inner_flowop->fo_highwater,
+ comp_mstr_flow->fo_lvar_list);
+
+ inner_flowtype = inner_flowtype->fo_exec_next;
+ }
+}
/*
* Calls flowop_define() to allocate a flowop with the supplied name.
@@ -2206,22 +2429,75 @@ parser_flowop_define(cmd_t *cmd, threadflow_t *thread,
}
if ((flowop = flowop_define(thread, name,
- flowop_type, category, 0)) == NULL) {
+ flowop_type, flowoplist_hdp, category, 0)) == NULL) {
+ filebench_log(LOG_ERROR,
+ "define flowop: Failed to instantiate flowop %s\n",
+ cmd->cmd_name);
+ filebench_shutdown(1);
+ }
+
+ /* Iterations */
+ if (attr = get_attr_integer(cmd, FSA_ITERS))
+ flowop->fo_iters = attr->attr_avd;
+ else
+ flowop->fo_iters = avd_int_alloc(1);
+
+
+ /* if this is a use of a composit flowop, create inner FLOW MASTERS */
+ if (flowop_type->fo_type == FLOW_TYPE_COMPOSITE) {
+ get_attr_lvars(cmd, flowop);
+ if (category == FLOW_MASTER)
+ parser_inner_flowop_define(thread,
+ flowop_type, flowop);
+ }
+ else {
+ parser_flowop_get_attrs(cmd, flowop);
+ }
+}
+
+static void
+parser_composite_flowop_define(cmd_t *cmd)
+{
+ flowop_t *flowop;
+ cmd_t *inner_cmd;
+ char *name;
+ attr_t *attr;
+
+ /* Get the name of the flowop */
+ if (attr = get_attr(cmd, FSA_NAME)) {
+ name = avd_get_str(attr->attr_avd);
+ } else {
+ filebench_log(LOG_ERROR,
+ "define flowop: Composit flowop specifies no name");
+
+ filebench_shutdown(1);
+ }
+
+ if ((flowop = flowop_new_composite_define(name)) == NULL) {
filebench_log(LOG_ERROR,
"define flowop: Failed to instantiate flowop %s\n",
cmd->cmd_name);
filebench_shutdown(1);
}
+ /* place any local var_t variables on the flowop's local list */
+ get_attr_lvars(cmd, flowop);
+
/* Iterations */
if (attr = get_attr_integer(cmd, FSA_ITERS))
flowop->fo_iters = attr->attr_avd;
else
flowop->fo_iters = avd_int_alloc(1);
- parser_flowop_get_attrs(cmd, flowop);
+ /* define inner flowops */
+ for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
+ inner_cmd = inner_cmd->cmd_next) {
+ parser_flowop_define(inner_cmd, NULL,
+ &flowop->fo_comp_fops, FLOW_INNER_DEF);
+ }
}
+
/*
* Calls fileset_define() to allocate a fileset with the supplied name and
* initializes the fileset's pathname attribute, and optionally the
@@ -3252,8 +3528,6 @@ parser_randvar_set(cmd_t *cmd)
{
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) {
@@ -3274,9 +3548,6 @@ parser_randvar_set(cmd_t *cmd)
{
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));
@@ -3351,7 +3622,7 @@ free_cmd(cmd_t *cmd)
* a pointer to the attr_t.
*/
static attr_t *
-alloc_attr()
+alloc_attr(void)
{
attr_t *attr;
@@ -3381,6 +3652,24 @@ alloc_probtabent(void)
}
/*
+ * Allocates an attr_t structure and puts the supplied var_t into
+ * its attr_avd location, and sets its name to FSA_LVAR_ASSIGN
+ */
+static attr_t *
+alloc_lvar_attr(var_t *var)
+{
+ attr_t *attr;
+
+ if ((attr = alloc_attr()) == NULL)
+ return (NULL);
+
+ attr->attr_name = FSA_LVAR_ASSIGN;
+ attr->attr_avd = (avd_t)var;
+
+ return (attr);
+}
+
+/*
* 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.
@@ -3490,6 +3779,66 @@ get_attr_bool(cmd_t *cmd, int64_t name)
}
/*
+ * removes the newly allocated local var from the shared local var
+ * list, then puts it at the head of the private local var list
+ * supplied as the second argument.
+ */
+static void
+add_lvar_to_list(var_t *newlvar, var_t **lvar_list)
+{
+ var_t *prev;
+
+ /* remove from shared local list, if there */
+ if (newlvar == filebench_shm->shm_var_loc_list) {
+ /* on top of list, just grap */
+ filebench_shm->shm_var_loc_list = newlvar->var_next;
+ } else {
+ /* find newvar on list and remove */
+ for (prev = filebench_shm->shm_var_loc_list; prev;
+ prev = prev->var_next) {
+ if (prev->var_next == newlvar)
+ prev->var_next = newlvar->var_next;
+ }
+ }
+ newlvar->var_next = NULL;
+
+ /* add to flowop private local list at head */
+ newlvar->var_next = *lvar_list;
+ *lvar_list = newlvar;
+}
+
+/*
+ * Searches the attribute list for the command for any allocated local
+ * variables. The attribute list is created by the parser from the list of
+ * attributes supplied with certain commands, such as the define and flowop
+ * commands. Places all found local vars onto the flowop's local variable
+ * list.
+ */
+static void
+get_attr_lvars(cmd_t *cmd, flowop_t *flowop)
+{
+ attr_t *attr;
+ var_t *list_tail, *orig_lvar_list;
+
+ /* save the local var list */
+ orig_lvar_list = flowop->fo_lvar_list;
+
+ for (attr = cmd->cmd_attr_list; attr != NULL;
+ attr = attr->attr_next) {
+
+ if (attr->attr_name == FSA_LVAR_ASSIGN) {
+ var_t *newvar, *prev;
+
+ if ((newvar = (var_t *)attr->attr_avd) == NULL)
+ continue;
+
+ add_lvar_to_list(newvar, &flowop->fo_lvar_list);
+ var_update_comp_lvars(newvar, orig_lvar_list, NULL);
+ }
+ }
+}
+
+/*
* Allocates memory for a list_t structure, initializes it to zero, and
* returns a pointer to it. On failure, returns NULL.
*/
diff --git a/usr/src/cmd/filebench/common/threadflow.c b/usr/src/cmd/filebench/common/threadflow.c
index 6c99e339d9..d5c1965298 100644
--- a/usr/src/cmd/filebench/common/threadflow.c
+++ b/usr/src/cmd/filebench/common/threadflow.c
@@ -271,7 +271,7 @@ threadflow_delete(threadflow_t **threadlist, threadflow_t *threadflow,
threadflow->tf_instance);
threadflow_kill(threadflow, wait_cnt);
- flowop_delete_all(&threadflow->tf_ops);
+ flowop_delete_all(&threadflow->tf_thrd_fops);
*threadlist = threadflow->tf_next;
ipc_free(FILEBENCH_THREADFLOW, (char *)threadflow);
return (0);
@@ -292,7 +292,7 @@ threadflow_delete(threadflow_t **threadlist, threadflow_t *threadflow,
entry->tf_next->tf_name,
entry->tf_next->tf_instance);
threadflow_kill(entry->tf_next, wait_cnt);
- flowop_delete_all(&entry->tf_next->tf_ops);
+ flowop_delete_all(&entry->tf_next->tf_thrd_fops);
ipc_free(FILEBENCH_THREADFLOW, (char *)threadflow);
entry->tf_next = entry->tf_next->tf_next;
return (0);
diff --git a/usr/src/cmd/filebench/common/threadflow.h b/usr/src/cmd/filebench/common/threadflow.h
index 119c368a1b..125280e816 100644
--- a/usr/src/cmd/filebench/common/threadflow.h
+++ b/usr/src/cmd/filebench/common/threadflow.h
@@ -82,7 +82,7 @@ typedef struct threadflow {
pthread_mutex_t tf_lock; /* Mutex around threadflow */
avd_t tf_instances; /* Number of instances for this flow */
struct threadflow *tf_next; /* Next on proc list */
- struct flowop *tf_ops; /* Flowop list */
+ struct flowop *tf_thrd_fops; /* Flowop list */
caddr_t tf_mem; /* Private Memory */
avd_t tf_memsize; /* Private Memory size attribute */
fbint_t tf_constmemsize; /* constant copy of memory size */
diff --git a/usr/src/cmd/filebench/common/vars.c b/usr/src/cmd/filebench/common/vars.c
index 38fad4d540..cc3f3e6d32 100644
--- a/usr/src/cmd/filebench/common/vars.c
+++ b/usr/src/cmd/filebench/common/vars.c
@@ -69,6 +69,7 @@ static var_t *var_find_dynamic(char *name);
* and integers of vars, and said components of avd_t.
*/
+
/*
* returns a pointer to a string indicating the type of data contained
* in the supplied attribute variable descriptor.
@@ -460,6 +461,11 @@ avd_alloc_var_ptr(var_t *var)
avd->avd_val.randptr = var->var_val.randptr;
break;
+ case VAR_TYPE_INDVAR_SET:
+ avd->avd_type = AVD_IND_VAR;
+ avd->avd_val.varptr = var->var_val.varptr;
+ break;
+
default:
avd->avd_type = AVD_IND_VAR;
avd->avd_val.varptr = var;
@@ -500,7 +506,7 @@ avd_str_alloc(char *string)
/*
* Allocates a var (var_t) from interprocess shared memory.
* Places the allocated var on the end of the globally shared
- * var_list. Finally, the routine allocates a string containing
+ * shm_var_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.
@@ -535,6 +541,12 @@ var_alloc_cmn(char *name, int var_type)
var_listp = &filebench_shm->shm_var_dyn_list;
break;
+ case VAR_TYPE_LOCAL:
+ /* place on head of shared local list */
+ newvar->var_next = filebench_shm->shm_var_loc_list;
+ filebench_shm->shm_var_loc_list = newvar;
+ return (newvar);
+
default:
var_listp = &filebench_shm->shm_var_list;
break;
@@ -552,9 +564,25 @@ var_alloc_cmn(char *name, int var_type)
}
/*
+ * Allocates a var (var_t) from interprocess shared memory after
+ * first adjusting the name to elminate the leading $. Places the
+ * allocated var temporarily on the end of the globally
+ * shared var_loc_list. If the allocation fails, returns NULL,
+ * otherwise it returns a pointer to the newly allocated var.
+ */
+var_t *
+var_lvar_alloc_local(char *name)
+{
+ if (name[0] == '$')
+ name += 1;
+
+ return (var_alloc_cmn(name, VAR_TYPE_LOCAL));
+}
+
+/*
* 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
+ * shm_var_list. If the allocation fails, returns NULL, otherwise
* it returns a pointer to the newly allocated var.
*/
static var_t *
@@ -566,7 +594,7 @@ var_alloc(char *name)
/*
* 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
+ * shm_var_dyn_list. If the allocation fails, returns NULL, otherwise
* it returns a pointer to the newly allocated var.
*/
static var_t *
@@ -576,15 +604,22 @@ var_alloc_dynamic(char *name)
}
/*
- * Searches for var_t with name "name" in the master var_list.
- * If successful, returns a pointer to the var_t, otherwise
- * returns NULL.
+ * Searches for var_t with name "name" in the shm_var_loc_list,
+ * then, if not found, in the global shm_var_list. If a matching
+ * local or global var is found, returns a pointer to the var_t,
+ * otherwise returns NULL.
*/
static var_t *
var_find(char *name)
{
var_t *var;
+ for (var = filebench_shm->shm_var_loc_list; var != NULL;
+ var = var->var_next) {
+ if (strcmp(var->var_name, name) == 0)
+ return (var);
+ }
+
for (var = filebench_shm->shm_var_list; var != NULL;
var = var->var_next) {
if (strcmp(var->var_name, name) == 0)
@@ -595,6 +630,40 @@ var_find(char *name)
}
/*
+ * Searches for var_t with name "name" in the supplied shm_var_list.
+ * If not found there, checks the global list. If still
+ * unsuccessful, returns NULL. Otherwise returns a pointer to the var_t.
+ */
+static var_t *
+var_find_list_only(char *name, var_t *var_list)
+{
+ var_t *var;
+
+ for (var = var_list; var != NULL; var = var->var_next) {
+ if (strcmp(var->var_name, name) == 0)
+ return (var);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Searches for var_t with name "name" in the supplied shm_var_list.
+ * If not found there, checks the global list. If still
+ * unsuccessful, returns NULL. Otherwise returns a pointer to the var_t.
+ */
+static var_t *
+var_find_list(char *name, var_t *var_list)
+{
+ var_t *var;
+
+ if ((var = var_find_list_only(name, var_list)) != NULL)
+ return (var);
+ else
+ return (var_find(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
@@ -959,13 +1028,64 @@ var_randvar_to_string(char *name, int param_name)
}
/*
+ * Copies the value stored in the source string into the destination
+ * string. Returns -1 if any problems encountered, 0 otherwise.
+ */
+static int
+var_copy(var_t *dst_var, var_t *src_var) {
+
+ if (VAR_HAS_BOOLEAN(src_var)) {
+ VAR_SET_BOOL(dst_var, src_var->var_val.boolean);
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Assign var %s=%s", dst_var->var_name,
+ dst_var->var_val.boolean?"true":"false");
+ }
+
+ if (VAR_HAS_INTEGER(src_var)) {
+ VAR_SET_INT(dst_var, src_var->var_val.integer);
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Assign var %s=%llu", dst_var->var_name,
+ (u_longlong_t)dst_var->var_val.integer);
+ }
+
+ if (VAR_HAS_DOUBLE(src_var)) {
+ VAR_SET_DBL(dst_var, src_var->var_val.dbl_flt);
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Assign var %s=%lf", dst_var->var_name,
+ dst_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 string for variable %s",
+ dst_var->var_name);
+ return (-1);
+ }
+ VAR_SET_STR(dst_var, strptr);
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Assign var %s=%s", dst_var->var_name,
+ dst_var->var_val.string);
+ }
+
+ if (VAR_HAS_INDVAR(src_var)) {
+ VAR_SET_INDVAR(dst_var, src_var->var_val.varptr);
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Assign var %s to var %s", dst_var->var_name,
+ src_var->var_name);
+ }
+ return (0);
+}
+
+/*
* 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
- * of the var "name", after first allocating a piece of
- * interprocess shared string memory. If the var "name"
- * cannot be found or allocated, or the var "string" cannot
- * be found, the routine returns -1, otherwise it returns 0.
+ * allocates it. The then copies the value from
+ * the src_var into the destination var "name"
+ * If the var "name" cannot be found or allocated, or the var "src_name"
+ * cannot be found, the routine returns -1, otherwise it returns 0.
*/
int
var_assign_var(char *name, char *src_name)
@@ -996,40 +1116,7 @@ var_assign_var(char *name, char *src_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=%llu",
- name, (u_longlong_t)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);
- }
- return (0);
+ return (var_copy(dst_var, src_var));
}
/*
@@ -1039,7 +1126,7 @@ var_assign_var(char *name, char *src_name)
* before the copy. Space for the string in the var comes
* from interprocess shared memory. If the var "name"
* cannot be found or allocated, or the memory for the
- * var_string copy of "string" cannot be allocated, the
+ * var_val.string copy of "string" cannot be allocated, the
* routine returns -1, otherwise it returns 0.
*/
int
@@ -1079,6 +1166,197 @@ var_assign_string(char *name, char *string)
}
/*
+ * Allocates a local var. The then extracts the var_string from
+ * the var named "string" and copies it into the var_string
+ * of the var "name", after first allocating a piece of
+ * interprocess shared string memory. Returns a pointer to the
+ * newly allocated local var or NULL on error.
+ */
+var_t *
+var_lvar_assign_var(char *name, char *src_name)
+{
+ var_t *dst_var, *src_var;
+
+ src_name += 1;
+
+ if ((src_var = var_find(src_name)) == NULL) {
+ filebench_log(LOG_ERROR,
+ "Cannot find source variable %s", src_name);
+ return (NULL);
+ }
+
+ dst_var = var_lvar_alloc_local(name);
+
+ if (dst_var == NULL) {
+ filebench_log(LOG_ERROR, "Cannot assign variable %s",
+ name);
+ return (NULL);
+ }
+
+ /*
+ * if referencing another local var which is currently
+ * empty, indirect to it
+ */
+ if ((src_var->var_type & VAR_TYPE_MASK) == VAR_TYPE_LOCAL) {
+ VAR_SET_INDVAR(dst_var, src_var);
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Assign local var %s to %s", name, src_name);
+ return (dst_var);
+ }
+
+ if (VAR_HAS_BOOLEAN(src_var)) {
+ VAR_SET_BOOL(dst_var, src_var->var_val.boolean);
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Assign var (%s, %p)=%s", name,
+ dst_var, src_var->var_val.boolean?"true":"false");
+ } else if (VAR_HAS_INTEGER(src_var)) {
+ VAR_SET_INT(dst_var, src_var->var_val.integer);
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Assign var (%s, %p)=%llu", name,
+ dst_var, (u_longlong_t)src_var->var_val.integer);
+ } else 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 (NULL);
+ }
+ VAR_SET_STR(dst_var, strptr);
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Assign var (%s, %p)=%s", name,
+ dst_var, src_var->var_val.string);
+ } else if (VAR_HAS_DOUBLE(src_var)) {
+ /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */
+ VAR_SET_INT(dst_var, src_var->var_val.dbl_flt);
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Assign var (%s, %p)=%8.2f", name,
+ dst_var, src_var->var_val.dbl_flt);
+ } else if (VAR_HAS_RANDDIST(src_var)) {
+ VAR_SET_RAND(dst_var, src_var->var_val.randptr);
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Assign var (%s, %p)=%llu", name,
+ dst_var, (u_longlong_t)src_var->var_val.integer);
+ }
+
+ return (dst_var);
+}
+
+/*
+ * the routine allocates a new local var and sets
+ * its var_boolean's value to that of the supplied
+ * boolean. It returns a pointer to the new local var
+ */
+var_t *
+var_lvar_assign_boolean(char *name, boolean_t bool)
+{
+ var_t *var;
+
+ var = var_lvar_alloc_local(name);
+
+ if (var == NULL) {
+ filebench_log(LOG_ERROR, "Cannot assign variable %s",
+ name);
+ return (NULL);
+ }
+
+ VAR_SET_BOOL(var, bool);
+
+ filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%s",
+ name, bool ? "true" : "false");
+
+ return (var);
+}
+
+/*
+ * the routine allocates a new local var and sets
+ * its var_integers's value to that of the supplied
+ * integer. It returns a pointer to the new local var
+ */
+var_t *
+var_lvar_assign_integer(char *name, fbint_t integer)
+{
+ var_t *var;
+
+ var = var_lvar_alloc_local(name);
+
+ if (var == NULL) {
+ filebench_log(LOG_ERROR, "Cannot assign variable %s",
+ name);
+ return (NULL);
+ }
+
+ VAR_SET_INT(var, integer);
+
+ filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%llu",
+ name, (u_longlong_t)integer);
+
+ return (var);
+}
+
+/*
+ * the routine allocates a new local var and sets
+ * its var_dbl_flt value to that of the supplied
+ * double precission floating point number. It returns
+ * a pointer to the new local var
+ */
+var_t *
+var_lvar_assign_double(char *name, double dbl)
+{
+ var_t *var;
+
+ var = var_lvar_alloc_local(name);
+
+ if (var == NULL) {
+ filebench_log(LOG_ERROR, "Cannot assign variable %s",
+ name);
+ return (NULL);
+ }
+
+ VAR_SET_DBL(var, dbl);
+
+ filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%8.2f", name, dbl);
+
+ return (var);
+}
+
+/*
+ * Like var_lvar_assign_integer, only this routine copies the
+ * supplied "string" into the var named "name". If the var
+ * named "name" cannot be found then it is first allocated
+ * before the copy. Space for the string in the var comes
+ * from interprocess shared memory. The allocated local var
+ * is returned at as a char *, or NULL on error.
+ */
+var_t *
+var_lvar_assign_string(char *name, char *string)
+{
+ var_t *var;
+ char *strptr;
+
+ var = var_lvar_alloc_local(name);
+
+ if (var == NULL) {
+ filebench_log(LOG_ERROR, "Cannot assign variable %s",
+ name);
+ return (NULL);
+ }
+
+ if ((strptr = ipc_stralloc(string)) == NULL) {
+ filebench_log(LOG_ERROR, "Cannot assign variable %s",
+ name);
+ return (NULL);
+ }
+ VAR_SET_STR(var, strptr);
+
+ filebench_log(LOG_DEBUG_SCRIPT,
+ "Lvar_assign_string (%s, %p)=%s", name, var, string);
+
+ return (var);
+}
+
+/*
* 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
@@ -1198,7 +1476,7 @@ var_find_environment(var_t *var)
* Look up special variables. The "name" argument is used to find
* the desired special var and fill it with an appropriate string
* value. Looks for an already allocated var of the same name on
- * the var_dyn_list. If not found a new dynamic var is allocated.
+ * the shm_var_dyn_list. If not found a new dynamic var is allocated.
* if the name begins with '{', it is an internal variable, and
* var_find_internal() is called. If the name begins with '(' it
* is an environment varable, and var_find_environment() is
@@ -1248,3 +1526,74 @@ var_find_dynamic(char *name)
return (NULL);
}
+
+/*
+ * replace the avd_t attribute value descriptor in the new FLOW_MASTER flowop
+ * that points to a local variable with a new avd_t containing
+ * the actual value from the local variable.
+ */
+void
+avd_update(avd_t *avdp, var_t *lvar_list)
+{
+ var_t *old_lvar, *new_lvar;
+
+ if ((*avdp)->avd_type == AVD_IND_VAR) {
+
+ /* Make sure there is a local var */
+ if ((old_lvar = (*avdp)->avd_val.varptr) == NULL) {
+ filebench_log(LOG_ERROR,
+ "avd_update: local var not found");
+ return;
+ }
+ } else {
+ /* Empty or not indirect, so no update needed */
+ return;
+ }
+
+ /* allocate a new avd using the new or old lvar contents */
+ if ((new_lvar =
+ var_find_list(old_lvar->var_name, lvar_list)) != NULL)
+ (*avdp) = avd_alloc_var_ptr(new_lvar);
+ else
+ (*avdp) = avd_alloc_var_ptr(old_lvar);
+}
+
+void
+var_update_comp_lvars(var_t *newlvar, var_t *proto_comp_vars,
+ var_t *mstr_lvars)
+{
+ var_t *proto_lvar;
+
+ /* find the prototype lvar from the inherited list */
+ proto_lvar = var_find_list_only(newlvar->var_name, proto_comp_vars);
+
+ if (proto_lvar == NULL)
+ return;
+
+ /*
+ * if the new local variable has not already been assigned
+ * a value, try to copy a value from the prototype local variable
+ */
+ if ((newlvar->var_type & VAR_TYPE_SET_MASK) == 0) {
+
+ /* copy value from prototype lvar to new lvar */
+ (void) var_copy(newlvar, proto_lvar);
+ }
+
+ /* If proto lvar is indirect, see if we can colapse indirection */
+ if (VAR_HAS_INDVAR(proto_lvar)) {
+ var_t *uplvp;
+
+ uplvp = (var_t *)proto_lvar->var_val.varptr;
+
+ /* search for more current uplvar on comp master list */
+ if (mstr_lvars) {
+ uplvp = var_find_list_only(
+ uplvp->var_name, mstr_lvars);
+ VAR_SET_INDVAR(newlvar, uplvp);
+ }
+
+ if (VAR_HAS_INDVAR(uplvp))
+ VAR_SET_INDVAR(newlvar, uplvp->var_val.varptr);
+ }
+}
diff --git a/usr/src/cmd/filebench/common/vars.h b/usr/src/cmd/filebench/common/vars.h
index af12a801fc..ede8dca983 100644
--- a/usr/src/cmd/filebench/common/vars.h
+++ b/usr/src/cmd/filebench/common/vars.h
@@ -87,18 +87,21 @@ typedef struct var {
double dbl_flt;
char *string;
struct randdist *randptr;
+ struct var *varptr;
} var_val;
} var_t;
#define VAR_TYPE_GLOBAL 0x00 /* global variable */
#define VAR_TYPE_DYNAMIC 0x01 /* Dynamic variable */
#define VAR_TYPE_RANDOM 0x02 /* random variable */
+#define VAR_TYPE_LOCAL 0x03 /* Local 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_INDVAR_SET 0x60 /* var points to another local var */
#define VAR_TYPE_SET_MASK 0xf0
#define VAR_HAS_BOOLEAN(vp) \
@@ -116,6 +119,9 @@ typedef struct var {
#define VAR_HAS_RANDDIST(vp) \
(((vp)->var_type & VAR_TYPE_SET_MASK) == VAR_TYPE_RAND_SET)
+#define VAR_HAS_INDVAR(vp) \
+ (((vp)->var_type & VAR_TYPE_SET_MASK) == VAR_TYPE_INDVAR_SET)
+
#define VAR_SET_BOOL(vp, val) \
{ \
(vp)->var_val.boolean = (val); \
@@ -134,41 +140,62 @@ typedef struct var {
{ \
(vp)->var_val.dbl_flt = (val); \
(vp)->var_type = \
- (((vp)->var_type & (~VAR_TYPE_SET_MASK)) | VAR_TYPE_DBL_SET); \
+ (((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); \
+ (((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);\
+ (((vp)->var_type & (~VAR_TYPE_SET_MASK)) | \
+ VAR_TYPE_RAND_SET); \
+ }
+
+#define VAR_SET_INDVAR(vp, val) \
+ { \
+ (vp)->var_val.varptr = (val); \
+ (vp)->var_type = \
+ (((vp)->var_type & (~VAR_TYPE_SET_MASK)) | \
+ VAR_TYPE_INDVAR_SET); \
}
avd_t avd_bool_alloc(boolean_t bool);
avd_t avd_int_alloc(fbint_t integer);
avd_t avd_str_alloc(char *string);
+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);
+void avd_update(avd_t *avdp, var_t *lvar_list);
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_double(char *name, double dbl);
int var_assign_string(char *name, char *string);
int var_assign_var(char *name, char *string);
+void var_update_comp_lvars(var_t *newlvar, var_t *proto_comp_vars,
+ var_t *mstr_lvars);
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);
+var_t *var_lvar_alloc_local(char *name);
+var_t *var_lvar_assign_boolean(char *name, boolean_t);
+var_t *var_lvar_assign_integer(char *name, fbint_t);
+var_t *var_lvar_assign_double(char *name, double);
+var_t *var_lvar_assign_string(char *name, char *string);
+var_t *var_lvar_assign_var(char *name, char *src_name);
char *var_to_string(char *name);
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