Showing posts with label COBOL performance. Show all posts
Showing posts with label COBOL performance. Show all posts

Sunday, 11 August 2013

COBOL OPTIMIZE Compiler Option: OPT(0), OPT(1), OPT(2)

OPT(2) tells IBM Enterprise COBOL to apply its highest documented optimization level to the generated object program. That setting can improve runtime performance, but it also assumes that the source, input data, and related compiler-option contracts are valid.

COBOL OPTIMIZE compiler option levels OPT 0 OPT 1 and OPT 2
Choose the optimization level for the build stage, then verify the option in the compiler listing.

What does the COBOL OPTIMIZE compiler option do?

The COBOL OPTIMIZE compiler option controls how much work the compiler performs to reduce the runtime or storage cost of generated code. Current Enterprise COBOL syntax is OPTIMIZE(0), OPTIMIZE(1), or OPTIMIZE(2), abbreviated as OPT(0), OPT(1), and OPT(2).

This page focuses only on OPTIMIZE. For a wider option set, see COBOL compiler and runtime performance tips and the broader COBOL performance tuning checklist.

OPT(0), OPT(1), and OPT(2) compared

LevelCompiler behaviorTypical useDebug effect with TEST
OPT(0)Limited optimization and shortest compile timeInitial code changes, diagnosis, and unit testingFull debug capabilities
OPT(1)Runtime-oriented transformations, basic inlining, local simplification, and value propagationA measured middle level when build or debugging constraints matterMost debug capabilities
OPT(2)More aggressive simplification, instruction scheduling, and interblock optimizationRegression-tested production buildsSome debug capabilities
Product default versus site default: IBM documents OPT(0) as the product default. Your installation can change or fix defaults, so use the compiler listing—not an assumption—to confirm the option that built a program.

What OPT(1) can change

At OPT(1), the compiler can simplify control flow, reduce repeated computations, evaluate constant expressions during compilation, combine suitable contiguous moves, rearrange blocks, and remove unreachable code. When INLINE is also active, the compiler can consider inlining eligible PERFORM procedures.

Source code and generated instructions no longer have a simple one-to-one relationship. A debugger can still provide most capabilities with TEST at this level, but the execution path can reflect moved, combined, or removed work.

What OPT(2) adds

OPT(2) applies the OPT(1) work and adds more aggressive simplification and instruction scheduling. IBM also identifies interblock transformations such as global value propagation and loop-invariant code motion. IBM recommends OPT(2) as part of the best-performance option set for Enterprise COBOL 6.

That recommendation is a build target, not proof that every program will improve by a particular percentage. Measure the program with the same input volume and comparable system conditions before and after recompilation.

Legacy STD and FULL syntax mapping

The original post described OPTIMIZE(STD) and OPTIMIZE(FULL). Since Enterprise COBOL 5, IBM removed those forms but tolerates them for compatibility and maps them as follows:

Legacy optionCurrent mapping
NOOPTIMIZEOPTIMIZE(0)
OPTIMIZEOPTIMIZE(2)
OPTIMIZE(STD)OPTIMIZE(2)
OPTIMIZE(FULL)OPTIMIZE(2) plus STGOPT

Use the numbered form in maintained build standards. It states the intended level directly and avoids carrying old terminology into new compiler migrations.

How to specify OPTIMIZE in source

A PROCESS or CBL statement can specify most compiler options. It must appear before the IDENTIFICATION DIVISION header and before comment lines or other compiler-directing statements.

CBL OPT(2),ARCH(13),TUNE(13)
IDENTIFICATION DIVISION.
PROGRAM-ID. PAYCALC.

Do not copy the architecture values blindly. Select ARCH for the oldest processor on which the module can run, including disaster-recovery machines. Select TUNE for the processor used most often, and keep TUNE greater than or equal to ARCH.

How to specify OPTIMIZE in compile JCL

Compiler options can also be passed on the compiler invocation. The exact cataloged procedure varies by installation, but a direct compiler step can use a PARM string such as:

//COBOL    EXEC PGM=IGYCRCTL,REGION=0M,
//         PARM='OPT(2),ARCH(13),TUNE(13)'

