Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

COBOL  Module 15 – Modern tooling, performance and safe change

Performance: measuring and writing efficient COBOL

Measure COBOL CPU time the same way every time, then speed up arithmetic, lookups and file handling, with GnuCOBOL timings and the z/OS options that matter.

  • Advanced
  • 20 minutes
  • Examples run with GnuCOBOL 3.2, Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free core, Pro depth: 7 of 20 minutes free
Free: Measure the same way every time, and say how you measured · USAGE decides what arithmetic costs, measured on 10 million additions · Practise: measuring and USAGE. With a pass: 3 in-depth parts and 3 interview answers, about 13 minutes.

What you will learn

  • Measure a COBOL program's CPU time reproducibly and report the machine, compiler, flags, data and runs
  • Choose the USAGE of fields used in arithmetic from measured costs
  • Improve a batch program's lookups and file handling while keeping its output identical
  • Explain why GnuCOBOL timings do not transfer to z/OS, and which Enterprise COBOL options change speed

Before you start

Adding 1.25 to a total 10 million times took 0.836 seconds of CPU with the two fields in USAGE DISPLAY and 0.300 with COMP-5, on the same laptop, for the same total. Numbers like these decide where a change pays for itself, but only if they are measured the same way every time and reported with the machine, the compiler and the data they came from.

This lesson sets up that measurement and applies it to COBOL’s usual costs: the USAGE of numbers in arithmetic, the way a table is searched, and how often a file is opened. Every timing here was recorded with GnuCOBOL 3.2 on one busy machine, which the lesson names, and none of them is a statement about z/OS.

Measure the same way every time, and say how you measured

A timing is evidence only with its conditions. The run report of every measurement on this page names the machine, an Apple M5 Pro with macOS 26.7.1, the compiler, GnuCOBOL 3.2 with cobc -O2, which passes optimisation to the C compiler, the data and the number of runs. It reports CPU time: The seconds a processor spent running a program's own instructions, user time for its code and system time for the requests it made to the operating system, such as OPEN and CLOSE. Waiting for a processor or a disk is not counted., the seconds the program itself kept a processor busy, user and system, and not wall-clock time: The elapsed time of a run from start to end, as a clock on the wall would show it, including every wait for a processor, a disk or another job. On a busy machine it changes far more from run to run than CPU time.: this machine shared its cores with other work, which stretches elapsed time far more than CPU time.

bench.sh runs each variant once to show its output, then three rounds in which every variant runs once in turn, so a busy moment falls on all of them alike, and prints each run’s CPU seconds with the median:

bench.sh: CPU seconds of every run, in interleaved rounds Shell · bench.sh
#!/bin/bash
# Usage: ./bench.sh ROUNDS PROGRAM...: runs each program once to show what it
# prints, then ROUNDS rounds in which every program runs once, in turn, so that a
# busy moment of the machine falls on all of them alike. It prints the CPU
# seconds, user plus system, of every timed run and the median of each program.
set -eu
rounds=$1
shift
for p in "$@"; do
  echo "$p: $(./"$p")"
done
TIMEFORMAT='%U %S'
for r in $(seq "$rounds"); do
  for p in "$@"; do
    { time "./$p" > /dev/null; } 2>&1 | awk '{ printf "%.3f\n", $1 + $2 }' >> "cpu-$p.txt"
  done
done
for p in "$@"; do
  runs=$(tr '\n' ' ' < "cpu-$p.txt")
  median=$(sort -n "cpu-$p.txt" | sed -n "$(( (rounds + 1) / 2 ))p")
  echo "$p: CPU seconds ${runs}median $median"
done

The routine around it matters as much as the script. The golden-file tests of the tooling lesson pass before the first measurement and after every change, one change is measured at a time, and a gain smaller than the spread between rounds is not a gain:

