parser_gram.y revision f2fc321be9b4df7748e8c31a5edd154b0177b139
/*
* 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
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
%{
#pragma ident "%Z%%M% %I% %E% SMI"
%}
%{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <locale.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <fcntl.h>
#ifdef HAVE_LIBTECLA
#include <libtecla.h>
#endif
#include "parsertypes.h"
#include "filebench.h"
#include "utils.h"
#include "stats.h"
#include "vars.h"
#include "eventgen.h"
#ifdef HAVE_LIBTECLA
#include "auto_comp.h"
#endif
static const char cmdname[] = "filebench";
static const char cmd_options[] = "pa:f:hi:s:m:";
static void usage(int);
#ifdef HAVE_LIBTECLA
#endif
char *execname;
char *fscriptname;
int noproc = 0;
/* yacc externals */
extern int yydebug;
extern void yyerror(char *s);
/* utilities */
static void terminate(void);
static attr_t *alloc_attr(void);
static list_t *alloc_list();
/* Info Commands */
static void parser_show(cmd_t *);
static void parser_list(cmd_t *);
/* Define Commands */
static void parser_proc_define(cmd_t *);
static void parser_file_define(cmd_t *);
static void parser_fileset_define(cmd_t *);
/* Create Commands */
static void parser_proc_create(cmd_t *);
static void parser_thread_create(cmd_t *);
static void parser_flowop_create(cmd_t *);
static void parser_file_create(cmd_t *);
static void parser_fileset_create(cmd_t *);
/* Shutdown Commands */
static void parser_proc_shutdown(cmd_t *);
/* Other Commands */
static void parser_abort(int arg);
%}
%union {
char * sval;
}
%%
{
free($2);
}
{
if (dofile)
}
|;
{
$$ = $1;
}
{
/* Find end of list */
"inner_commands adding cmd %zx to list %zx", $2, $1);
$$ = $1;
};
| quit_command;
{
}
{
$$ = $1;
$$->cmd_list = $6;
$$->cmd_tgt1 = $2;
$$->cmd_param_list = $4;
$$->cmd = parser_foreach_integer;
"packing foreach: %zx %s=%lld, cmd %zx",
$$,
$$->cmd_tgt1,
}
}
{
$$ = $1;
$$->cmd_list = $6;
$$->cmd_tgt1 = $2;
$$->cmd_param_list = $4;
$$->cmd = parser_foreach_string;
"packing foreach: %zx %s=%s, cmd %zx",
$$,
$$->cmd_tgt1,
}
}
};
{
if (($$ = alloc_list()) == NULL)
}
{
if (($$ = alloc_list()) == NULL)
/* Find end of list */
$$ = $1;
};
{
if (($$ = alloc_list()) == NULL)
}
{
if (($$ = alloc_list()) == NULL)
/* Find end of list */
$$ = $1;
};
{
$$->cmd = &parser_eventgen;
}
{
};
{
$$->cmd_param_list = $2;
$$->cmd = parser_system;
};
{
$$->cmd_param_list = $2;
$$->cmd = parser_echo;
};
{
$$->cmd_param_list = $2;
$$->cmd = parser_usage;
};
{
$$->cmd = parser_printvars;
};
{
if (($$ = alloc_list()) == NULL)
}
{
if (($$ = alloc_list()) == NULL)
/* Find end of list */
$$ = $1;
};
{
if (($$ = alloc_list()) == NULL)
}
{
if (($$ = alloc_list()) == NULL)
};
{
$$ = $1;
{
/* Add string */
if (($$ = alloc_list()) == NULL)
/* Find end of list */
$$ = $1;
{
/* Add variable */
if (($$ = alloc_list()) == NULL)
/* Find end of list */
$$ = $1;
{
/* Add string */
if (($$ = alloc_list()) == NULL)
/* Find end of list */
$$ = $1;
{
/* Add variable */
if (($$ = alloc_list()) == NULL)
/* Find end of list */
$$ = $1;
};
{
if (($$ = alloc_list()) == NULL)
}
{
if (($$ = alloc_list()) == NULL)
};
{
/* Add string */
if (($$ = alloc_list()) == NULL)
/* Find end of list */
$$ = $1;
{
/* Add variable */
if (($$ = alloc_list()) == NULL)
/* Find end of list */
$$ = $1;
{
/* Add string */
if (($$ = alloc_list()) == NULL)
/* Find end of list */
$$ = $1;
{
/* Add variable */
if (($$ = alloc_list()) == NULL)
/* Find end of list */
$$ = $1;
{
$$ = $1;
{
$$ = $1;
};
{
$$->cmd = &parser_list;
};
{
$$->cmd = &parser_log;
$$->cmd_param_list = $2;
};
{
yydebug = 1;
};
{
if (parentscript) {
$$->cmd_tgt1 = $2;
parser_vars($$);
}
}
{
if (parentscript) {
$$->cmd_tgt1 = $2;
parser_vars($$);
}
{
if (parentscript) {
$$->cmd_tgt1 = $2;
parser_vars($$);
}
{
if (parentscript) {
$$->cmd_tgt1 = $2;
parser_vars($$);
}
};
{
break;
}
{
}
{
$$->cmd_param_list = $3;
}
{
$$->cmd_param_list = $3;
$$->cmd = parser_statscmd;
{
$$->cmd_param_list = $3;
$$->cmd = parser_statsdump;
{
$$->cmd_param_list = $3;
$$->cmd = parser_statsxmldump;
};
{
$$->cmd = parser_filebench_shutdown;
};
{
$$ = $1;
{
/* Find end of list */
"flowop_list adding cmd %zx to list %zx", $2, $1);
$$ = $1;
};
{
/*
* Allocate a cmd node per thread, with a
* list of flowops attached to the cmd_list
*/
$$->cmd_list = $4;
$$->cmd_attr_list = $2;
};
{
$$ = $1;
{
/* Find end of list */
"thread_list adding cmd %zx to list %zx", $2, $1);
$$ = $1;
};
{
$$->cmd = &parser_proc_define;
$$->cmd_list = $5;
$$->cmd_attr_list = $3;
{
$$->cmd = &parser_file_define;
{
$$->cmd = &parser_fileset_define;
}
{
};
{
switch ($2) {
case FSE_PROC:
$$->cmd = &parser_proc_create;
break;
case FSE_FILE:
$$->cmd = &parser_file_create;
break;
case FSE_FILESET:
$$->cmd = &parser_fileset_create;
break;
default:
}
};
{
switch ($2) {
case FSE_PROC:
$$->cmd = &parser_proc_shutdown;
break;
default:
}
};
{
$$->cmd = parser_sleep;
$$->cmd_qty = $2;
}
{
$$->cmd = parser_sleep_variable;
};
{
$$->cmd = parser_run;
$$->cmd_qty = $2;
}
{
$$->cmd = parser_run_variable;
}
| FSC_RUN
{
$$->cmd = parser_run;
$$->cmd_qty = 60UL;
};
{
$$->cmd = parser_help;
};
{
}
{
};
{
char loadfile[128];
}
}
parentscript = yyin;
};
| FSE_THREAD {$$ = FSE_THREAD;}
| FSE_FILESET {$$ = FSE_FILESET;}
| FSV_STRING { $$.s = $1;}
| FSV_VAL_BOOLEAN { $$.b = $1;};
{
$$ = $1;
}
{
$$ = $1;
};
{
$$ = $3;
$$->attr_name = $1;
}
{
if (($$ = alloc_attr()) == NULL)
$$->attr_name = $1;
}
|FSA_INSTANCES { $$ = FSA_INSTANCES;};
| FSA_PREALLOC { $$ = FSA_PREALLOC;}
| FSA_PARALLOC { $$ = FSA_PARALLOC;};
| FSA_DIRWIDTH { $$ = FSA_DIRWIDTH;}
| FSA_PREALLOC { $$ = FSA_PREALLOC;}
| FSA_FILESIZEGAMMA { $$ = FSA_FILESIZEGAMMA;}
| FSA_DIRGAMMA { $$ = FSA_DIRGAMMA;}
| FSA_CACHED { $$ = FSA_CACHED;}
| FSA_ENTRIES { $$ = FSA_ENTRIES;};
FSA_PROCESS { $$ = FSA_PROCESS;}
|FSA_MEMSIZE { $$ = FSA_MEMSIZE;}
|FSA_USEISM { $$ = FSA_USEISM;}
|FSA_INSTANCES { $$ = FSA_INSTANCES;};
|FSA_RANDOM { $$ = FSA_RANDOM;}
|FSA_ROTATEFD { $$ = FSA_ROTATEFD;}
|FSA_DIRECTIO { $$ = FSA_DIRECTIO;}
|FSA_TARGET { $$ = FSA_TARGET;}
|FSA_BLOCKING { $$ = FSA_BLOCKING;}
|FSA_HIGHWATER { $$ = FSA_HIGHWATER;}
|FSA_IOSIZE { $$ = FSA_IOSIZE;};
if (($$ = alloc_attr()) == NULL)
$$->attr_param_list = $1;
} | FSV_STRING
{
if (($$ = alloc_attr()) == NULL)
} | FSV_VAL_INT {
if (($$ = alloc_attr()) == NULL)
} | FSV_VARIABLE {
if (($$ = alloc_attr()) == NULL)
};
%%
/*
* The following 'c' routines implement the various commands defined in the
* above yacc parser code. The yacc portion checks the syntax of the commands
* found in a workload file, or typed on interactive command lines, parsing
* the commands' parameters into lists. The lists are then passed in a cmd_t
* struct for each command to its related routine in the following section
* for actual execution. This section also includes a few utility routines
* and the main entry point for the program.
*/
/*
* Entry point for filebench. Processes command line arguements. The -f
* option will read in a workload file (the full name and extension must
* must be given). The -a, -s, -m and -i options are used by worker process
* to receive their name, the base address of shared memory, its path, and
* the process' instance number, respectively. This information is supplied
* by the master process when it execs worker processes under the process
* model of execution. If the worker process arguments are passed then main
* will call the procflow_exec routine which creates worker threadflows and
* flowops and executes the procflow's portion of the workload model until
* completion. If worker process arguments are not passed to the process,
* then it becomes the master process for a filebench run. It initializes
* the various filebench components and either executes the supplied workload
* file, or enters interactive mode.
*/
int
{
int opt;
int instance;
char procname[128];
char dir[MAXPATHLEN];
#ifdef HAVE_SETRLIMIT
#endif
#ifdef HAVE_LIBTECLA
char *line;
#else
char line[1024];
#endif
char shmpathtmp[1024];
#ifdef HAVE_SETRLIMIT
/* Set resource limits */
#endif
yydebug = 0;
*procname = 0;
switch (opt) {
case 'h':
usage(2);
break;
case 'p':
noproc = 1;
break;
case 'f':
usage(1);
"Cannot open file %s", optarg);
exit(1);
}
break;
case 'a':
usage(1);
break;
case 's':
usage(1);
#else
#endif
break;
case 'm':
usage(1);
break;
case 'i':
usage(1);
break;
case '?':
default:
usage(1);
break;
}
}
#ifdef USE_PROCESS_MODEL
if (!(*procname))
#endif
#ifdef USE_PROCESS_MODEL
if (*procname) {
if (ipc_attach(shmaddr) < 0) {
procname);
exit(1);
}
procname);
exit(1);
}
exit(1);
}
#endif
ipc_init();
if (fscriptname)
flowop_init();
stats_init();
if (dofile)
yyparse();
else {
#ifdef HAVE_LIBTECLA
"Failed to create GetLine object");
}
"Failed to register auto-completion function");
}
yyparse();
}
#else
continue;
else
break;
}
yyparse();
}
printf("\n");
#endif /* HAVE_LIBTECLA */
}
parser_filebench_shutdown((cmd_t *)0);
return (0);
}
/*
* arg_parse() puts the parser into command parsing mode. Create a tmpfile
* and instruct the parser to read instructions from this location by setting
* yyin to the value returned by tmpfile. Write the command into the file.
* Then seek back to to the start of the file so that the parser can read
* the instructions.
*/
static void
{
}
/*
* Converts a list of var_strings or ordinary strings to a single ordinary
* string. It returns a pointer to the string (in malloc'd memory) if found,
* or NULL otherwise.
*/
char *
{
list_t *l;
char *string;
char *tmp;
return (NULL);
}
*string = 0;
/* Format args */
l = l->list_next) {
"converting string '%s'", *l->list_string);
} else {
}
}
return (string);
}
/*
* If the list just contains a single string starting with '$', then find
* or create the named var and return the var's var_string component.
* Otherwise, convert the list to a string, and allocate a var_string
* containing a copy of that string. On failure either returns NULL
* or shuts down the run.
*/
{
/* Special case - variable name */
}
/*
* 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.
*/
{
return (v);
}
return (NULL);
}
/*
* Sets the event generator rate from the attribute supplied with the
* command. If the attribute doesn't exist the routine does nothing.
*/
static void
{
/* Get the rate from attribute */
if (attr->attr_integer) {
"Eventgen: %lld per second",
*attr->attr_integer);
}
}
}
/*
* Assigns the designated integer variable successive values from the
* supplied comma seperated integer list. After each successive integer
* assignment, it executes the bracket enclosed list of commands. For
* example, repeated runs of a workload with increasing io sizes can
* be done using the following command line:
* foreach $iosize in 2k, 4k, 8k {run 60}
*/
static void
{
*list->list_integer);
}
}
}
/*
* Similar to parser_foreach_integer(), except takes a list of strings after
* the "in" token. For example, to run twice using a different directory,
* perhaps using a different filesystem, the following command line
* could be used:
*/
static void
{
*list->list_string);
}
}
}
/*
* Lists the file name, path name and file size for all defined file objects.
*/
static void
{
(void) fileobj_iter(fileobj_print);
}
/*
* 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
* pf_nice. Finally the routine loops through the list of inner commands, if
* any, which are defines for threadflows, and passes them one at a time to
* parser_thread_define() to allocate threadflow entities for the process(es).
*/
static void
{
char *name;
/* Get the name of the process */
} else {
"define proc: proc specifies no name");
}
/* Get the memory size from attribute */
"Setting instances = %lld",
*attr->attr_integer);
}
"Failed to instantiate %d %s process(es)\n",
}
/* Get the pri from attribute */
*attr->attr_integer);
} else
/* Create the list of threads for this process */
}
}
/*
* Calls threadflow_define() to allocate "instances" number of threadflow(s)
* (threads) with the supplied name. The default number of instances is
* one. Two other optional attributes may be supplied, one to set the memory
* size, stored in tf_memsize, and to select the use of Interprocess Shared
* Memory, which sets the THREADFLOW_USEISM flag in tf_attrs. Finally
* the routine loops through the list of inner commands, if any, which are
* defines for flowops, and passes them one at a time to
* parser_flowop_define() to allocate flowop entities for the threadflows.
*/
static void
{
char *name;
/* Get the name of the thread */
} else {
"define thread: thread in process %s specifies no name",
}
/* Get the number of instances from attribute */
"define thread: Setting instances = %lld",
*attr->attr_integer);
}
/* Get the memory size from attribute */
"define thread: Setting memsize = %lld",
*attr->attr_integer);
} else
"define thread: Failed to instantiate thread\n");
}
/* Use ISM Memory? */
}
/* Create the list of flowops */
}
}
/*
* Calls flowop_define() to allocate a flowop with the supplied name.
* The allocated flowop inherits attributes from a base flowop of the
* same type. If the new flowop has a file or fileset attribute specified,
* it must specify a defined fileobj or fileset or an error will be logged.
* The new flowop may also have the following attributes set by
* the program:
* - file size (fo_iosize)
* - working set size (fo_wss)
* - do random io (fo_random)
* - do synchronous io (fo_dsync)
* - perform each operation multiple times before advancing (fo_iter)
* - target name (fo_targetname)
* - An integer value (fo_value)
* - a file descriptor (fo_fd)
* - specify to rotate file descriptors (fo_rotatefd)
* - a source fd (fo_srcfdnumber)
* - specify a blocking operation (fo_blocking)
* - specify a highwater mark (fo_highwater)
*
* After all the supplied attributes are stored in their respective locations
* in the flowop object, the flowop's init function is called. No errors are
* returned, but the filebench run will be terminated if the flowtype is not
* specified, a name for the new flowop is not supplied, the flowop_define
* call fails, or a file or fileset name is supplied but the corresponding
* fileobj or fileset cannot be located.
*/
static void
{
char *name;
/* Get the inherited flowop */
if (flowop_type == NULL) {
"define flowop: flowop type %s not found",
type);
}
/* Get the name of the flowop */
} else {
"define flowop: flowop %s specifies no name",
}
"define flowop: Failed to instantiate flowop %s\n",
}
/* Get the filename from attribute */
"define flowop: file %s not found",
*attr->attr_string);
}
}
/* Get the iosize of the op */
else
/* Get the working set size of the op */
else
/* Random I/O? */
else
/* Sync I/O? */
else
/* Iterations */
else
/* Target, for wakeup etc */
/* Value */
else
/* FD */
/* Rotatefd? */
else
/* SRC FD, for copies etc... */
/* Blocking operation? */
else
/* Blocking operation? */
else
/* Highwater mark */
else
}
/*
* Calls fileobj_define() to allocate a fileobj with the supplied name
* and initializes the fileobj's pathname attribute, fo_path and fo_create,
* and optionally the fo_prealloc, fo_paralloc, fo_reuse, fo_cached,
* and fo_size attributes.
*/
static void
{
char *name;
/* Get the name of the file */
} else {
"define file: file specifies no name");
return;
}
"define file: failed to instantiate file %s\n",
return;
}
/* Get the pathname from attribute */
"define file: no pathname specified");
return;
}
/* Expand variables in pathname */
== NULL) {
return;
}
/* For now, all files are pre-created */
/* Should we preallocate? */
} else
/* Should we prealloc in parallel? */
} else
/* Should we reuse the existing file? */
} else
/* Should we leave in cache? */
} else
/* Get the size of the file */
} else
}
/*
* 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_preallocpercent, fs_prealloc, fs_entries, fs_dirwidth,
* fs_size, fs_dirgamma, and fs_sizegamma attributes.
*/
static void
{
char *name;
/* Get the name of the file */
} else {
"define file: file specifies no name");
return;
}
"define file: failed to instantiate file %s\n",
return;
}
/* Get the pathname from attribute */
return;
}
/* Expand variables in pathname */
return;
}
/* Should we leave in cache? */
} else
/* Should we reuse the existing file? */
} else
/* How much should we prealloc */
attr->attr_integer) {
} else {
}
/* Should we preallocate? */
} else
/* Get the size of the fileset */
} else {
}
/* Get the mean dir width of the fileset */
} else {
}
/* Get the mean or absolute size of the file */
} else
/* Get the gamma value for dir width distributions */
} else
/* Get the gamma value for dir width distributions */
} else
}
/*
* Creates and starts all defined procflow processes. The call to
* procflow_init() results in creation of the requested number of
* process instances for each previously defined procflow. The
* child processes exec() a new instance of filebench, passing it
* the instance number and address of the shared memory region.
* The child processes will then create their threads and flowops.
* The routine then unlocks the run_lock to allow all the processes'
* threads to start and waits for all of them to begin execution.
* Finally, it records the start time and resets the event generation
* system.
*/
static void
{
if (procflow_init() != 0) {
}
/* Release the read lock, allowing threads to start */
/* Wait for all threads to start */
if (procflow_allstarted() != 0) {
return;
}
if (filebench_shm->shm_required &&
return;
}
}
/*
* Calls fileobj_init() to create and optionally pre fill files
* for all fileobjs on the master list of fileobjs (filelist).
* If errors are encountered, calls filebench_shutdown()
* to exit filebench.
*/
static void
{
if (fileobj_init() != 0) {
}
}
/*
* Calls fileset_createset() to populate all filesets and create all
* associated, initially existant, files and subdirectories.
* If errors are encountered, calls filebench_shutdown()
* to exit filebench.
*/
static void
{
if (fileset_createset(NULL) != 0) {
}
}
/*
* Shuts down all processes and their associated threads. When finished
* it deletes interprocess shared memory and resets the event generator.
* It does not exit the filebench program though.
*/
static void
{
if (filebench_shm->shm_required)
}
/*
* Ends filebench run after first destoring any interprocess
* shared memory. The call to filebench_shutdown()
* also causes filebench to exit.
*/
static void
{
ipc_cleanup();
}
/*
* Sleeps for cmd->cmd_qty seconds, one second at a time.
*/
static void
{
int sleeptime;
/* check for startup errors */
if (filebench_shm->f_abort)
return;
while (sleeptime) {
(void) sleep(1);
sleeptime--;
if (filebench_shm->f_abort)
break;
}
}
/*
* Do a file bench run. Calls routines to create file sets, files, and
* processes. It resets the statistics counters, then sleeps for the runtime
* passed as an argument to it on the command line in 1 second increments.
* When it is finished sleeping, it collects a snapshot of the statistics
* and ends the run.
*/
static void
{
int runtime;
/* check for startup errors */
if (filebench_shm->f_abort)
return;
stats_clear();
while (runtime) {
(void) sleep(1);
runtime--;
if (filebench_shm->f_abort)
break;
}
}
/*
* Similar to parser_run, but gets the sleep time from a variable
* whose name is supplied as an argument to the command.
*/
static void
{
int runtime;
return;
}
/* check for startup errors */
if (filebench_shm->f_abort)
return;
stats_clear();
while (runtime) {
(void) sleep(1);
runtime--;
if (filebench_shm->f_abort)
break;
}
}
/*
* Prints usage string if defined, else just a message requesting load of a
* personality.
*/
static void
{
int runtime;
if (usagestr) {
} else {
"load <personality> (ls "
"/usr/benchmarks/filebench/workloads for list)");
}
}
/*
* Prints the string of all var definitions, if there is one.
*/
static void
{
int runtime;
char *str, *c;
if (varstr) {
for (c = str; *c != '\0'; c++) {
if ((char)*c == '$')
*c = ' ';
}
}
}
/*
* Used by the SET command to add a var and default value string to the
* varstr string. It allocates a new, larger varstr string, copies the
* old contents of varstr into it, then adds the new var string on the end.
*/
static void
{
char *newvars;
return;
if (dofile)
return;
*newvars = 0;
} else {
}
if (varstr)
}
/*
* 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
{
int sleeptime;
return;
}
/* check for startup errors */
if (filebench_shm->f_abort)
return;
while (sleeptime) {
(void) sleep(1);
sleeptime--;
if (filebench_shm->f_abort)
break;
}
}
/*
* Parser log prints the values of a list of variables to the log file.
* The list of variables is placed on the command line, separated
* by comas and the entire list is enclosed in quotes.
*/
static void
{
char *string;
return;
return;
}
/*
* Implements the stats directory command. changes the directory for
* dumping statistics to supplied directory path. For example:
* stats directory /tmp
* changes the stats directory to "/tmp".
*/
static void
{
char newdir[MAXPATHLEN];
char *dir;
return;
}
*newdir = 0;
/* Change dir relative to cwd if path not fully qualified */
if (*dir != '/') {
}
}
#define PIPE_PARENT 1
#define PIPE_CHILD 0
/*
* Runs the quoted unix command as a background process. Intended for
* running statistics gathering utilities such as mpstat while the filebench
* workload is running. Also records the pid's of the background processes
* so that parser_statssnap() can terminate them when the run completes.
*/
static void
{
char *string;
int pipe_fd[2];
int newstdout;
return;
return;
return;
}
#ifdef HAVE_FORK1
return;
}
return;
}
#else
#endif /* HAVE_FORK1 */
if (pid == 0) {
setsid();
"Backgrounding %s", string);
/*
* Child
* - close stdout
* - dup to create new stdout
* - close pipe fds
*/
(void) close(1);
"statscmd dup failed: %s",
}
"statscmd exec failed: %s",
}
/* Failed! */
exit(1);
} else {
/* Record pid in pidlist for subsequent reaping by stats snap */
== NULL) {
return;
}
/* Add fileobj to global list */
} else {
}
}
}
/*
* Launches a shell to run the unix command supplied in the argument.
* The command should be enclosed in quotes, as in:
* system "rm xyz"
* which would run the "rm" utility to delete the file "xyz".
*/
static void
{
char *string;
return;
return;
"Running '%s'", string);
"system exec failed: %s",
}
}
/*
* Echos string supplied with command to the log.
*/
static void
{
char *string;
return;
return;
}
/*
* Adds the string supplied as the argument to the usage command
* to the end of the string printed by the help command.
*/
static void
{
char *string;
char *newusage;
return;
return;
if (dofile)
return;
*newusage = 0;
} else {
}
if (usagestr)
}
/*
* Updates the global dump filename with the filename supplied
* as the command's argument. Then dumps the statistics of each
* worker flowop into the dump file, followed by a summary of
* overall totals.
*/
static void
{
char *string;
return;
return;
"Stats dump to file '%s'", string);
}
/*
* Same as parser_statsdump, but in xml format.
*/
static void
{
char *string;
return;
return;
"Stats dump to file '%s'", string);
}
/*
* Kills off background statistics collection processes, then takes a snapshot
* of the filebench run's collected statistics using stats_snap() from
* stats.c.
*/
static void
{
int stat;
pidlistent->pl_pid);
if (pidlistent->pl_fd)
#ifdef HAVE_SIGSEND
#else
#endif
/* Close pipe */
if (pidlistent->pl_fd)
/* Wait for cmd and all its children */
"Waited for pid %lld", pid);
}
}
stats_snap();
}
/*
* Shutdown filebench.
*/
static void
parser_abort(int arg)
{
}
/*
* alloc_cmd() allocates the required resources for a cmd_t. On failure, a
* filebench_log is issued and NULL is returned.
*/
static cmd_t *
alloc_cmd(void)
{
return (NULL);
}
return (cmd);
}
/*
* Frees the resources of a cmd_t and then the cmd_t "cmd" itself.
*/
static void
{
}
/*
* Allocates an attr_t structure and zeros it. Returns NULL on failure, or
* a pointer to the attr_t.
*/
static attr_t *
{
return (NULL);
}
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.
* 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 returned attr_t struct.
*/
static attr_t *
{
char *string;
"attr %d = %d %llx?",
name,
attr->attr_integer);
}
return (NULL);
if (rtn->attr_param_list) {
"attr string %s", string);
}
}
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
* portion of the returned attr_t struct.
*/
static attr_t *
{
}
return (NULL);
if (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
* portion of the returned attr_t struct. If no parameter string is supplied
* then it defaults to TRUE (1).
*/
static attr_t *
{
}
return (NULL);
if (rtn->attr_param_list) {
} else if (rtn->attr_integer == 0) {
}
return (rtn);
}
/*
* Allocates memory for a list_t structure, initializes it to zero, and
* returns a pointer to it. On failure, returns NULL.
*/
static list_t *
{
return (NULL);
}
return (list);
}
#define USAGE1 \
"Usage:\n" \
"%s: interpret f script and generate file workload\n" \
"Options:\n" \
" [-h] Display verbose help\n" \
" [-p] Disable opening /proc to set uacct to enable truss\n"
#define PARSER_CMDS \
"create [files|filesets|processes]\n" \
"stats [clear|snap]\n" \
"stats command \"shell command $var1,$var2...\"\n" \
"stats directory <directory>\n" \
"sleep <sleep-value>\n" \
"quit\n\n" \
"Variables:\n" \
"set $var = value\n" \
" $var - regular variables\n" \
" ${var} - internal special variables\n" \
" $(var) - environment variables\n\n"
#define PARSER_EXAMPLE \
"Example:\n\n" \
"\n" \
"define file name=bigfile,path=bigfile,size=1g,prealloc,reuse\n" \
"define process name=randomizer\n" \
"{\n" \
" thread random-thread procname=randomizer\n" \
" {\n" \
" flowop read name=random-read,filename=bigfile,iosize=16k,random\n" \
" }\n" \
"}\n" \
"create files\n" \
"create processes\n" \
"stats clear\n" \
"sleep 30\n" \
"stats snap\n"
/*
* usage() display brief or verbose help for the filebench(1) command.
*/
static void
{
if (help >= 1)
if (help >= 2) {
"\n'f' language definition:\n\n");
}
}
int
yywrap()
{
char buf[1024];
if (parentscript) {
yyin = parentscript;
parentscript = NULL;
return (0);
} else
return (1);
}