summaryrefslogtreecommitdiff
path: root/usr/src/cmd/filebench/common/flowop.c
diff options
context:
space:
mode:
authorJosef 'Jeff' Sipek <josef.sipek@nexenta.com>2014-04-28 16:13:37 -0400
committerRobert Mustacchi <rm@joyent.com>2014-05-05 07:37:48 -0700
commitd05b42383f649c1384ae2af878515cc2c6674ec6 (patch)
treebed8341c53c38b7ffa7d9a87f2fae20dba6a8ae5 /usr/src/cmd/filebench/common/flowop.c
parent5539384561c0efe744226d5e5d331f5546e500e4 (diff)
downloadillumos-gate-d05b42383f649c1384ae2af878515cc2c6674ec6.tar.gz
4821 remove filebench
Reviewed by: Dan McDonald <danmcd@omniti.com> Reviewed by: Garrett D'Amore <garrett@damore.org> Reviewed by: Richard Elling <richard.elling@gmail.com> Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src/cmd/filebench/common/flowop.c')
-rw-r--r--usr/src/cmd/filebench/common/flowop.c1210
1 files changed, 0 insertions, 1210 deletions
diff --git a/usr/src/cmd/filebench/common/flowop.c b/usr/src/cmd/filebench/common/flowop.c
deleted file mode 100644
index 4a527e2a44..0000000000
--- a/usr/src/cmd/filebench/common/flowop.c
+++ /dev/null
@@ -1,1210 +0,0 @@
-/*
- * 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 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#include "config.h"
-
-#ifdef HAVE_LWPS
-#include <sys/lwp.h>
-#endif
-#include <fcntl.h>
-#include "filebench.h"
-#include "flowop.h"
-#include "stats.h"
-
-#ifdef LINUX_PORT
-#include <sys/types.h>
-#include <linux/unistd.h>
-#endif
-
-static flowop_t *flowop_define_common(threadflow_t *threadflow, char *name,
- 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
- * implements the various flowops is in flowop_library.c.
- *
- * Routines for defining, creating, initializing and destroying
- * 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.
- */
-int
-flowop_printlist(flowop_t *list)
-{
- flowop_t *flowop = list;
-
- while (flowop) {
- filebench_log(LOG_DEBUG_IMPL, "flowop-list %s-%d",
- flowop->fo_name, flowop->fo_instance);
- flowop = flowop->fo_exec_next;
- }
- 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->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))
-/*
- * Puts current high resolution time in start time entry
- * for threadflow and may also calculate running filebench
- * overhead statistics.
- */
-void
-flowop_beginop(threadflow_t *threadflow, flowop_t *flowop)
-{
-#ifdef HAVE_PROCFS
- if ((filebench_shm->shm_mmode & FILEBENCH_MODE_NOUSAGE) == 0) {
- if ((noproc == 0) && (threadflow->tf_lwpusagefd == 0)) {
- char procname[128];
-
- (void) snprintf(procname, sizeof (procname),
- "/proc/%d/lwp/%d/lwpusage", my_pid, _lwp_self());
- threadflow->tf_lwpusagefd = open(procname, O_RDONLY);
- }
-
- (void) pread(threadflow->tf_lwpusagefd,
- &threadflow->tf_susage,
- sizeof (struct prusage), 0);
-
- /* Compute overhead time in this thread around op */
- if (threadflow->tf_eusage.pr_stime.tv_nsec) {
- flowop->fo_stats.fs_mstate[FLOW_MSTATE_OHEAD] +=
- TIMESPEC_TO_HRTIME(threadflow->tf_eusage.pr_utime,
- threadflow->tf_susage.pr_utime) +
- TIMESPEC_TO_HRTIME(threadflow->tf_eusage.pr_ttime,
- threadflow->tf_susage.pr_ttime) +
- TIMESPEC_TO_HRTIME(threadflow->tf_eusage.pr_stime,
- threadflow->tf_susage.pr_stime);
- }
- }
-#endif
-
- /* Start of op for this thread */
- threadflow->tf_stime = gethrtime();
-}
-
-flowstat_t controlstats;
-pthread_mutex_t controlstats_lock;
-static int controlstats_zeroed = 0;
-
-/*
- * Updates flowop's latency statistics, using saved start
- * time and current high resolution time. Updates flowop's
- * io count and transferred bytes statistics. Also updates
- * threadflow's and flowop's cumulative read or write byte
- * and io count statistics.
- */
-void
-flowop_endop(threadflow_t *threadflow, flowop_t *flowop, int64_t bytes)
-{
- hrtime_t t;
-
- flowop->fo_stats.fs_mstate[FLOW_MSTATE_LAT] +=
- (gethrtime() - threadflow->tf_stime);
-#ifdef HAVE_PROCFS
- if ((filebench_shm->shm_mmode & FILEBENCH_MODE_NOUSAGE) == 0) {
- if ((pread(threadflow->tf_lwpusagefd, &threadflow->tf_eusage,
- sizeof (struct prusage), 0)) != sizeof (struct prusage))
- filebench_log(LOG_ERROR, "cannot read /proc");
-
- t =
- TIMESPEC_TO_HRTIME(threadflow->tf_susage.pr_utime,
- threadflow->tf_eusage.pr_utime) +
- TIMESPEC_TO_HRTIME(threadflow->tf_susage.pr_ttime,
- threadflow->tf_eusage.pr_ttime) +
- TIMESPEC_TO_HRTIME(threadflow->tf_susage.pr_stime,
- threadflow->tf_eusage.pr_stime);
- flowop->fo_stats.fs_mstate[FLOW_MSTATE_CPU] += t;
-
- flowop->fo_stats.fs_mstate[FLOW_MSTATE_WAIT] +=
- TIMESPEC_TO_HRTIME(threadflow->tf_susage.pr_tftime,
- threadflow->tf_eusage.pr_tftime) +
- TIMESPEC_TO_HRTIME(threadflow->tf_susage.pr_dftime,
- threadflow->tf_eusage.pr_dftime) +
- TIMESPEC_TO_HRTIME(threadflow->tf_susage.pr_kftime,
- threadflow->tf_eusage.pr_kftime) +
- TIMESPEC_TO_HRTIME(threadflow->tf_susage.pr_kftime,
- threadflow->tf_eusage.pr_kftime) +
- TIMESPEC_TO_HRTIME(threadflow->tf_susage.pr_slptime,
- threadflow->tf_eusage.pr_slptime);
- }
-#endif
-
- 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++;
- controlstats.fs_bytes += bytes;
- }
- if (flowop->fo_attrs & FLOW_ATTR_READ) {
- threadflow->tf_stats.fs_rbytes += bytes;
- threadflow->tf_stats.fs_rcount++;
- flowop->fo_stats.fs_rcount++;
- controlstats.fs_rbytes += bytes;
- controlstats.fs_rcount++;
- } else if (flowop->fo_attrs & FLOW_ATTR_WRITE) {
- threadflow->tf_stats.fs_wbytes += bytes;
- threadflow->tf_stats.fs_wcount++;
- flowop->fo_stats.fs_wcount++;
- controlstats.fs_wbytes += bytes;
- controlstats.fs_wcount++;
- }
- (void) ipc_mutex_unlock(&controlstats_lock);
-}
-
-/*
- * Calls the flowop's initialization function, pointed to by
- * flowop->fo_init.
- */
-static int
-flowop_initflow(flowop_t *flowop)
-{
- /*
- * save static copies of two items, in case they are supplied
- * from random variables
- */
- if (!AVD_IS_STRING(flowop->fo_value))
- flowop->fo_constvalue = avd_get_int(flowop->fo_value);
-
- flowop->fo_constwss = avd_get_int(flowop->fo_wss);
-
- if ((*flowop->fo_init)(flowop) < 0) {
- filebench_log(LOG_ERROR, "flowop %s-%d init failed",
- flowop->fo_name, flowop->fo_instance);
- return (-1);
- }
- 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.
- */
-static void
-flowop_destructflow(flowop_t *flowop)
-{
- (*flowop->fo_destruct)(flowop);
-}
-
-/*
- * call the destruct funtions of all the threadflow's flowops,
- * if it is still flagged as "running".
- */
-void
-flowop_destruct_all_flows(threadflow_t *threadflow)
-{
- flowop_t *flowop;
-
- /* wait a moment to give other threads a chance to stop too */
- (void) sleep(1);
-
- (void) ipc_mutex_lock(&threadflow->tf_lock);
-
- /* prepare to call destruct flow routines, if necessary */
- if (threadflow->tf_running == 0) {
-
- /* allready destroyed */
- (void) ipc_mutex_unlock(&threadflow->tf_lock);
- return;
- }
-
- flowop = threadflow->tf_thrd_fops;
- threadflow->tf_running = 0;
- (void) ipc_mutex_unlock(&threadflow->tf_lock);
-
- while (flowop) {
- flowop_destructflow(flowop);
- flowop = flowop->fo_exec_next;
- }
-}
-
-/*
- * The final initialization and main execution loop for the
- * worker threads. Sets threadflow and flowop start times,
- * waits for all process to start, then creates the runtime
- * flowops from those defined by the F language workload
- * script. It does some more initialization, then enters a
- * loop to repeatedly execute the flowops on the flowop list
- * until an abort condition is detected, at which time it exits.
- * This is the starting routine for the new worker thread
- * created by threadflow_createthread(), and is not currently
- * called from anywhere else.
- */
-void
-flowop_start(threadflow_t *threadflow)
-{
- flowop_t *flowop;
- size_t memsize;
- int ret = FILEBENCH_OK;
-
-#ifdef HAVE_PROCFS
- if (noproc == 0) {
- char procname[128];
- long ctl[2] = {PCSET, PR_MSACCT};
- int pfd;
-
- (void) snprintf(procname, sizeof (procname),
- "/proc/%d/lwp/%d/lwpctl", my_pid, _lwp_self());
- pfd = open(procname, O_WRONLY);
- (void) pwrite(pfd, &ctl, sizeof (ctl), 0);
- (void) close(pfd);
- }
-#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_thrd_fops;
- threadflow->tf_stats.fs_stime = gethrtime();
- flowop->fo_stats.fs_stime = gethrtime();
-
- /* Hold the flowop find lock as reader to prevent lookups */
- (void) pthread_rwlock_rdlock(&filebench_shm->shm_flowop_find_lock);
-
- /*
- * Block until all processes have started, acting like
- * a barrier. The original filebench process initially
- * holds the run_lock as a reader, preventing any of the
- * threads from obtaining the writer lock, and hence
- * passing this point. Once all processes and threads
- * have been created, the original process unlocks
- * run_lock, allowing each waiting thread to lock
- * and then immediately unlock it, then begin running.
- */
- (void) pthread_rwlock_wrlock(&filebench_shm->shm_run_lock);
- (void) pthread_rwlock_unlock(&filebench_shm->shm_run_lock);
-
- /* Create the runtime flowops from those defined by the script */
- (void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock);
- 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);
-
- /* Release the find lock as reader to allow lookups */
- (void) pthread_rwlock_unlock(&filebench_shm->shm_flowop_find_lock);
-
- /* Set to the start of the new flowop list */
- flowop = threadflow->tf_thrd_fops;
-
- 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(memsize);
- } else {
- threadflow->tf_mem =
- malloc(memsize);
- }
-
- (void) memset(threadflow->tf_mem, 0, memsize);
- filebench_log(LOG_DEBUG_SCRIPT, "Thread allocated %d bytes", memsize);
-
-#ifdef HAVE_LWPS
- filebench_log(LOG_DEBUG_SCRIPT, "Thread %zx (%d) started",
- threadflow,
- _lwp_self());
-#endif
-
- /* Main filebench worker loop */
- while (ret == FILEBENCH_OK) {
- int i, count;
-
- /* Abort if asked */
- if (threadflow->tf_abort || filebench_shm->shm_f_abort)
- break;
-
- /* Be quiet while stats are gathered */
- if (filebench_shm->shm_bequiet) {
- (void) sleep(1);
- continue;
- }
-
- /* Take it easy until everyone is ready to go */
- if (!filebench_shm->shm_procs_running) {
- (void) sleep(1);
- continue;
- }
-
- if (flowop == NULL) {
- filebench_log(LOG_ERROR, "flowop_read null flowop");
- return;
- }
-
- if (flowop->fo_stats.fs_stime == 0)
- flowop->fo_stats.fs_stime = gethrtime();
-
- /* Execute the flowop for fo_iters times */
- count = (int)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);
-
- /*
- * Return value FILEBENCH_ERROR means "flowop
- * failed, stop the filebench run"
- */
- if (ret == FILEBENCH_ERROR) {
- filebench_log(LOG_ERROR,
- "%s-%d: flowop %s-%d failed",
- threadflow->tf_name,
- threadflow->tf_instance,
- flowop->fo_name,
- flowop->fo_instance);
- (void) ipc_mutex_lock(&threadflow->tf_lock);
- threadflow->tf_abort = 1;
- filebench_shm->shm_f_abort =
- FILEBENCH_ABORT_ERROR;
- (void) ipc_mutex_unlock(&threadflow->tf_lock);
- break;
- }
-
- /*
- * Return value of FILEBENCH_NORSC means "stop
- * the filebench run" if in "end on no work mode",
- * otherwise it indicates an error
- */
- if (ret == FILEBENCH_NORSC) {
- (void) ipc_mutex_lock(&threadflow->tf_lock);
- threadflow->tf_abort = FILEBENCH_DONE;
- if (filebench_shm->shm_rmode ==
- FILEBENCH_MODE_Q1STDONE) {
- filebench_shm->shm_f_abort =
- FILEBENCH_ABORT_RSRC;
- } else if (filebench_shm->shm_rmode !=
- FILEBENCH_MODE_QALLDONE) {
- filebench_log(LOG_ERROR1,
- "WARNING! Run stopped early:\n "
- " flowop %s-%d could "
- "not obtain a file. Please\n "
- " reduce runtime, "
- "increase fileset entries "
- "($nfiles), or switch modes.",
- flowop->fo_name,
- flowop->fo_instance);
- filebench_shm->shm_f_abort =
- FILEBENCH_ABORT_ERROR;
- }
- (void) ipc_mutex_unlock(&threadflow->tf_lock);
- break;
- }
-
- /*
- * Return value of FILEBENCH_DONE means "stop
- * the filebench run without error"
- */
- if (ret == FILEBENCH_DONE) {
- (void) ipc_mutex_lock(&threadflow->tf_lock);
- threadflow->tf_abort = FILEBENCH_DONE;
- filebench_shm->shm_f_abort =
- FILEBENCH_ABORT_DONE;
- (void) ipc_mutex_unlock(&threadflow->tf_lock);
- break;
- }
-
- /*
- * If we get here and the return is something other
- * than FILEBENCH_OK, it means a spurious code
- * was returned, so treat as major error. This
- * probably indicates a bug in the flowop.
- */
- if (ret != FILEBENCH_OK) {
- filebench_log(LOG_ERROR,
- "Flowop %s unexpected return value = %d\n",
- flowop->fo_name, ret);
- filebench_shm->shm_f_abort =
- FILEBENCH_ABORT_ERROR;
- break;
- }
- }
-
- /* advance to next flowop */
- flowop = flowop->fo_exec_next;
-
- /* but if at end of list, start over from the beginning */
- if (flowop == NULL) {
- flowop = threadflow->tf_thrd_fops;
- threadflow->tf_stats.fs_count++;
- }
- }
-
-#ifdef HAVE_LWPS
- filebench_log(LOG_DEBUG_SCRIPT, "Thread %d exiting",
- _lwp_self());
-#endif
-
- /* Tell flowops to destroy locally acquired state */
- flowop_destruct_all_flows(threadflow);
-
- pthread_exit(&threadflow->tf_abort);
-}
-
-void flowoplib_flowinit(void);
-void fb_lfs_flowinit(void);
-
-void
-flowop_init(void)
-{
- (void) pthread_mutex_init(&controlstats_lock,
- ipc_mutexattr(IPC_MUTEX_NORMAL));
- flowoplib_flowinit();
-}
-
-static int plugin_flowinit_done = FALSE;
-
-/*
- * Initialize any "plug-in" flowops. Called when the first "create fileset"
- * command is encountered.
- */
-void
-flowop_plugin_flowinit(void)
-{
- if (plugin_flowinit_done)
- return;
-
- plugin_flowinit_done = TRUE;
-
- switch (filebench_shm->shm_filesys_type) {
- case LOCAL_FS_PLUG:
- fb_lfs_flowinit();
- break;
-
- case NFS3_PLUG:
- case NFS4_PLUG:
- case CIFS_PLUG:
- break;
- }
-}
-
-
-/*
- * Delete the designated flowop from the thread's flowop list.
- */
-static void
-flowop_delete(flowop_t **flowoplist, flowop_t *flowop)
-{
- flowop_t *entry = *flowoplist;
- int found = 0;
-
- filebench_log(LOG_DEBUG_IMPL, "Deleting flowop (%s-%d)",
- flowop->fo_name,
- flowop->fo_instance);
-
- /* Delete from thread's flowop list */
- if (flowop == *flowoplist) {
- /* First on list */
- *flowoplist = flowop->fo_exec_next;
- filebench_log(LOG_DEBUG_IMPL,
- "Delete0 flowop: (%s-%d)",
- flowop->fo_name,
- flowop->fo_instance);
- } else {
- while (entry->fo_exec_next) {
- filebench_log(LOG_DEBUG_IMPL,
- "Delete0 flowop: (%s-%d) == (%s-%d)",
- entry->fo_exec_next->fo_name,
- entry->fo_exec_next->fo_instance,
- flowop->fo_name,
- flowop->fo_instance);
-
- if (flowop == entry->fo_exec_next) {
- /* Delete */
- filebench_log(LOG_DEBUG_IMPL,
- "Deleted0 flowop: (%s-%d)",
- 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_exec_next;
- }
- }
-
-#ifdef HAVE_PROCFS
- /* Close /proc stats */
- if (flowop->fo_thread)
- (void) close(flowop->fo_thread->tf_lwpusagefd);
-#endif
-
- /* Delete from global list */
- entry = filebench_shm->shm_flowoplist;
-
- if (flowop == filebench_shm->shm_flowoplist) {
- /* First on list */
- filebench_shm->shm_flowoplist = flowop->fo_next;
- found = 1;
- } else {
- while (entry->fo_next) {
- filebench_log(LOG_DEBUG_IMPL,
- "Delete flowop: (%s-%d) == (%s-%d)",
- entry->fo_next->fo_name,
- entry->fo_next->fo_instance,
- flowop->fo_name,
- flowop->fo_instance);
-
- if (flowop == entry->fo_next) {
- /* Delete */
- entry->fo_next = entry->fo_next->fo_next;
- found = 1;
- break;
- }
-
- entry = entry->fo_next;
- }
- }
- if (found) {
- filebench_log(LOG_DEBUG_IMPL,
- "Deleted flowop: (%s-%d)",
- flowop->fo_name,
- flowop->fo_instance);
- ipc_free(FILEBENCH_FLOWOP, (char *)flowop);
- } else {
- filebench_log(LOG_DEBUG_IMPL, "Flowop %s-%d not found!",
- flowop->fo_name,
- flowop->fo_instance);
- }
-}
-
-/*
- * Deletes all the flowops from a flowop list.
- */
-void
-flowop_delete_all(flowop_t **flowoplist)
-{
- flowop_t *flowop = *flowoplist;
- flowop_t *next_flowop;
-
- (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);
-
- if (flowop->fo_instance &&
- (flowop->fo_instance == FLOW_MASTER)) {
- flowop = flowop->fo_exec_next;
- continue;
- }
- next_flowop = flowop->fo_exec_next;
- flowop_delete(flowoplist, flowop);
- flowop = next_flowop;
- }
-
- (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock);
-}
-
-/*
- * Allocates a flowop entity and initializes it with inherited
- * contents from the "inherit" flowop, if it is supplied, or
- * with zeros otherwise. In either case the fo_next and fo_exec_next
- * pointers are set to NULL, and fo_thread is set to point to
- * the owning threadflow. The initialized flowop is placed at
- * the head of the global flowop list, and also placed on the
- * tail of the supplied local flowop list, which will either
- * be a threadflow's tf_thrd_fops list or a composite flowop's
- * fo_comp_fops list. The routine locks the flowop's fo_lock and
- * leaves it held on return. If successful, it returns a pointer
- * to the allocated and initialized flowop, otherwise it returns NULL.
- *
- * filebench_shm->shm_flowop_lock must be held by caller.
- */
-static flowop_t *
-flowop_define_common(threadflow_t *threadflow, char *name, flowop_t *inherit,
- flowop_t **flowoplist_hdp, int instance, int type)
-{
- flowop_t *flowop;
-
- if (name == NULL)
- return (NULL);
-
- if ((flowop = (flowop_t *)ipc_malloc(FILEBENCH_FLOWOP)) == NULL) {
- filebench_log(LOG_ERROR,
- "flowop_define: Can't malloc flowop");
- return (NULL);
- }
-
- filebench_log(LOG_DEBUG_IMPL, "defining flowops %s-%d, addr %zx",
- name, instance, flowop);
-
- if (flowop == NULL)
- return (NULL);
-
- if (inherit) {
- (void) memcpy(flowop, inherit, sizeof (flowop_t));
- (void) pthread_mutex_init(&flowop->fo_lock,
- ipc_mutexattr(IPC_MUTEX_PRI_ROB));
- (void) ipc_mutex_lock(&flowop->fo_lock);
- flowop->fo_next = NULL;
- flowop->fo_exec_next = NULL;
- filebench_log(LOG_DEBUG_IMPL,
- "flowop %s-%d calling init", name, instance);
- } else {
- (void) memset(flowop, 0, sizeof (flowop_t));
- flowop->fo_iters = avd_int_alloc(1);
- flowop->fo_type = type;
- (void) pthread_mutex_init(&flowop->fo_lock,
- ipc_mutexattr(IPC_MUTEX_PRI_ROB));
- (void) ipc_mutex_lock(&flowop->fo_lock);
- }
-
- /* Create backpointer to thread */
- flowop->fo_thread = threadflow;
-
- /* Add flowop to global list */
- if (filebench_shm->shm_flowoplist == NULL) {
- filebench_shm->shm_flowoplist = flowop;
- flowop->fo_next = NULL;
- } else {
- flowop->fo_next = filebench_shm->shm_flowoplist;
- filebench_shm->shm_flowoplist = flowop;
- }
-
- (void) strcpy(flowop->fo_name, name);
- flowop->fo_instance = instance;
-
- if (flowoplist_hdp == NULL)
- return (flowop);
-
- /* Add flowop to thread op list */
- if (*flowoplist_hdp == NULL) {
- *flowoplist_hdp = flowop;
- flowop->fo_exec_next = NULL;
- } else {
- flowop_t *flowend;
-
- /* Find the end of the thread list */
- flowend = *flowoplist_hdp;
- while (flowend->fo_exec_next != NULL)
- flowend = flowend->fo_exec_next;
- flowend->fo_exec_next = flowop;
- flowop->fo_exec_next = NULL;
- }
-
- return (flowop);
-}
-
-/*
- * Calls flowop_define_common() to allocate and initialize a
- * flowop, and holds the shared flowop_lock during the call.
- * It releases the created flowop's fo_lock when done.
- */
-flowop_t *
-flowop_define(threadflow_t *threadflow, char *name, flowop_t *inherit,
- 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, 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);
-}
-
-/*
- * Attempts to take a write lock on the flowop_find_lock that is
- * defined in interprocess shared memory. Since each call to
- * flowop_start() holds a read lock on flowop_find_lock, this
- * routine effectively blocks until all instances of
- * flowop_start() have finished. The flowop_find() routine calls
- * this routine so that flowops won't be searched for until all
- * flowops have been created by flowop_start.
- */
-static void
-flowop_find_barrier(void)
-{
- /* Block on wrlock to ensure find waits for all creates */
- (void) pthread_rwlock_wrlock(&filebench_shm->shm_flowop_find_lock);
- (void) pthread_rwlock_unlock(&filebench_shm->shm_flowop_find_lock);
-}
-
-/*
- * Returns a list of flowops named "name" from the master
- * flowop list.
- */
-flowop_t *
-flowop_find(char *name)
-{
- flowop_t *flowop;
- flowop_t *result = NULL;
-
- flowop_find_barrier();
-
- (void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock);
-
- flowop = filebench_shm->shm_flowoplist;
-
- while (flowop) {
- if (strcmp(name, flowop->fo_name) == 0) {
-
- /* Add flowop to result list */
- if (result == NULL) {
- result = flowop;
- flowop->fo_resultnext = NULL;
- } else {
- flowop->fo_resultnext = result;
- result = flowop;
- }
- }
- flowop = flowop->fo_next;
- }
-
- (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock);
-
-
- return (result);
-}
-
-/*
- * Returns a pointer to the specified instance of flowop
- * "name" from the global list.
- */
-flowop_t *
-flowop_find_one(char *name, int instance)
-{
- flowop_t *test_flowop;
-
- flowop_find_barrier();
-
- (void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock);
-
- test_flowop = filebench_shm->shm_flowoplist;
-
- while (test_flowop) {
- if ((strcmp(name, test_flowop->fo_name) == 0) &&
- (instance == test_flowop->fo_instance))
- break;
-
- test_flowop = test_flowop->fo_next;
- }
-
- (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock);
-
- return (test_flowop);
-}
-
-/*
- * recursively searches through lists of flowops on a given thread
- * and those on any included composite flowops for the named flowop.
- * either returns with a pointer to the named flowop or NULL if it
- * cannot be found.
- */
-static flowop_t *
-flowop_recurse_search(char *path, char *name, flowop_t *list)
-{
- flowop_t *test_flowop;
- char fullname[MAXPATHLEN];
-
- test_flowop = list;
-
- /*
- * when searching a list of inner flowops, "path" is the fullname
- * of the containing composite flowop. Use it to form the
- * full name of the inner flowop to search for.
- */
- if (path) {
- if ((strlen(path) + strlen(name) + 1) > MAXPATHLEN) {
- filebench_log(LOG_ERROR,
- "composite flowop path name %s.%s too long",
- path, name);
- return (NULL);
- }
-
- /* create composite_name.name for recursive search */
- (void) strcpy(fullname, path);
- (void) strcat(fullname, ".");
- (void) strcat(fullname, name);
- } else {
- (void) strcpy(fullname, name);
- }
-
- /*
- * loop through all flowops on the supplied tf_thrd_fops (flowop)
- * list or fo_comp_fops (inner flowop) list.
- */
- while (test_flowop) {
- if (strcmp(fullname, test_flowop->fo_name) == 0)
- return (test_flowop);
-
- if (test_flowop->fo_type == FLOW_TYPE_COMPOSITE) {
- flowop_t *found_flowop;
-
- found_flowop = flowop_recurse_search(
- test_flowop->fo_name, name,
- test_flowop->fo_comp_fops);
-
- if (found_flowop)
- return (found_flowop);
- }
- test_flowop = test_flowop->fo_exec_next;
- }
-
- /* not found here or on any child lists */
- return (NULL);
-}
-
-/*
- * Returns a pointer to flowop named "name" from the supplied tf_thrd_fops
- * list of flowops. Returns the named flowop if found, or NULL.
- */
-flowop_t *
-flowop_find_from_list(char *name, flowop_t *list)
-{
- flowop_t *found_flowop;
-
- flowop_find_barrier();
-
- (void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock);
-
- found_flowop = flowop_recurse_search(NULL, name, list);
-
- (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock);
-
- return (found_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;
- }
-}
-
-/*
- * Support routines for libraries of flowops
- */
-
-int
-flowop_init_generic(flowop_t *flowop)
-{
- (void) ipc_mutex_unlock(&flowop->fo_lock);
- return (FILEBENCH_OK);
-}
-
-void
-flowop_destruct_generic(flowop_t *flowop)
-{
- char *buf;
-
- /* release any local resources held by the flowop */
- (void) ipc_mutex_lock(&flowop->fo_lock);
- buf = flowop->fo_buf;
- flowop->fo_buf = NULL;
- (void) ipc_mutex_unlock(&flowop->fo_lock);
-
- if (buf)
- free(buf);
-}
-
-
-/*
- * Loops through the supplied list of flowops and creates and initializes
- * a flowop for each one by calling flowop_define. As a side effect of
- * calling flowop define, the created flowops are placed on the
- * master flowop list. All created flowops are set to instance "0".
- */
-void
-flowop_flow_init(flowop_proto_t *list, int nops)
-{
- int i;
-
- for (i = 0; i < nops; i++) {
- flowop_t *flowop;
- flowop_proto_t *fl;
-
- fl = &(list[i]);
-
- if ((flowop = flowop_define(NULL,
- fl->fl_name, NULL, NULL, 0, fl->fl_type)) == 0) {
- filebench_log(LOG_ERROR,
- "failed to create flowop %s\n",
- fl->fl_name);
- filebench_shutdown(1);
- }
-
- flowop->fo_func = fl->fl_func;
- flowop->fo_init = fl->fl_init;
- flowop->fo_destruct = fl->fl_destruct;
- flowop->fo_attrs = fl->fl_attrs;
- }
-}