Interactive · stage by stage One change, measured before and after Step through the routine for a single change. A branch back means the change is undone.
One change, measured before and after, step 6 of 6. Showing Golden tests pass, Measure the baseline, Make one change, Golden tests again, Measure again, Keep or undo it. In focus: Keep or undo it.output changedno clear gainGolden tests passbefore anything changesMeasure the baseline3 interleaved roundsMake one changeand only oneGolden tests againsame output, exactlyMeasure againsame machine and dataKeep or undo itonly a clear gain stays

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Correct first. A program is only made faster once its golden-file tests pass, so that every later run can be checked against the same output.
  2. The baseline. bench.sh runs every variant once to show its output, then three rounds in which each variant runs in turn, and keeps the CPU seconds of each run.
  3. One change. Change one thing, such as the USAGE of two fields. Two changes at once leave you unable to say which one helped, or which one broke something.
  4. The same output. The golden tests run again. A faster program that writes a different report is a new bug, so the change goes back.
  5. Measured the same way. The same machine, compiler, flags, data and number of rounds. A gain smaller than the spread between rounds is no gain.
  6. Record and decide. Keep the change only when every new run beats every old one, and write down the machine, the compiler and its flags, the data and the medians beside the numbers.

The same routine serves every change in this lesson, from the cheapest to try to the ones only a run on z/OS can judge:

Change What it means
USAGE in arithmetic DISPLAY, COMP-3, COMP or COMP-5 for the same PICTURE
A table lookup a PERFORM loop over a subscript, SEARCH from the first entry with an index, or SEARCH ALL, a binary search of a table in key order
Opening a file an OPEN and a CLOSE for every record written, or one of each for the whole run
OPTIMIZE (z/OS) how far Enterprise COBOL improves the code it generates
ARCH (z/OS) the IBM Z generation whose instructions the code may use
NUMPROC (z/OS) how the code treats the signs of packed and zoned decimal data

A lookup inside a read loop and a file opened for every record both repeat once for every record of the input, so their cost grows with the file. The three options change no line of the source, which is why only a timing on z/OS can judge them.

Checkpoint

Check: Measuring CPU time reproducibly

  1. One question Two builds of a batch are compared on a machine that other jobs keep busy. Which numbers make a fair comparison?

    Choose one answer.

    Show the answer: One question

    Answer: The CPU seconds, user plus system, of several interleaved runs of each build, compared by their medians

    bench.sh does exactly this: three rounds, every variant once per round, CPU seconds and the median.

USAGE decides what arithmetic costs, measured on 10 million additions

ADDLOOP adds an amount of PIC S9(3)V99 to a total of PIC S9(15)V99 10,000,000 times. Four builds differ only in the USAGE clause: The clause that says how an item's value is stored: DISPLAY as characters, PACKED-DECIMAL or COMP-3 as packed digits, BINARY, COMP or COMP-5 as binary integers, and COMP-1 or COMP-2 as floating point. More in “USAGE: zoned, packed decimal (COMP-3) and binary” of those two fields, which sed writes in:

addloop.cob: one ADD in a loop; USAGE-HERE is the variant COB · addloop.cob
       IDENTIFICATION DIVISION.
       PROGRAM-ID. ADDLOOP.
      * Adds 1.25 to a total 10,000,000 times. The USAGE of AMOUNT
      * and TOTAL is the only difference between the four variants:
      * the session writes it in place of USAGE-HERE with sed.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  AMOUNT       PIC S9(3)V99  USAGE USAGE-HERE VALUE 1.25.
       01  TOTAL        PIC S9(15)V99 USAGE USAGE-HERE VALUE 0.
       01  N            PIC 9(8) COMP-5.
       01  SHOWN        PIC Z(14)9.99.
       PROCEDURE DIVISION.
           PERFORM VARYING N FROM 1 BY 1 UNTIL N > 10000000
               ADD AMOUNT TO TOTAL
           END-PERFORM
           MOVE TOTAL TO SHOWN
           DISPLAY "total " FUNCTION TRIM(SHOWN)
           STOP RUN.
