Working with the compiler optimizer and Code Debug


This section describes the best practices for optimization and debugging.

Compiler optimization

Compiler optimization was the primary feature that attracted early adopters to migrate to the newer language versions. Reducing the 4HRA footprint can have a measurable reduction on the monthly invoice, which is an outstanding benefit.

However, compiler optimization introduces significant difficulties in debugging and determining the cause of optimized program failures. For optimized code, the complexity of associating source code and generated binary code is well known as problematic in compiler optimization literature. For a comprehensive discussion of COBOL V5/6 optimization implementation, see our blog about compiler optimization.

Furthermore, it can be challenging to debug an optimized program because optimization is not confined to individual language statements but across all statements. When cross statement optimization occurs, the IBM optimizer may move some machine instructions in each statement to a preceding or following statement—sometimes for more than one statement.

Compiler optimization requires using a compiler source listing to debug programs properly. Therefore, the complete compiler listing that details the optimization generated is paramount to a successful debugging experience. Code Debug is enabled for this optimized source listing and tested with all OPT levels to give you the best debugging experience.

Debugging at OPT(0)

Higher optimization levels, such as OPT(1) and OPT(2), will likely introduce changes to the program that will limit the use of a source debugging tool. Hence, debugging a program with higher optimization levels can give incorrect or invalid results because it no longer behaves as it did with OPT(0). For example, a common optimization technique uses registers instead of data areas, which speeds program execution. The optimized program listing might reflect this register optimization. Hence, any source code debugging would likely have problems, as data areas are expected to be updated but are not because the data is in a register.

For this reason, we recommend that even though programs should run at the highest reasonable OPT level for user acceptance, staging, and production levels, debugging might have to occur at the OPT(0) level. Doing so will either require a recompile at OPT(0) or have a second binary at OPT(0) available for debugging. It is true for both COBOL and PL/I, as the COBOL V6 and PL/I V5 compilers seem to implement similar optimization techniques.

TEST and OPT compiler options

IBM COBOL optimization and debugging using IBM tools are tightly bound together. Compiler options specified for debugging affect the capability of debugging, affecting the sizes of both the COBOL listing and executable binary.

Specifically, using these IBM debugging tools depends on the TEST compiler option, which adds binary information to the executable.

Comparatively, BMC AMI products implement a debugging methodology with highly customized code and the common CSS routines that provide services and functions shared between our products.

We also use the COBOL listing but does not use any IBM-generated debugging data written to the executable binary.

Important
When you use COBOL V6 optimization with OPT(1) or OPT(2) compile-time options, the optimized code can make debugging difficult. During debugging, the COBOL statement flow might appear to alternate between a limited set of statements. This behavior is an expected result of optimization and does not indicate an issue with the debugger. For more detailed information, see Considerations.

For optimized code, the complexity of associating the COBOL source code and generated binary machine code is considered problematic in compiler optimization literature. This jumping behavior led us to develop a more smooth stepping experience and minimize any statement jumping. The TEST compiler option is required to solve this.

To reduce the DASD size of executable program object binaries, we worked with the IBM COBOL Compiler team to develop and introduce the TEST(NODWARF), parameter which eliminates the IBM debugging (DWARF) information written to the executable program object binary.

Both TEST and OPT add substantial data to the executable binary.

Similarly, as you can see in the following chart, the EJPD and SOURCE options can add quite a lot of additional data to the program object executable. Because both options are IBM debugger options, BMC AMI products do not need them, and you should disable them with NOEJP and NOSOURCE.

Alternatively, for optimization, OPT(0) disk sizes are static, and OPT(1) and OPT(2) sizes are optimized similarly. The fact that OPT(1) and OPT(2) sizes are similar is an artifact of the optimization process. With the highest level 2, there is seemingly no additional optimization possible over what the compiler already provides for level 1.

Another observation is that CPU times for compilation increase dramatically for higher optimization levels. We ran tests on a sample COBOL program to exemplify how DASD usage varies with these options.
worddav3fae6296ef716b1286e54391162f0107.png

Considerations

  • For BMC AMI tools, you can minimize the undesired COBOL jumping behavior by using the TEST compiler option, for Code Debug tools, and successfully generating a test case using . However, TEST is not needed or recommended for all other BMC AMI products.
  • When developing and with initial testing, you might be performing repeated compilations. We recommend avoiding OPT(1 and 2) if you are doing functional testing as these waste CPU time. Final testing (and performance testing), promotion to higher development levels, and production should be with the higher OPT(1 or 2) levels.
  • When you compile a program using OPT(1) or OPT(2), the compiler prioritizes execution speed over line-by-line traceability. To achieve faster execution, the compiler applies the following optimization techniques:
    • Instruction scheduling—The compiler reorders machine instructions to keep the processor pipeline full. Although the program logic remains correct, the debugger’s current-line indicator follows the reordered instructions, which can cause it to jump unexpectedly.

    • Statement collapsing—When possible, the compiler combines multiple COBOL statements into a single, more efficient block of code. As a result, the debugger might appear to skip calls or logic that still executes.

    • Inlining—Smaller subroutines or paragraphs can be inserted directly into the main execution flow to avoid branch overhead. This optimization can make it appear as though a PERFORM or CALL statement never occurs.

  • Maintenance upgrades, such as PTFs or new releases, often refine the optimization engine. Even a small performance improvement can change the generated instruction sequence. As a result, a program that was previously easy to debug can become harder to trace after an upgrade.

    This behavior is an artifact of the optimization process and is not a limitation of the debugger. If you need to perform detailed forensic debugging, the standard practice is to recompile the affected module at OPT(0) to restore a more linear execution flow. You can then recompile the module at OPT(1) or OPT(2) for production use.

    For more recommendations, see the IBM Enterprise COBOL for z/OS documentation on optimization and debugging options.

Recommendations

To enable Code Debug debugging, creating unit tests with Total Test, and rerun unit tests created by Total Test, use the following compile options:

Cobol v5 and above

OPT(0),LIST
OPT(1) or OPT(2) with TEST(EJPD,DWARF) and LIST

Cobol below v5

NOOPT and LIST 

 

Tip: For faster searching, add an asterisk to the end of your partial query. Example: cert*

BMC AMI Enterprise Common Components 17.02