If your site uses a compile procedure, place the option on the documented procedure symbol instead of assuming its parameter name. Review the listing to confirm the final resolved settings.

Compiler-option precedence under z/OS

For options that are not fixed, IBM documents this high-to-low precedence:

  1. Fixed installation defaults, which an application build cannot override.
  2. Certain batch-wide settings in effect for the first program.
  3. PROCESS or CBL statements in the source program.
  4. Compiler invocation options, including the JCL PARM value.
  5. Nonfixed installation defaults.

If JCL requests OPT(2) but a source CBL statement requests OPT(0), the source setting normally wins unless the installation fixed the option. This is why the compiler listing belongs with the promoted load module.

OPTIMIZE and TEST debugging behavior

IBM documents full debug capabilities with TEST at OPT(0), most at OPT(1), and some at OPT(2). Higher optimization can move, combine, inline, or remove generated work, so a source statement might not correspond to a single executable instruction range.

Use the COBOL TEST compiler option guide for debug-build choices. For targeted condition-handler visibility, IBM prefers the VOLATILE clause over reducing optimization for an entire program where VOLATILE fits the design.

Use a two-step migration build

IBM recommends a two-step compile process when moving or changing Enterprise COBOL programs. A diagnostic build can use runtime checks and OPT(0):

OPT(0),SSRANGE,NUMCHECK,PARMCHECK,INITCHECK

After invalid-data and storage-reference problems are corrected, the QA and production candidate can remove the runtime checks and use:

OPT(2),NOSSRANGE,NONUMCHECK,NOPARMCHECK

Follow local standards and preserve a repeatable test record. The SSRANGE guide, NUMPROC guide, and ARITH guide explain related data and arithmetic choices.

Valid data matters more at higher optimization

The optimizer assumes the program and data comply with the selected compiler options. Invalid packed-decimal signs, invalid zoned-decimal digits, out-of-range subscripts, storage overlays, or a call-interface mismatch can appear to behave differently after an optimization-level or compiler-version change.

Do not diagnose an OPT(2) difference as a compiler fault first: reproduce it with diagnostic options, verify input data and call interfaces, and correct undefined application behavior before comparing generated code.

OPT(2), ARCH, and TUNE work together

IBM's best-performance set for Enterprise COBOL 6 is OPT(2), ARCH(x), and TUNE(y). OPT controls transformation depth. ARCH controls which processor instructions the generated module may use. TUNE guides instruction selection and scheduling for the processor used most often.

A build that selects an ARCH level newer than a disaster-recovery processor can produce a module that cannot run there. Record both production and recovery hardware requirements in the compiler-option standard.

When MAXPCF can reduce optimization

Enterprise COBOL calculates a program complexity factor for optimization control. If that value exceeds a nonzero MAXPCF threshold, a requested OPT(1) or OPT(2) can be reset to OPT(0) and the compiler issues a warning.

Do not assume that a requested option was applied to a very large program. Check the listing for the effective option, the complexity warning, compile return code, and available region or MEMLIMIT before changing MAXPCF.

Measure an OPT(2) rollout

  1. Capture the compiler version, all effective options, binder settings, and load-module identity.
  2. Run the old and new modules with the same representative input and output checks.
  3. Compare CPU time or service units, elapsed time, EXCP or I/O behavior, and storage only where the measurement source is reliable.
  4. Repeat enough runs to separate a code change from workload and system noise.
  5. Promote only after functional results match and rollback material is retained.

Compiler optimization cannot repair an inefficient SQL access path or excessive file I/O. The COBOL runtime performance-options guide covers other build and execution factors.

COBOL OPTIMIZE rollout checklist

  • Replace tolerated STD/FULL syntax with an explicit numbered level in maintained standards.
  • Confirm the effective setting in the compiler listing.
  • Run diagnostic checks before moving a migrated application to OPT(2).
  • Verify ARCH against every processor that might execute the program.
  • Keep TUNE greater than or equal to ARCH.
  • Investigate MAXPCF warnings and compiler storage failures.
  • Compare functional output before evaluating runtime measurements.