The machine, the compiler and four USAGE variants, timed Python · usage_session.py
from session import files, run

# The machine and the toolchain, then ADDLOOP built in four USAGE variants with cobc -O2 and timed in three rounds.
# The timings change from run to run; the page reports the recorded ones.
files("addloop.cob", "bench.sh")
run("""
uname -m && sysctl -n machdep.cpu.brand_string && sw_vers -productVersion
cobc --version | head -n 1 && cc --version | head -n 1
for u in DISPLAY COMP-3 COMP COMP-5; do sed "s/USAGE-HERE/$u/" addloop.cob > "add-$u.cob" && cobc -x -O2 -o "add-$u" "add-$u.cob" || exit 1; done
./bench.sh 3 add-DISPLAY add-COMP-3 add-COMP add-COMP-5
""")

Output

$ uname -m && sysctl -n machdep.cpu.brand_string && sw_vers -productVersion
arm64
Apple M5 Pro
26.7.1
$ cobc --version | head -n 1 && cc --version | head -n 1
cobc (GnuCOBOL) 3.2.0
Apple clang version 21.0.0 (clang-2100.3.34.2)
$ for u in DISPLAY COMP-3 COMP COMP-5; do sed "s/USAGE-HERE/$u/" addloop.cob > "add-$u.cob" && cobc -x -O2 -o "add-$u" "add-$u.cob" || exit 1; done
$ ./bench.sh 3 add-DISPLAY add-COMP-3 add-COMP add-COMP-5
add-DISPLAY: total 12500000.00
add-COMP-3: total 12500000.00
add-COMP: total 12500000.00
add-COMP-5: total 12500000.00
add-DISPLAY: CPU seconds 0.836 0.837 0.829 median 0.836
add-COMP-3: CPU seconds 0.366 0.369 0.363 median 0.366
add-COMP: CPU seconds 0.321 0.333 0.331 median 0.331
add-COMP-5: CPU seconds 0.300 0.304 0.288 median 0.300

This output changes from run to run: CPU times change from run to run, and the lines that name the machine and the C compiler change with the hardware and its updates

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 usage_session.py

GnuCOBOL numbers, not z/OS numbers

These timings come from GnuCOBOL 3.2 on one laptop. Enterprise COBOL on z/OS is another compiler on other hardware, so its costs must be measured there, with IBM’s guidance as the starting point.

All four printed the same total, 12,500,000.00, and the medians were far apart:

USAGE Median CPU seconds Against COMP-5
DISPLAY 0.836 2.8 times
COMP-3 0.366 1.2 times
COMP 0.331 1.1 times
COMP-5 0.300 1

The spread inside each row, 0.016 seconds or less, is small next to the gaps between rows, so the order is real. A DISPLAY item holds one digit a byte, as characters, so each ADD works on characters before it can add. COMP-5 is a binary number in the machine’s own byte order. COMP is binary too, but GnuCOBOL keeps it big-endian, as the USAGE lesson showed, and this laptop’s processor is little-endian, which is the likely reason for its small extra cost.

Key idea

Fields that take part in heavy arithmetic belong in a computational USAGE: on this machine DISPLAY cost 2.8 times as much CPU as COMP-5 for the same additions.

Checkpoint

Check: What USAGE costs in arithmetic

  1. One question From the recorded medians, about how many times as much CPU did the DISPLAY build use as the COMP-5 build for the same 10 million additions?

    Type a number.

    A hint

    Divide the DISPLAY median by the COMP-5 median.

    Show the answer: One question

    Answer: 2.8 times (anything from 2.5 to 3.1 counts)

    0.836 ÷ 0.300 ≈ 2.8. COMP-3 and COMP were 1.2 and 1.1 times COMP-5.

Practise: measuring and USAGE

The questions cover the two sections above, and each wrong choice names the slip it comes from.

Practice that adapts to you

Practise this lesson

