George Plue is Systems Programming Manager and Computer Hardware Maintenance Supervisor for Andrews University Computing Center. George has held these positions for six years. George was the principle designer for the enhancements described in this paper. Dan Bidwell has been a Systems Programmer at AUCC for three years and did much of the implementation of the projects described. Keith Calkins has been a Systems Programmer for about a year. He did much of the writing of this paper, some of the implementation and now holds the bag for making it all work.
This paper describes two enhancements for systems using COBOL. The first is a shared public library containing most of the run-time subroutines required by a COBOL object program, as well as the most commonly used subroutines at Andrews University. The second enhancement is a processor which splits a COBOL object program into separate data and procedure control sections. These changes greatly reduce swapping during execution of COBOL programs, especially in an online environment. The shared library has been in use since February 1978, and the processor was installed in September 1978. This software will be available through the user's group library.
Before introducing the changes described in this paper all COBOL programs were treated as data, that is the procedure and data were in the same control section (00, read and write access) (Figure 1). The COBOL run-time library, consisting of I/O routines, numeric conversion routines, etc., was also treated as data. Every COBOL program required its own copy of any run-time routines which were used.
In an interative timesharing environment the user requesting service is likely to be on the swapping device rather than in main memory. Before this user can be serviced sufficient space must be available in main memory for inswap. This is usually accomplished by the outswap of another user (or users). (Ideally the scheduler is able to keep the CPU busy during this transition.) Pure procedure is not swapped out because the copy on the swapping device is identical to the copy in main memory.
Pure procedure, because it is never modified, can also be shared among several users via the hardware memory map. This represents a significant reduction in total core usage.
For these reasons a COBOL shared library and a COBOL compiler post-processor (XROM), which separates the data from procedure in COBOL ROM's, were developed. In addition this permits programs written in COBOL to be used as shared processors.
The library is divided into two parts to allow for dynamic replacement of library routines without reloading all programs that use it. The first part, the Branch Vector, is the absolute interface between the user programs and the library routines which comprise the second part. This allows the actual library routines to vary in size while the definitions of the routines remain at an absolute address. Thus the order of the Branch Vector, once established, may not be altered (without reloading all associated programs). It can however be lengthened.
Several standard COBOL run-time library routines were not included in the package because of their low usage at our installation. These include: Debugger (DBGR,TRC), Exponentiation (EXP), No Co-Resident Sort (NCRS), Report generator (RRG), FORMESS, GETCOM, and SETZERO. In addition, numerous commonly used local routines have been included in the library because of their high usage. Our shared library with local application routines occupies thirteen pages, but without our routines the total size is only nine pages. The library has been in use since February 1978.
One of the major problems encountered while creating the COBOL shared library was that the original COBOL run-time library was not designed to be used as a shared library. There is no practical way to pre-initialize the library context area so this must be done at run time by an initialization routine in the library. Since there is no subroutine that is always called as the first thing in the program the initialization routine must be called by all of the programs that use the initialized area. We have used the library error stack in the TCB to flag completed initialization (Figure 2). The shared library does not use the library error stack so during initialization it modifies the stack pointer doubleword to say there is one entry on the stack.
Another problem with a shared library is that some of the routines reference items that are DEF'ed by the loader or the COBOL compiler in the user program. An example of this is the data references required by the inspect and the trap routines. The addresses were obtained by separating the routine into a shared and a non-shared portion. The non-shared portion is loaded with the user program and can thus obtain and pass the needed addresses to the shared portion of the routine. Another example is that the I/O routines need to know the address of M:DO to output error messages. We solved this by writing a subroutine that finds the address of M:DO by looking it up in the DCB name table.
One of the design limitations in the old run-time library is that the routine that does all the I/O processing modifies the FPT's to fit the current I/O operation. This is no longer allowed because the FPT's are all in the write protected area. The shared library I/O routines now have a table of valid FPT's for the available I/O operations. So instead of modifying an existing FPT it calculates an index to point to the appropriate FPT in the table. This method is faster than the old one. This technique does not work for some applications, and is [sic s/b in] cases the existing skeleton FPT must be moved to the context area because they are updated. This only occurs after an irrecoverable error.
When introducing write protection for pure procedure areas a problem with standard COBOL emerged. If a packed decimal variable was compared to a literal space (X'40') the standard processor trapped and the trap handler modified the literal and retried the compare. Since literals are write protected alteration is no longer permitted and the trap handler logic had to be revised.
With the onset of pure procedure COBOL programs we had to change the I/O error routine to give the proper relative addresses for both the old and new programs. We found it essential to change the COBOL compiler such that the PMAP always starts at zero. This altered slightly the way in which applications programmers used the PMAP. It should also be noted that, because of problems like the one mentioned above in the trap routine, pure procedure programs must use the shared library.
A notable amount of library data area was saved by using much of the library context area as a scratch area. The context area is only as large as the data area for the largest routine (and the routines that it references). The data savings amount to about 0.52K words per user.
Of the 6,362 lines of library source code, more than 20% was changed and about 10% was added. See example in Figure 3.
The implementation of XROM presents little change for the COBOL programmer. The altered PMAP is now added to the start address rather than the beginning data address. We patched the COBOL compiler to automatically transfer control to XROM at the completion of the compile unless the user specifically asked for the NMP (No Memory Protection) option. (We disabled the SEQCHK (sequence check) option to allow our NMP option.)
The prototype for XROM was finished in September 1978 and the XROM processor was completed in November 1978. In April 1979, after five months of error-free testing, the patches were installed in the COBOL compiler to make it our system default.
The prototype for XROM took about two man-months to complete after we had attained a thorough working knowledge of the library routines and COBOL program structure. After a short investigation it was found that COBOL programs do not modify their own code with the PERFORM and ALTER statements. With this knowledge we started enthusiastically analyzing LO listings of small COBOL programs to find out how to split the data and procedure apart. A program was written to strip the LO listing of extraneous garbage to prepare the file for assembly. This included rebuilding all of the DCB's because the COBOL LO included only a skeleton of the DCB.
One major problem with the COBOL LO was its inconsistency from one program to another. After an extensive search for additional rules to follow we had three versions of the prototype that were used to convert our first six programs. The only way to tell which version to use was to try one and if it did not work properly to try another version. Some of the symptoms include getting memory protection traps, the character 9 (X'F9') not being numeric, all the display literals being off by one byte, or the numeric edited fields being off.
Once the COBOL LO was converted into an assembly source, it was then ready for AP. This whole process took about two and a half times that of a normal compile! The first COBOL shared processor was produced by the prototype in this manner. The prototype was not a practical means of separating the data and procedure on a daily basis, but the production version could not have been written without first having used the prototype to define the rules for the conversion.
The XROM processor makes two passes of the ROM and evaluates each expression up to six times as it generates its tables and output expressions and code. XROM converts all ROM's produced by the COBOL compiler (GO, BO, and overlays). The XROM transformation adds 5% to 10% to the total compile execution time.
Total swap = inswap + outswap
inswap = DCB's + data + other + procedure
outswap = DCB's + data + other [other includes JIT, AJIT, SBUF1, SBUF2]
Also used in this calcuation was the fact that the programs using the shared library are smaller.
Figure 1 | Figure 2 | Figure 3 | ||||||
` | ||||||||
Figure 4 | Figure 5 | Figure 6 |
KGC's nightmare | GSP, the Sigma tamer |