HP OpenVMS Systems Documentation
OpenVMS Programming Concepts Manual
23.22.2 Fast Path (Alpha Only)
Like Fast I/O, Fast Path is an optional, high-performance feature designed to improve I/O performance. By restructuring and optimizing class and port device driver code around high-volume I/O code paths, Fast Path creates a streamlined path to the device. Fast Path is of interest to any application where enhanced I/O performance is desirable. Two examples are database systems and real-time applications, where the speed of transferring data to disk is often a vital concern.
Using Fast Path features does not require source-code changes. Minor interface changes are available for expert programmers who want to maximize Fast Path benefits.
At this time, Fast Path is not available on the OpenVMS VAX operating
Fast Path achieves performance gains by reducing CPU time for I/O requests on both uniprocessor and SMP systems. The performance benefits are produced by:
The performance improvement can best be seen by contrasting the current OpenVMS I/O scheme to the new Fast Path scheme. While transparent to an OpenVMS user, each disk and tape device is tied to a specific port interconnect. All I/O for a device is sent out over its assigned port. Under the current OpenVMS I/O scheme, a multiprocessor I/O can be initiated on any CPU, but I/O completion must occur on the primary CPU. Under Fast Path, all I/O for a given port is affinitized to a specific CPU, eliminating the requirement for completing the I/O on the primary CPU. This means that the entire I/O can be initiated and completed on a single CPU. Because I/O operations are no longer split among different CPUs, performance increases as memory cache thrashing between CPUs decreases.
Fast Path also removes a possible SMP bottleneck on the primary CPU. If the primary CPU must be involved in all I/O, then once this CPU becomes saturated, no further increase in I/O throughput is possible. Spreading the I/O load evenly among CPUs in a multiprocessor system provides greater maximum I/O throughput on a multiprocessor system.
With most of the I/O code path executing under port-specific spinlocks
and with each port assigned to a specific CPU, a scalable SMP model of
parallel operation exists. Given multiple port and CPUs, I/O can be
issued in parallel to a large degree.
For complete information about using Fast Path, see the OpenVMS I/O User's Reference Manual.
|Entry Point||System Service||Function|
|LIB$SYS_ASCTIM||$ASCTIM||Converts system time in binary form to ASCII text|
|LIB$SYS_FAO||$FAO||Converts a binary value to ASCII text|
|LIB$SYS_FAOL||$FAOL||Converts a binary value to ASCII text, using a list argument|
|LIB$SYS_GETMSG||$GETMSG||Obtains a system or user-defined message text|
|LIB$SYS_TRNLOG||$TRNLOG||Returns the translation of the specified logical name|
Two command language interpreters (CLIs) are available on the operating system: DCL and MCR. The run-time library provides several routines that provide access to the CLI callback facility. These routines allow your program to call the current CLI. In most cases, these routines are called from programs that execute as part of a command procedure. They allow the command procedure and the CLI to exchange information.
These routines call the CLI associated with the current process to perform the specified function. In some cases, however, a CLI is not present. For example, the program may be running directly as a subprocess or as a detached process. If a CLI is not present, these routines return the status LIB$_NOCLI. Therefore, you should be sure that these routines are called when a CLI is active. Table 24-2 lists the RTL routines that access the CLI.
|LIB$GET_FOREIGN||Gets a command line|
|LIB$DO_COMMAND||Executes a command line after exiting the current program|
|LIB$RUN_PROGRAM||Runs another program after exiting the current program (chain)|
|LIB$GET_SYMBOL||Returns the value of a CLI symbol as a string|
|LIB$DELETE_SYMBOL||Deletes a CLI symbol|
|LIB$SET_SYMBOL||Defines or redefines a CLI symbol|
|LIB$DELETE_LOGICAL||Deletes a supervisor-mode process logical name|
|LIB$SET_LOGICAL||Defines or redefines a supervisor-mode process logical name|
|LIB$DISABLE_CTRL||Disables CLI interception of control characters|
|LIB$ENABLE_CTRL||Enables CLI interception of control characters|
|LIB$ATTACH||Attaches a terminal to another process|
|LIB$SPAWN||Creates a subprocess of the current process|
The following routines execute only when the current CLI is DCL:
The LIB$GET_FOREIGN routine returns the contents of the command line that you use to activate an image. You can use it either to give your program access to the qualifiers of a foreign command or to prompt for further command line text.
A foreign command is a command that you can define and then use, as if it were a DCL or MCR command to run a program. When you use the foreign command at command level, the CLI parses the foreign command only and activates the image. It ignores any options or qualifiers that you have defined for the foreign command. Once the CLI has activated the image, the program can call LIB$GET_FOREIGN to obtain and parse the remainder of the command line (after the command itself) for whatever options it may contain.
The OpenVMS DCL Dictionary describes how to define a foreign command.
The action of LIB$GET_FOREIGN depends on the environment in which the image is activated:
The following PL/I example illustrates the use of the optional force-prompt argument to permit repeated calls to LIB$GET_FOREIGN. The command line text is retrieved on the first pass only; after this, the program prompts from SYS$INPUT.
EXAMPLE: ROUTINE OPTIONS (MAIN); %INCLUDE $STSDEF; /* Status-testing definitions */ DECLARE COMMAND_LINE CHARACTER(80) VARYING, PROMPT_FLAG FIXED BINARY(31) INIT(0), LIB$GET_FOREIGN ENTRY (CHARACTER(*) VARYING, CHARACTER(*) VARYING, FIXED BINARY(15), FIXED BINARY(31)) OPTIONS(VARIABLE) RETURNS (FIXED BINARY(31)), RMS$_EOF GLOBALREF FIXED BINARY(31) VALUE; /* Call LIB$GET_FOREIGN repeatedly to obtain and print subcommand text. Exit when end-of-file is found. */ DO WHILE ('1'B); /* Do while TRUE */ STS$VALUE = LIB$GET_FOREIGN (COMMAND_LINE,'Input: ',, PROMPT_FLAG); IF STS$SUCCESS THEN PUT LIST (' Command was ',COMMAND_LINE); ELSE DO; IF STS$VALUE ^= RMS$_EOF THEN PUT LIST ('Error encountered'); RETURN; END; PUT SKIP; /* Skip to next line */ END; /* End of DO WHILE loop */ END;
Assuming that this program is present as SYS$SYSTEM:EXAMPLE.EXE, you can define the foreign command EXAMPLE to invoke it, as follows:
$ EXAM*PLE :== $EXAMPLE
Note the optional use of the asterisk in the symbol name to denote an abbreviated command name. This permits the command name to be abbreviated as EXAM, EXAMP, EXAMPL or to be specified fully as EXAMPLE. See the OpenVMS DCL Dictionary for information about abbreviated command names.
Note that the use of the dollar sign ($) before the image name is required in foreign commands.
Now assume that a user runs the image by typing the foreign command and giving "subcommands" that the program displays:
$ EXAMP Subcommand 1 Command was SUBCOMMAND 1 Input: Subcommand 2 Command was SUBCOMMAND 2 Input: ^Z $
In this example, Subcommand 1 was obtained from the command line; the
program prompts the user for the second subcommand. The program
terminated when the user pressed the Ctrl/Z key sequence (displayed as
^Z) to indicate end-of-file.
24.2.2 Chaining from One Program to Another
The LIB$RUN_PROGRAM routine causes the current image to exit at the point of the call and directs the CLI, if present, to start running another program. If LIB$RUN_PROGRAM executes successfully, control passes to the second program; if not, control passes to the CLI. The calling program cannot regain control. This technique is called chaining.
This routine is provided primarily for compatibility with PDP-11 systems, on which chaining is used to extend the address space of a system. Chaining may also be useful in an operating system environment where address space is severely limited and large images are not possible. For example, you can use chaining to perform system generation on a small virtual address space because disk space is lacking.
With LIB$RUN_PROGRAM, the calling program can pass arguments to the next program in the chain only by using the common storage area. One way to do this is to direct the calling program to call LIB$PUT_COMMON to pass the information into the common area. The called program then calls LIB$GET_COMMON to retrieve the data.
In general, this practice is not recommended. There is no convenient way to specify the order and type of arguments passed into the common area, so programs that pass arguments in this way must know about the format of the data before it is passed. Fortran COMMON or BASIC MAP/COMMON areas are global OWN storage. When you use this type of storage, it is very difficult to keep your program modular and AST reentrant. Further, you cannot use LIB$RUN_PROGRAM if a CLI is present, as with image subprocesses and detached subprocesses.
The following PL/I example illustrates the use of LIB$RUN_PROGRAM. It prompts the user for the name of a program to run and calls the RTL routine to execute the specified program.
CHAIN: ROUTINE OPTIONS (MAIN) RETURNS (FIXED BINARY (31)); DECLARE LIB$RUN_PROGRAM ENTRY (CHARACTER (*)) /* Address of string /* descriptor */ RETURNS (FIXED BINARY (31)); /* Return status */ %INCLUDE $STSDEF; /* Include definition of return status values */ DECLARE COMMAND CHARACTER (80); GET LIST (COMMAND) OPTIONS (PROMPT('Program to run: ')); STS$VALUE = LIB$RUN_PROGRAM (COMMAND); /* If the function call is successful, the program will terminate here. Otherwise, return the error status to command level. */ RETURN (STS$VALUE); END CHAIN;
The following COBOL program also demonstrates the use of LIB$RUN_PROGRAM. When you compile and link these two programs, the first calls LIB$RUN_PROGRAM, which activates the executable image of the second. This call results in the following screen display:
THIS MESSAGE DISPLAYED BY PROGRAM PROG2 WHICH WAS RUN BY PROGRAM PROG1 USING LIB$RUN_PROGRAM
IDENTIFICATION DIVISION. PROGRAM-ID. PROG1. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 01 PROG-NAME PIC X(9) VALUE "PROG2.EXE". 01 STAT PIC 9(9) COMP. 88 SUCCESSFUL VALUE 1. ROUTINE DIVISION. 001-MAIN. CALL "LIB$RUN_PROGRAM" USING BY DESCRIPTOR PROG-NAME GIVING STAT. IF NOT SUCCESSFUL DISPLAY "ATTEMPT TO CHAIN UNSUCCESSFUL" STOP RUN. IDENTIFICATION DIVISION. PROGRAM-ID. PROG2. ENVIRONMENT DIVISION. DATA DIVISION. ROUTINE DIVISION. 001-MAIN. DISPLAY " ". DISPLAY "THIS MESSAGE DISPLAYED BY PROGRAM PROG2". DISPLAY " ". DISPLAY "WHICH WAS RUN BY PROGRAM PROG1". DISPLAY " ". DISPLAY "USING LIB$RUN_PROGRAM". STOP RUN.
This routine is especially useful when you want to execute a CLI command after your program has finished executing. For example, you could set up a series of conditions, each associated with a different command. You could also use the routine to execute a SUBMIT or PRINT command to handle a file that your program creates.
Because of the following restrictions on LIB$DO_COMMAND, you should be careful when you incorporate it in your program:
You can also use LIB$DO_COMMAND to execute a DCL command file. To do this, include the at sign (@) along with a command file specification as the input argument to the routine.
Some DCL CLI$ routines perform the functions of LIB$DO_COMMAND. See the OpenVMS DCL Dictionary for more information.
The following PL/I example prompts the user for a DCL command to execute after the program exits:
EXECUTE: ROUTINE OPTIONS (MAIN) RETURNS (FIXED BINARY (31)); DECLARE LIB$DO_COMMAND ENTRY (CHARACTER (*)) /* Pass DCL command */ /* by descriptor */ RETURNS (FIXED BINARY (31)); /* Return status */ %INCLUDE $STSDEF; /* Include definition of return status values */ DECLARE COMMAND CHARACTER (80); GET LIST (COMMAND) OPTIONS (PROMPT('DCL command to execute: ')); STS$VALUE = LIB$DO_COMMAND (COMMAND); /* If the call to LIB$DO_COMMAND is successful, the program will terminate here. Otherwise, it will return the error status to command level. */ RETURN (STS$VALUE); END EXECUTE;
This example displays the following prompt:
DCL command to execute:
What you type after this prompt determines the action of LIB$DO_COMMAND. LIB$DO_COMMAND executes any command that is entered as a valid string according to the syntax of PL/I. If the command you enter is incomplete, you are prompted for the rest of the command. For example, if you enter the SHOW command, you receive the following prompt:
The RTL provides a number of routines that give you access to the CLI callback facility. These routines allow a program to "call back" to the CLI to perform functions that normally are performed by CLI commands. These routines perform the following functions:
Returns the value of a CLI symbol as a string.
Optionally, this routine also returns the length of the returned value and a value indicating whether the symbol was found in the local or global symbol table. This routine executes only when the current CLI is DCL.
Causes the CLI to define or redefine a CLI symbol.
The optional argument specifies whether the symbol is to be defined in the local or global symbol table; the default is local. This routine executes only when the current CLI is DCL.
Causes the CLI to delete a symbol.
An optional argument specifies the local or global symbol table. If the argument is omitted, the symbol is deleted from the local symbol table. This routine executes only when the current CLI is DCL.
Defines or redefines a supervisor-mode process logical name.
Supervisor-mode logical names are not deleted when an image exits. This routine is equivalent to the DCL command DEFINE. LIB$SET_LOGICAL allows the calling program to define a supervisor-mode process logical name without itself executing in supervisor mode.
Deletes a supervisor-mode process logical name.
This routine is equivalent to the DCL command DEASSIGN. LIB$DELETE_LOGICAL does not require the calling program to be executing in supervisor mode to delete a supervisor-mode logical name.
For information about using logical names, see Chapter 34.