6 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 6 Which of these belong next to a timing in a report? Choose every one.

    Choose every answer that is right.

    Show the answer: Question 1 of 6

    Answer:

    • The machine and its operating system
    • The data and the number of runs
    • The compiler, its version and its flags

    Each measurement on the page names the M5 Pro with macOS 26.7.1, GnuCOBOL 3.2 with cobc -O2, the program's data and three rounds.

  2. Question 2 of 6 Why does bench.sh run every variant once per round instead of all runs of one variant, then all of the next?

    Choose one answer.

    Show the answer: Question 2 of 6

    Answer: So that a busy spell of the machine falls on every variant alike

    Interleaving and medians keep the comparison fair on a machine you do not have to yourself.

  3. Question 3 of 6 A colleague changes three fields to COMP-5 and moves an OPEN out of a loop, then reports the batch 40 % faster. What is missing?

    Choose one answer.

    Show the answer: Question 3 of 6

    Answer: Separate measurements for each change, and the golden-file test after each one

    One change, the golden test, a measurement; then the next change.

  4. Question 4 of 6 Which USAGE gave the lowest median CPU time for the 10 million additions?

    Choose one answer.

    Show the answer: Question 4 of 6

    Answer: COMP-5

    All four printed the same total; only the cost of getting there differed.

  5. Question 5 of 6 COMP and COMP-5 are both binary. What is the likely reason COMP took a little longer on this laptop?

    Choose one answer.

    Show the answer: Question 5 of 6

    Answer: GnuCOBOL keeps COMP big-endian, and this laptop's processor is little-endian, so the bytes are put in order for each addition

    The USAGE lesson showed COMP's big-endian bytes; the gap here was 0.331 against 0.300 seconds.

  6. Question 6 of 6 Can the team conclude from this table that COMP is faster than COMP-3 for their totals on z/OS?

    Choose one answer.

    Show the answer: Question 6 of 6

    Answer: No; these are GnuCOBOL numbers on one laptop, and z/OS has another compiler and other hardware, so it is measured there

    A laptop measurement decides what to try; a z/OS measurement with the production options decides what to keep.

Four lookups timed, from a DISPLAY subscript to SEARCH ALL Pro: opens with a Pro, Premium or Ultimate pass

A lookup inside a read loop runs once for every record, so its cost multiplies. This part times four ways of finding a branch code in a table of 5,000, and puts IBM’s advice on tables beside the numbers.

In this part:

  • The cost of one lookup, four ways, measured
  • What IBM’s advice on tables adds for z/OS

1 diagram · 2 runnable examples (COB, Python) · about 5 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Files: one OPEN for all lines, measured, and the output checked unchanged Pro: opens with a Pro, Premium or Ultimate pass

An OPEN and a CLOSE are requests to the operating system, and a program that makes them for every record pays for them every time. This part times both ways of writing 10,000 lines, proves that they write the same file, and has you write the verdict that decides whether a change was worth keeping.

In this part:

  • One OPEN for all lines, measured, with the same file written
  • The same cost inside a subprogram, and the first-call pattern
  • Write the verdict on a change
  • Decide from timed runs whether a change made a program faster
    • Results of the sample tests

2 runnable examples (COB, Python) · 1 exercise with sample tests · about 5 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

On z/OS: OPTIMIZE, ARCH, NUMPROC and the data types IBM recommends Pro: opens with a Pro, Premium or Ultimate pass

Laptop numbers decide what to try; z/OS numbers decide what to keep. This part gives the Enterprise COBOL 6.5 options that change the speed of the same source, what each one risks, and IBM’s own ranking of the numeric types.

In this part:

  • OPTIMIZE, ARCH and NUMPROC: what Enterprise COBOL’s options change
  • Why the laptop’s ranking of USAGE does not transfer

about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Interview questions

