APSMpPARTurnon -mode inj -energy 400 -standardizationTime 12 -restoreFile res.gz APSMpPARStandardize -energy 400 -standardizationTime 2 -restoreFile res.gzIn a separate tcl library file (*.tcl), the machine procedures APSMpPARTurnon and APSMpPARStandardize are defined. If this library file is installed via the OAG software repository, access is automatic. If you are testing procedures locally, make sure you have the library file and tclIndex in the directory you invoke "pem" from.
The PEM allows you to select a host machine to run the procedure on (defaults to current host). If you choose another host, make sure you have xhost permission (i.e. "xhost + hostmachine"). You may also select an execution mode: Automatic, Semi-Automatic, or Manual. This defines the degree of interaction and monitoring that will occur. The mode determines what happens when a "step" is encountered in your procedure. In Manual mode, the PEM will stop at each "step" until you press continue. In Automatic mode, all steps are ignored. Semi-Automatic mode only stops on the first "step".
proc APSMpDoThis {args} { set opt1 default1 set opt2 default2 APSParseArguments {opt1 opt2} # Do something set fd [open /tmp/stuff w] puts $fd "You supplied $opt1 for opt1 and $opt2 for opt2" close $fd APSMpReturn ok "arbitrary return data here" } # Note: a companion "description" procedure should be defined. proc APSMpDoThisInfo {} { return "This procedure should return a string describing the machine proc." }This procedure just takes two optional arguments and writes their value to a file. Note that all arguments should be passed using the APSParseArguments calling convention (see the APS Tcl/Tk Library document at http://ops.aps.anl.gov/asd/oag/oagSoftware.shtml). Lastly, the APSMpReturn call must be made as the last executed statement of the machine procedure. This is true even if you return prematurely due to some detected error condition.
There are other utility procedures you may call from within your machine procedure. These will be covered in the next section, but here's a list:
APSMpStep Defines steps within a procedure APSMpInterface Returns user-interface execution context (0 or 1) APSMpParallel Schedules execution of a procedure in parallel APSMpJoin Synchronizes current procedure with parallel procedure APSMpAbort Abort execution of selected parallel procedure
Machine procedures may also be executed from any arbitrary tcl script or from within another machine procedure. Special "dummy" versions of APSMpReturn and APSMpStep will be loaded from the APS Tcl/Tk Library. These dummy versions essentially do nothing, but allow your machine procedure to be executed as if it were a regular tcl procedure. APSMpParallel and APSMpJoin may be used at any time, provided you have configured inetd and installed some scripts (reference).
Lastly, machine procedures may be executed from the command line by using the command line utility "runProc". This script starts up a tcl interpreter and evaluates the command line arguments in the interpreter. Ex:
runProc APSMpPARStandardize -energy 400 -standardizationTime 2 -restoreFile res.gz
proc APSMpPARStandardize {args} { set controlFilesDir /home/helios/oagData/controlFiles set SnapshotDir /home/helios/oagData/SCR/snapshots set status ok set energy 400 set restoreFile "" APSParseArguments {energy restoreFile} # Note: by convention we define an initial step. If this procedure is # being executed in Semi-Automatic or Manual mode, the procedure # will stop here and bring up the InitDialog, giving the user an # opportunity to change the default arguments interactively. In # fact, the dialog procedure may set any variable in the scope of # this procedure, provided it is passed using the -vars option. The # InitDialog is defined below. APSMpStep init -promptDialog APSMpPARStandardizeInitDialog -vars {energy \ restoreFile} if {![string length $restoreFile]} { # Note: Info window will only be brought up here if this procedure # is being executed in a context which provides a tk interpreter, # and the procedure is not being executed in Automatic mode. if [APSMpInterface] { APSInfoWindow .parStandAlert -name "Warning" -infoMessage \ "No Restore File Given, returning" -modal 1 } APSMpReturn error "No restore file given" } # Note: here there is no dialog associated with this step. APSMpStep standardize set sfile ${controlFilesDir}/PAR/P${energy}MeV.std if [catch {exec standardize $sfile} result] { if [APSMpInterface] { APSInfoWindow .parStandAlert -name "Warning" -infoMessage $result \ -modal 1 } APSMpReturn error "unable to exec standardize" } # Note: this procedure will block here until standardization is complete. If, # for example, you are running PARStandardize from a higher level # procedure, you may wish to use APSMpParallel to execute # PARStandardize. That way, your higher level procedure can continue # doing work while this procedure sits and waits for standardization # to complete. APSMpStep waitForStandardization while {[exec cavget -list=P:DCPS:CondCALC]} { update idletasks after 5000 } APSMpStep restoreMagnets if [catch {exec burtwb -f $restoreFile} result] { if [APSMpInterface] { APSInfoWindow .parRestoreAlert -name "Warning" -infoMessage $result\ -modal 1 } APSMpReturn error "unable to exec burtwb" } APSMpReturn ok "success!" } # Note: by convention, this procedure has only one argument. It provides the # parent frame into which you should pack all widgets. proc APSMpPARStandardizeInitDialog {frame} { # Note: this dialog procedure has access only to those variables explicitly # passed in via the -vars option of APSMpStep. You can access them here # as elements of the following global array (which always has the same # name as the machine procedure itself. global APSMpPARStandardize APSLabeledEntry .le1 -parent $frame -label "Enter energy" -textVariable \ APSMpPARStandardize(energy) APSLabeledEntry .le2 -parent $frame -label "Enter Restore File Name" \ -textVariable APSMpPARStandardize(restoreFile) }This procedure may be added to the PEM's configuration file (pemConfig). When the PEM is invoked, you may select APSMpPARStandardize for execution. If you execute it in Automatic mode, there will be no interaction, although you will see the steps displayed in sequence in a status dialog box. If you execute in Semi-Automatic mode, the status dialog will stop at the "init" step and wait for you to fill out the InitDialog and press OK. All subsequent steps in APSMpPARStandardize will be passed over. If you execute in Manual mode, the InitDialog will also be presented, and the procedure will stop at every APSMpStep, awaiting confirmation.
Now suppose you wish to build a higher level machine procedure called APSMpPARTurnOn. This will in turn call APSMpPARStandardize. There is no problem doing this directly, ex.
proc APSMpPARTurnOn {args} { set energy 400 set restoreFile "" APSParseArguments {energy restoreFile} if [catch \ {APSMpPARStandardize -energy $energy -restoreFile $restoreFile} res] { puts stderr "error during standardization: $res" } else { puts "par standardize succeeded" $res" } # Code to start up PAR RF here APSMpReturn ok }The problem with this, however, is that the code to start up the PAR RF will not begin until the PAR standardization is completed. If starting up the PAR RF were also time consuming, it is clearly best that these two activities occur in parallel. Here is another version using APSMpParallel and APSMpJoin:
proc APSMpPARTurnOn {args} { set energy 400 set restoreFile "" APSParseArguments {energy restoreFile} set p "APSMpPARStandardize -energy $energy -restoreFile $restoreFile" # Note: the next statement causes a separate UNIX process to start which # handles the execution of the procedure. This process will inherit # the host selection and execution mode of the current procedure, # although options to APSMpParallel permit you to override that. if [catch {APSMpParallel -procedure $p} result] { APSInfo .parOnAlert -name "Warning" -infoMessage \ "PAR Standardization failed: $result" -modal 1 APSMpReturn error "unable to run parallel procedure" } else { set parallelId $result } # Code to start up PAR RF here # This statement will block until the parallel procedure is completed. If you # omit the use of APSMpJoin, it will automatically be done for you prior # to returning from this procedure. Note that return value from parallel # procedure is returned by APSMpJoin. catch {APSMpJoin $parallelId} parallelResult APSMpReturn ok }By using APSMpParallel and APSMpJoin, you can construct arbitrary parallelism in your procedures. Multiple parallel procedures may be outstanding at any given time. The invoking procedure can synchronize with them in any order using APSMpJoin. You may wish to use APSMpAbort with the "-onError 1" option to prevent blocking in APSMpJoin's in the event that one of your parallel procedures returns an error.
As stated above, you may omit any use of APSMpJoin. The "system" will automatically perform an APSMpJoin on all outstanding processes prior to returning from your high level procedure. Explicit use of APSMpJoin is best, though, since it permits you to check the return status and value of the parallel procedure.
There are a number of options to APSMpStep, APSMpReturn, and APSMpParallel which are covered in the reference section.
proc <procName> {frame} { global <machineProcName> # Create widgets and use $frame as parent, i.e. APSLabeledEntry .le -parent $frame -label "Enter something" \ -textVariable <machineProcName>(<varName>) }In order to permit the promptDialog access to variables in the scope of the machine procedure, you must pass them explicitly with the -vars option. When this is done, a global array variable is created with the same name as the machine procedure. The promptDialog may then access the variables as elements of the array. See the section with examples of machine procedures.
runMP stream tcp nowait oag /usr/local/bin/dptcl dptcl -f /usr/ local/oag/apps/bin/sun4/runMPservReplace "oag" with whatever account you want, and also the paths may vary for your site.
Basically, the PEM invokes a machine procedure by contacting inetd. Inetd then in turn fires up the "runMPserv" script which sets up an appropriate shell environment. You will probably want to customize runMPserv to set various environment variables, as the inetd environment is extremely vanilla (ie. no cshrc is sourced). This environment you set up is what the interpreter running your machine procedure will have.
The runMPserv script then executes the runMP script. The runMP script takes care of setting up any user interface, and contacting the PEM in order to communicate runtime status.