Official IBM references

COBOL OPTIMIZE FAQ

What is the default COBOL OPTIMIZE level?

IBM Enterprise COBOL documents OPTIMIZE(0) as the product default, but a site can change or fix installation defaults. Check the compiler listing to see the option actually in effect.

What is the difference between OPT(1) and OPT(2)?

OPT(1) applies runtime-oriented transformations such as basic inlining and local simplification. OPT(2) adds more aggressive simplification, instruction scheduling, and interblock work such as global value propagation and loop-invariant code motion.

What happened to OPTIMIZE(STD) and OPTIMIZE(FULL)?

Since Enterprise COBOL 5, those forms are removed but tolerated for compatibility. IBM maps OPTIMIZE(STD) to OPTIMIZE(2) and OPTIMIZE(FULL) to OPTIMIZE(2) with STGOPT.

Should every production program use OPT(2)?

IBM recommends OPT(2) for best performance, but each application still needs functional regression testing, valid-data checks, compatible ARCH and TUNE values, and before-and-after runtime measurement under representative workloads.

The compiler listing is the final authority for a build: it shows whether the requested optimization level survived source overrides, fixed site defaults, and MAXPCF processing.

COBOL CALL Performance: Static, Dynamic, and Nested Calls

A COBOL batch job can spend a surprising amount of time transferring control between programs. The cost is small for one call, but it matters when a transaction driver calls the same validation module millions of times. The right choice depends on whether the subprogram name is fixed, whether the module must be loaded separately, and how the application is maintained.

COBOL CALL performance diagram comparing nested static and dynamic calls
Pick the call style.

What does CALL do in COBOL?

The CALL statement transfers control from one COBOL program to another program in the same run unit. The calling program passes data with the USING phrase, and the called program receives that data in its PROCEDURE DIVISION USING list.

CALL "TAXCALC" USING WS-GROSS-PAY
                     WS-TAX-AMOUNT
END-CALL

That example uses a CALL literal because the program name is hard-coded. A CALL identifier uses a data item to hold the program name, which lets the job choose the target at run time.

Static, dynamic, and nested calls at a glance

Call style Typical coding Best fit Tradeoff
Nested call CALL "INNER-PGM" inside a containing program Small helper logic that belongs inside one program source Less flexible for separate reuse
Static call CALL "TAXCALC" with NODYNAM Fixed subprogram names and stable batch applications Relink needed when called modules change
Dynamic call CALL WS-PROG-NAME or CALL literal with DYNAM Selectable routines, shared utility modules, plugin-style processing Runtime load and library lookup must be managed

CALL literal and CALL identifier

A CALL literal is easier for a reviewer to trace because the target name appears in the source. With NODYNAM, a nonnested CALL literal is normally handled as a static call. With DYNAM, that same source can behave like a dynamic call.

CALL "RATEEDIT" USING WS-RATE-AREA

A CALL identifier is dynamic. The program name comes from a working-storage item, parameter, file, or table. This is useful when one driver program chooses between several routines, but it also makes production diagnosis harder because the target module is not obvious from the statement alone.

01  WS-CALL-NAME PIC X(08) VALUE "RATEEDIT".

CALL WS-CALL-NAME USING WS-RATE-AREA
   ON EXCEPTION
      DISPLAY "CALL FAILED: " WS-CALL-NAME
END-CALL

Nested program calls

A nested program is coded inside another COBOL program. IBM documents nested calls as a structured way to keep helper logic close to the containing program and to reduce accidental changes to unrelated data. Nested programs can be called with a literal or identifier, subject to the scope rules of contained programs.

IDENTIFICATION DIVISION.
PROGRAM-ID. PAYDRVR.

PROCEDURE DIVISION.
    CALL "EDIT-PAY" USING WS-PAY-DATA
    GOBACK.

IDENTIFICATION DIVISION.
PROGRAM-ID. EDIT-PAY.
PROCEDURE DIVISION USING LS-PAY-DATA.
    GOBACK.