The first question is a warm-up with its full answer. The other three each begin with a batch job that has slowed down:

  1. Fresher to mid · Warm-up

    Why compare the CPU time of two builds of a COBOL program rather than their elapsed time?

    CPU time counts the seconds a processor spent on the program itself, user and system, while elapsed time also counts every wait: for a processor that other work holds, for the disk and for other jobs. On a shared machine, or on z/OS beside other workloads, elapsed time changes with whatever else runs, so two builds timed at different moments are not compared fairly. CPU time is steadier, but not perfectly steady, so measure several runs, interleave the builds so a busy spell falls on both, and compare the medians. Report the machine, the compiler and its flags and the data with the numbers. Elapsed time still matters for a batch window, but it is the result of the CPU time and the waits, and each is improved on its own.

  2. Mid to senior

    A nightly COBOL step has grown from 25 to 40 minutes and now threatens the batch window. How do you find where the time goes before changing any code, and how do you prove that a fix is both faster and still correct?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. Mid to senior

    A colleague proposes changing every COMP-3 field of a large batch program to COMP, because COMP was faster in a laptop test. What do you check before agreeing, on the laptop and on z/OS?

    Model answer, Pro. First step and follow-ups

  4. Mid to staff

    A batch reads 2 million transactions and, for each one, looks up its branch among 5,000 codes with a PERFORM loop over a PIC 9(4) subscript. Estimate the cost of the lookups, and choose between SEARCH, SEARCH ALL, sorting the transactions and a keyed file.

    Model answer, Pro. First step and follow-ups

Organisations named on this page

MySmartCoPilot has no connection with IBM. The Enterprise COBOL options and advice here are from IBM’s documentation; every timing was recorded with GnuCOBOL 3.2.

Flashcards · 7 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. Why time a COBOL program by its CPU time on a shared machine?

    CPU time counts only the seconds the program kept a processor busy, while elapsed time stretches with every other job the machine runs.

  2. What must go with a timing for it to count as evidence?

    The machine, the compiler and its flags, the data and the number of runs, with medians of interleaved rounds compared and the golden-file tests passing before and after.

  3. Why run the variants of a benchmark in interleaved rounds?

    Each round runs every variant once in turn, so a busy moment on the machine falls on all of them alike rather than on one.

  4. What did 10 million additions cost in each USAGE under GnuCOBOL 3.2 on the lesson's laptop?

    Median CPU seconds: DISPLAY 0.836, COMP-3 0.366, COMP 0.331, COMP-5 0.300. DISPLAY cost 2.8 times as much as COMP-5.

  5. Why is arithmetic on DISPLAY items slower than on COMP-5?

    A DISPLAY item keeps one digit a byte as characters, which each ADD must work through before it can add. COMP-5 is a binary number in the machine's own byte order.

  6. What do the Enterprise COBOL options OPTIMIZE, ARCH and NUMPROC change?

    OPTIMIZE: how far the compiler improves the code it generates. ARCH: which IBM Z generation's instructions it may use. NUMPROC: how it treats the signs of decimal data. Only a timing on z/OS can judge them.

  7. When is a measured speed-up not a speed-up?

    When it is smaller than the spread between rounds of the same variant. Measure one change at a time and compare medians.

Key takeaways

  • A timing counts as evidence only with its machine, compiler, flags, data and runs: CPU seconds of interleaved rounds, compared by their medians, with the golden tests passing before and after.
  • On this machine 10 million additions cost 0.836 CPU seconds in DISPLAY and 0.300 in COMP-5, so fields in heavy arithmetic belong in a computational USAGE.
  • These are GnuCOBOL numbers on one laptop; z/OS decisions are measured on z/OS.

Terms in this lesson

CPU time
The seconds a processor spent running a program's own instructions, user time for its code and system time for the requests it made to the operating system, such as OPEN and CLOSE. Waiting for a processor or a disk is not counted.
wall-clock time
The elapsed time of a run from start to end, as a clock on the wall would show it, including every wait for a processor, a disk or another job. On a busy machine it changes far more from run to run than CPU time.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.