Runtime Efficiency in COBOL
Arnold J. Trembley
Additional material and links were last updated
Modern IBM mainframe COBOL compilers contain a patented optimizer that
generates extremely clean and efficient code. But the compiler writers cannot
read your mind and occasionally you may have issues with runtime performance
efficiency. Most performance problems are caused by poor design. These
problems can sometimes be corrected with simple coding changes. In extreme
cases runtime performance can only be improved with a major rewrite.
In general, COBOL programs are built to solve business accounting
problems. They tend to be I/O bound rather than CPU bound. One
indication of a runtime performance problem may be CPU time exceeding
50% of wall-clock runtime on a batch job. Another indication may be
response time in excess of one second for a CICS online program. Even
if CPU utilization seems normal, you may have a runtime performance
problem if a job simply takes too much time, and prevents the daily
batch cycle from completing in less than 24 hours.
I have heard it said that there are only two ways to improve runtime
performance: Shorten your instruction path or reduce your I/O. Or
in simpler terms, don't do any work you don't need to do. Since COBOL
programs are typically I/O bound, the gains from optimizing your file
I/O design tend to be bigger than from shortening your instruction
path. So here are some tips on best practices to reduce your I/O:
Use BLOCK CONTAINS 0 RECORDS in your FD (and BLKSIZE=0 in your JCL DCB
parameters) to allow the OS/390 operating system to optimize your block
size. These two changes ensure that the maximum number of records will be
processed for a single file input/output operation.
Avoid multiple passes against the same file, if possible.
Try not to tie up too many tape drives in a single job step. If your
program needs 10 tape drives, it will wait until all 10 drives are
available. Try to keep files on disk whenever conveniently possible.
For massive changes to a key-sequenced VSAM file in batch, it is
generally faster to unload to QSAM and process sequentially. Even
with external sorts, tape access, and multiple steps, the CPU will
do less work.
If you need to support multiple alternate indexes to a file, consider
conversion to DB/2. DB/2 does this faster and better than VSAM.
If performance is absolutely critical for your application, don't be
afraid to test alternate designs.
I have seen 90% reductions in wall-clock runtime, simply by optimizing
the block size of a QSAM file. That means a 10-hour job can complete
in one hour.
Shortening your instruction path can also improve your runtime efficiency,
sometimes as dramatically as improving your I/O. Here are some tips for
writing efficient procedure logic:
When performing arithmetic, always use signed numeric fields. COBOL
performs faster with signed fields than unsigned fields. Arithmetic
will be faster on binary fields than on packed-decimal fields, but
not by much. Either binary or packed-decimal arithmetic is much
faster than arithmetic on DISPLAY USAGE numbers.
For any computation more complex than ADD +1 TO RECORD-COUNT, use the
COMPUTE statement rather than a mix of ADD, SUBTRACT, MULTIPLY, and
DIVIDE commands. Be sure your numeric fields are wide enough to avoid
truncation of intermediate results.
For fixed-point binary arithmetic, runtime performance will be better
with the TRUNC(OPT) compile option. Don't use TRUNC(BIN), it generates
a great deal of additional code to truncate results to the target
picture width. It will also perform your arithmetic with packed-decimal
numbers instead of binary numbers.
In a nested IF statement or an EVALUATE case structure, you can shorten
your instruction path if you know in advance that certain conditions
occur much more frequently than others. Test for these conditions early.
That bypasses all the logic to test for the less common situations.
Watch your loops. Any code that is iterated will adversely lengthen
your instruction path if it includes instructions that do not need
to be executed. This is particularly important with table searches.
When searching a table with more than 20 items, try to use a binary
search (SEARCH ALL) rather than a serial search. A serial search of
a 1000-entry table is very inefficient, especially if it is performed
for every input record and your file has 10 million of them.
Testing alternate designs will help identify which approach improves
efficiency. Sometimes it may be helpful to examine the disassembled
code generated by the compiler. In my experience, optimizing your
loops and table searches will make the biggest gains.
Many years ago I assisted another programmer in an all-night session,
building some one-time reports. We wrote a program that read a large
file. For each record, a table was serially searched to look up
customer information. The input file was large, and the customer
table had over 2000 entries. We cancelled that program after one
hour, because it would not finish in time. Looking at the program,
we realized that the input file was in sequence by customer number.
A simple test was added to see if the current customer number matched
the last customer number searched for, allowing the table search to
be bypassed. The modified program completed in five minutes.
Recently I worked on a production program that was having a performance
problem. The program ran for 10 hours and used almost 10 hours of CPU
time. For each of 15 million input records, a table with about 1000
entries was searched serially. I modified the program to use a
binary search rather than a serial search. On the next execution the
CPU utilization was reduced by 97% and the wall-clock runtime was
reduced by eight hours.
Efficient runtime performance results from good analysis and design,
but many performance problems can be repaired with relatively simple
More COBOL Run-time Efficiency anecdotes
If you have an interesting story about a performance problem in COBOL,
please send it to me. I would like to read it, and perhaps include it on this
Here to return to my home page.