Using PERFORM
Enterprise COBOL allows you to use the PERFORM verb in two basic ways: you may write an inline PERFORM or an out-of-line PERFORM.
An inline PERFORM is preferable from a performance perspective, because at all optimization levels control flow is straightforward. In addition, with V6 program objects, Debug Tool is capable of skipping over the contents of an out-of-line PERFORM. However, it is generally not desirable to replicate large or complicated code sequences simply to have inline PERFORMs.
- Establishing the program address where control will return when the PERFORM is completed and saving that address in a compiler generated LOCAL-STORAGE data item.
- Branching to the start of the PERFORMed range.
- Executing the PERFORMed range.
- Branching back indirectly via the compiler generated data item mentioned in the first step.
In addition, the logic associated with phrases such as those for specifying the number of iterations or testing conditions is also executed.
At optimization levels above OPT(0), the compiler will attempt to remove some of the out-of-line branching code. If necessary, it will replicate code sequences to achieve this. This replication is limited to a maximum size for a PERFORM range and to a total maximum size for the whole program. There are no configuration options to control these maximum values.
This ‘PERFORM inlining’ optimization can be done on a per PERFORM statement basis. However, the nature of the range being PERFORMed must have certain characteristics in order to be a candidate.
In essence, out-of-line PERFORM statements should resemble procedure calls to have the best chance to be optimized. And, of course, that implies that the range being performed should resemble a procedure.
PERFORM A THROUGH C
PERFORM B THROUGH C
PERFORM A THROUGH C
PERFORM B THROUGH D
A. IF COND THEN PERFORM A.
Recursion can be more subtle than this case. Ranges A and B might recursively call each other and this would inhibit optimization.
In general, any branching between code in the main program and code in declarative sections (except the branching that happens as part of the natural flow of the COBOL program) is an impediment to optimization. And this is certainly true of branching in the form of PERFORM statements.
LOCAL-STORAGE SECTION.
01 ACTION PIC 9.
PROCEDURE DIVISION.
MOVE 1 TO ACTION
PERFORM A
MOVE 2 TO ACTION
PERFORM A
MOVE 1 TO ACTION
PERFORM A
A. IF ACTION = 1 DISPLAY "X" ELSE DISPLAY "Y".
In a case like this, it is likely beneficial to specialize
the performed range as follows:PERORM A1
PERFORM A2
PERFORM A1
A1. DISPLAY "X".
A2. DISPLAY "Y".
In this specific case, the optimizer will be able to achieve the same effect. It will start by replicating the statement in A at each PERFORM statement. Then it will have to spend compilation resources at each PERFORM statement to realize that, in each context, it can clearly identify whether or not ACTION = 1. Furthermore, in similar code patterns, there may be cases where the programmer knows something about the use of a utility range that the optimizer is not able to deduce.