END PROGRAM EDIT-PAY.
END PROGRAM PAYDRVR.

Use nested programs for local helper routines that are not meant to be called across many load modules. Avoid them when the routine is a shared service that many programs must update independently.

Static CALL performance

A static call is usually faster to enter because the called program is resolved through link-edit or binder processing rather than found and loaded at run time. It also gives build-time visibility: if the called object is missing, the build process is more likely to expose the problem before the batch job starts.

The cost is maintenance. Static calls can make the load module larger, and a changed subprogram may require relink work. In a shop with many shared routines, that can turn one utility change into a batch of packaging work.

Dynamic CALL performance

Dynamic calls give the application more freedom. A program can call a module by name at run time, and a changed called program can often be replaced without rebuilding every caller. That is why dynamic calls are common for utility routines and configurable processing.

The tradeoff is runtime control. The correct module must be available through the job's load library search path, such as STEPLIB or site-standard runtime libraries. If the module is missing or the name is wrong, the failure happens during execution instead of during link-edit.

DYNAM and NODYNAM

The DYNAM compiler option tells Enterprise COBOL to treat nonnested, separately compiled CALL literal statements as dynamic calls. NODYNAM is the usual static choice for a fixed CALL literal. A CALL identifier is dynamic regardless of that option.

CALL "PAYCALC"     *> literal: static with NODYNAM, dynamic with DYNAM
CALL WS-PROG-NAME  *> identifier: dynamic

Do not decide this option from one statement alone. Check the compile option list, binder control, runtime libraries, and whether the program contains features with site restrictions, such as CICS or embedded SQL rules at your installation.

Parameter passing affects support more than speed

Most production issues around CALL do not come from the transfer itself. They come from mismatched parameters. IBM documents three common passing methods: BY REFERENCE, BY CONTENT, and BY VALUE.

Method What the called program gets Support note
BY REFERENCE Access to the caller's storage Changes in the called program affect the caller's data item.
BY CONTENT A copy of the caller's content The called program cannot change the original caller item.
BY VALUE A value, often for non-COBOL linkage Useful for C/C++ style calls, but both sides must agree.

Production checklist for CALL-heavy programs

  • List the top repeated calls in the job before changing compiler options.
  • Use CALL literal when the target program name is fixed and easy tracing matters.
  • Use CALL identifier only when the target truly needs to vary at run time.
  • Check whether DYNAM or NODYNAM is used by the compile JCL.
  • Verify the called module is available in the expected load library.
  • Match every CALL USING item with the called program's linkage layout.
  • Add ON EXCEPTION handling when a missing dynamic target should produce a clean message.

Common mistakes

Changing DYNAM without checking all calls

A compiler-option change can alter how fixed-name calls are loaded. Review every frequent CALL literal, especially in batch drivers and shared utility modules.

Using CALL identifier for a fixed name

If the target never changes, a literal is usually clearer. An identifier hides the target and makes source searches less useful during a production incident.

Passing the wrong layout

The called program does not know your intent. If the caller sends a 50-byte area and the callee expects 80 bytes, the symptom may appear as bad data, a protection exception, or a later logic error.

Related Mainframe Forum guides

For surrounding topics, read COBOL DYNAM Compiler Option, COBOL Application Structure, COBOL CALL by Reference, Content, and Value, COBOL CALL Statement, Static Call in COBOL, and COBOL RENT Compiler Option.

External references

IBM documents these rules in the Enterprise COBOL CALL statement, transferring control to another program, calling nested COBOL programs, and passing data pages.

FAQ

Is a static CALL always faster than a dynamic CALL?

Static calls usually avoid runtime load and lookup work, so they are often faster for repeated fixed-name calls. Measure the full job before changing a production compile option.

Is CALL identifier static or dynamic?

CALL identifier is dynamic. The target program name is taken from the value of the identifier at run time.

When should I use a nested COBOL program?

Use a nested program when the helper logic belongs inside one containing program and does not need to be separately shared by many applications.

What should I check first when a dynamic CALL fails?

Check the program name value, load library search path, compile option, and whether the called module exists under the expected name.

New In-feed ads