In the MANUAL workload mode, MEXTEX starts up a number of independant
read and write I/O threads. The number of these threads, the inter-I/O
times and the request length per I/O is selectable by the user thru
manipulation of the GUI.
The sequence of LBAs generated by each I/O
thread is determined by the next LBA selection
strategy script. Several canned scripts are defined for
some common patterns (e.g. random, linear, butterfly, etc.) by users
are free to construct their scripts when the next LBA selection
strategy button is the CUSTOM position. To actually
constuct a script, the user must first press the Read Selection
Strategy or Write Selection Strategy button to bring up the
script editing window. After making changes, the user must
compile the script before changes take effect.
If event tracing or event
triggering is enabled, following
completion of every I/O by every thread appropriate actions will be
taken to add trace records to the event trace and check for abnormal
trigger events.
The next LBA selection strategy is essentially a state machine which
determines the LBA for the next I/O and is described in the form a
C-shell like script. The most important features of this scripting language is
The WHILE statement is one of the basic looping constructs. The
statements comprising the body of the while-loop will be executed
until the termination expression evaluates to a zero value.
Usage: WHILE ( <texpr> ) DO
<statement 1>
<statement 2>
...
<statement n>
END
where <texpr> = termination expression.
The FOR statement is one of the basic looping constructs. The
statements comprising the body of the for loop will be executed a
number of times, depending on the values of the initial value
expression, the final value expression and the
increment value expression. The counting variable will be
set to the value to which the initial value expression evaluates
to. Following each iteration of the FOR loop body, the counting
variable will be incremented by the value of the increment value
expression. Once the value of the counting variable reaches the value
to which the final value expression evaluates, the loop is exited.
Usage: FOR <var> = <iexpr> TO <fexpr> [ INCREMENT <cexpr>]
<statement 1>
<statement 2>
...
<statement n>
END
where <var> = name of counting variable.
<iexpr> = initial value or <var>. (Can be arbitrary expression).
<fexpr> = final value or <var>. (Can be arbitrary expression).
<cexpr> = increment value or <var>; +1 by default. (Can be arbitrary expression).
The IF statament is the basic conditional execution construct. If
the if-expression evaluates to a non-zero value, then statements of
the THEN clause are executed. Otherwise, the next ELSEIF clauses are
evaluated. If all ELSEIF if-expr evaluate to zero, the statements of
the ELSE clause will be executed. The ELSEIF and ELSE clauses are
optional.
Usage: IF <if-expr> THEN
<then statement 1>
<then statement 2>
...
<then statement n>
ELSEIF <if-expr> THEN
<elseif statement 1>
<elseif statement 2>
...
<elseif statement n>
ELSEIF <if-expr> THEN
<elseif statement 1>
<elseif statement 2>
...
<elseif statement n>
...
ELSE
<else statement 1>
<else statement 2>
...
<else statement n>
ENDIF
where <if-expr> = expression determining conditional execution.
The SET statement is used to assign a value to a simgle valued or array variables.
Usage: SET <variable name> = <integer expression>
SET <variable name>[<integer expression>] = <integer expression>
An integer expression is a sequence of integer constants,
variables or function calls
combined with the 3 logical operations AND (&), OR (|) and NOT (~),
and the 5 arithmetic operators plus (+), minus (-), divide (/),
multiply (*) and mod (%) and the 6 comparison operators equal (==),
less-than (<), greater-than (>), less-than-or-equal (<=),
greater-than-or-equal (>=) and not-equal (!=). Additionally, an
expression may be negated with the uniary minus (-) operator. The
precedence of operators is as follows, in decreasing order of
precedence. The order among equivalent operators is from left to
right. Parenthesis may be used to redefine the order from the default
precedence.
- Highest precedence
- uniary -, ! (logical NOT)
- *, /, %, &
- +, -, | (logical OR)
- == , != , < , > , <= , >=
- Lowest precedence
The scripting language supports only a single constant type, namely
integers. The integer can be represented in decimal or hexadecimal. A
string of numerical characters will be interpretted as a decimal
integer. To represent a hexadecimal constant, simply prefix the string
of numerical characters with 0x.
Two variable types are defined; integer variables and array-of-integer variables.
The values of integer variables are referred to in integer expressions
by preceding the the variable name by the $
character. Variables must be defined before use via the set command.
The values of array integer variables are referred to in integer
expressions in a manner similar to integer variables except that an
index needs to be supplied in order to select the appropriate element
of the array. For example, $V[10] would select the 10th element of the
array V. The index can take the form of any integer expression.
The following variables are predefined and should not be modified.
- MINRLEN
- The value of the minimum request length input widget as found on the manual workload controls.
- MAXRLEN
- The value of the maximum request length input widget as found on the manual workload controls.
- MAXLBA
- The value of the largest available LBA for the particular device this thread is communication with.
- THID
- The normalized thread ID of the thread executing this script.
- ALIGNMASK
- The value of the I/O alignment boundary mask. For example, if the
I/O alignment boundary is 4, ALIGNMASK is set of 0xFFFFFFFC.
A function call performs a specific role dependant on the particular
function, and returns a value dependant on the particular function.
Usage: <function name>( <parameter 1> [, <argument 2> [... ,<argument n>]])
If the function call return value is to be examined, the set statement can be used to assign it to a
variable.
Calling the READ function will cause one or more blocks to be
read. Two arguments are required; an LBA number and a block count.
The value returned by the function is the number of 10ths of milli-seconds
elapsed.
Usage: READ(<starting LBA>, <block count>)
Calling the WRITE function will cause one or more blocks to be
written. Two arguments are required; an LBA number and a block count.
The value returned by the function is the number of 10ths of milli-seconds
elapsed.
Usage: WRITE(<starting LBA>, <block count>)
Calling the PRINTF function will cause formatted text to be
written to the standard output. The syntax of PRINTF is
identical to that of the C printf
function. The function takes at least one argument, the format string,
and returns the number of characters written.
Usage: PRINTF(<format string> [, ... ])
Calling the RANDOM function causes the return of a integral
random number chosen uniformly from the range by the two parameters.
Usage: RANDOM(<lower bound>, <upper bound>)
Calling the SLEEP function causes the calling thread to
sleep for the specified number of seconds.
Usage: SLEEP(<count>)
Calling the MSECS function causes the return of the current
value of the hardware cycle timer in milli-seconds. The value by
itself is if not too much use, however elapsed time can be computed by
subtracting the values returned by successive calls to MSECS.
Usage: MSECS()
Calling the USECS function causes the return of the current
value of the hardware cycle timer in micro-seconds. The value by
itself is if not too much use, however elapsed time can be computed by
subtracting the values returned by successive calls to USECS.
Usage: USECS()
The following is a example script fragment. The script will loop
indefinitely reading a random number of blocks, chosen from the range
$MINRLEN and $MAXRLEN, starting at a random LBA chosen from any
available LBA on the current device. The elapsed time will be saved in
the variable TIME and the printf function will be used to print
informative text.
while (1) do
set RLEN = RANDOM($MINRLEN, $MAXRLEN)
set LBA = RANDOM(0, $MAXLBA-$RLEN)
set TIME = READ($LBA, $RLEN)
printf("READ LBA = %d : RLEN = %d : TIME (in uSecs) = %d\n", $LBA, $RLEN, $TIME*100)
end
The following is the grammer in BNF (Bachus-Normal-Form) for the scripting language.
SCRIPT --> LINES
LINES --> LINE LINES
--> empty
LINE --> "set" INT_IDENT "=" EXPR
--> "set" INT_IDENT "[" EXPR "]" "=" EXPR
--> "while" WHILE_STMT
--> "if" IF_STMT
--> "for" FOR_STMT
--> FUNC_IDENT "(" [ CARG ["," CARG ["," CARG [ ..."," CARG] ] ] ] ")"
--> "#" COMMENT
WHILE_STMT --> "(" EXPR ")" "do" \
LINE LINES \
"end"
IF_STMT --> "(" EXPR ")" "then" \
LINE LINES \
ELSEIF_STMT \
ELSEIF_STMT\
ELSE_STMT \
"endif"
ELSEIF_STMT --> "elseif" "(" EXPR ")" "then" \
LINE LINES
--> empty
ELSE_STMT --> "else" \
LINE LINES
--> empty
FOR_STMT --> INT_IDENT = EXPR "to" EXPR [ "increment" EXPR ] "do" \
LINE LINES \
"end"
EXPR --> LTERM LTERM_EXPR
LTERM --> LFACTOR LFACTOR_EXPR
LTERM_EXPR --> "||" LTERM LTERM_EXPR
--> empty
LFACTOR --> COMP COMP_EXPR
LFACTOR_EXPR --> "&&" LFACTOR LFACTOR_EXPR
--> empty
COMP --> "!" COMP
--> TERM TERM_EXPR
COMP_EXPR --> "==" COMP COMP_EXPR
--> "!=" COMP COMP_EXPR
--> ">" COMP COMP_EXPR
--> "<" COMP COMP_EXPR
--> ">=" COMP COMP_EXPR
--> "<=" COMP COMP_EXPR
--> empty
TERM --> FACTOR FACTOR_EXPR
TERM_EXPR --> "+" TERM TERM_EXPR
--> "-" TERM TERM_EXPR
--> "|" TERM TERM_EXPR
--> empty
FACTOR --> "(" EXPR ")"
--> "-" EXPR
--> "+" EXPR
--> "~" EXPR
--> SIMPLE
FACTOR_EXPR --> "*" FACTOR FACTOR_EXPR
--> "/" FACTOR FACTOR_EXPR
--> "%" FACTOR FACTOR_EXPR
--> "&" FACTOR FACTOR_EXPR
--> empty
SIMPLE --> "$" INT_IDENT "[" EXPR "]"
--> "$" INT_IDENT
--> FUNC_IDENT "(" [ CARG ["," CARG ["," CARG [ ..."," CARG] ] ] ] ")"
--> NUMBER
INT_IDENT --> IDENT
FUNC_IDENT --> IDENT
CARG --> STRING
--> EXPR
IDENT --> ( a..z | A..Z ) ( a..z | A..Z | 0..9 | - | _ | . )*
STRING --> ["\""] -- all character -- ["\""]
--> -- all characters except "tab" and " " --
NUMBER --> (decimal | hexidecimal)