Get better performance with a 2 stage COBOL compile process in a DevOps model
We’ve been working with a number of customers who have used legacy mainframe SCM’s over the years migrate to Git and Dependency Based Build. When migrating, one of the things we look at is their compile parameters. Many have not updated the parameters in years, and some do not even know what the parameters do. This is a golden opportunity to update the parameters and get better operational performance from your load modules. Here’s how:
The OPTIMIZE parm
The OPTIMIZE or OPT parameter tells the compiler how much to optimize the object deck during compilation, with values from 0-2. The highest level, OPT(2) applies advanced optimization techniques to your COBOL code. This includes things like:
Instruction Scheduling: Rearranging the order of instructions to maximize processor efficiency.
Interblock Optimizations: Optimizing code across different blocks of your program, including global value propagation and loop invariant code motion.
More aggressive simplifications: Applying more complex transformations to the code to reduce execution time.
Performance Improvements: Using OPT(2) generally leads to more efficient runtime code compared to lower optimization levels like OPT(0) or OPT(1). It can yield significant performance benefits, especially for compute-intensive programs.
Increased Compilation Time: OPT(2) compilation takes longer and uses more memory compared to lower optimization levels. This is because the compiler performs more extensive analysis and transformations.
Debugging Considerations: Due to the aggressive nature of OPT(2), it may affect debugging capabilities. The compiler might rearrange code or use registers instead of data areas, which can make it harder to trace the execution flow and inspect variable values.
Since OPT(2) can adversely affect debugging, and because performance is less of an issue during debugging we recommend OPT(0) for a development level compile. Thus, we introduce a 2 stage compile process. The first compile is done either via a “User Build”, or in the development pipeline for the lowest environment level. This allows the developer to interactively debug the program in situ whether it be a batch or online application. Then, once the developer is satisfied with the results, he or she can merge the code to the next branch (i.e. a develop branch to a release branch), which will then trigger another pipeline compile. This time, with OPT(2). This ensures that the program performance is fully optimize for a production load. Now, a developer can still get some debugging ability, but with the caveats listed above. However, by the time the program is in the TEST environment, the key debugging activities should already have been done.
TUNE and ARCH parameters
These are two often neglected parameters that have a great affect on performance without affecting the debugging abilities. The ARCH setting tells the compiler to select instructions that exist on the corresponding hardware, ensuring the program can execute on the target hardware. TUNE instructs the compiler to choose the sequence of instructions that will be most optimal on the corresponding hardware level.
- ARCH(x), where x = 11 | 12 | 13 | 14 | 15. Set the value to match the architecture of the oldest machine where your application will run, including any disaster recovery (DR) systems.
- TUNE(y), where y = 11 | 12 | 13 | 14 | 15. Set the value to match the architecture of the machine where your application will run most often. The TUNE level must always be greater or equal to the ARCH level.
For example, if your development environment is running on a z15 mainframe and your production environment is running on a z16, then use the parameters ARCH(14),TUNE(15).
TEST parameter
This parameter is suited to the development environment. If using a 2 stage compile, you can use TEST(DWARF,NOSEP). This means that the object deck has the DWARF area included in the module and there is not need for a SYSDEBUG dataset. This makes deployment much easier, but at the expense of having to have a larger dataset for your load modules.
For compilation to a prod environment, use the option NOTEST(DWARF,NOSEP), which also keeps the dwarf area in the load module, but without the debugging information. This also makes it easier of ancillary tools such as Fault Analyzer and Application Peformance Analyzer to analyze issues and problems with the load module should there be a performance problem or abend.
Other recommended parameters
The LINECOUNT(x) parameter is usually left for paging of data in the listing file. This adds a header and footer every (x) lines. This is not needed in a Git/DBB environment and frankly, annoying when anything other than 0. Thus use a LINECOUNT(0) for all languages (PL/I, COBOL, Assembler, and C/C++).
SSRANGE affects whether code is generated to check for out-of-range storage references. This is a parm that should at least be used in the development level compile. The default is SSRANGE=NO, thus specify in a development compile SSRANGE(ZLEN,MSG) to get messages about out of range storage references. Do not specify SSRANGE for a production compile (which defaults to NO as specified above).
WORD(CICS) – this is to be used when compiling CICS program. This will use the CICS reserved word table to identify and flag variables named after CICS reserved words (a potential production issue). This should be a development level compile option, but could be used for both development and test/production compile scenarios.
For more information on COBOL 6 compile parameters and recommendations visit https://www.ibm.com/docs/en/cobol-zos/6.5.0?topic=ptg-how-tune-compiler-options-get-most-out-cobol-6