Comparing GnuCOBOL to IBM COBOL

· klm's blog


Original post is here: eklausmeier.goip.de

When I ran the n-queens problem in COBOL using GnuCOBOL I was a little bit surprised how slow the resulting program was -- it was slower than the equivalent PHP program. Therefore I installed the IBM COBOL for Linux compiler on the same machine and compared performance, see Installing IBM COBOL for Linux on Arch Linux. The IBM compiler generated program was 17-times faster!

Here are the results in seconds (real) on an Intel NUC.

Program runtime
GnuCOBOL 6.33
IBM COBOL 0.37

I reproduce the previous results Performance Comparison C vs. Java vs. Javascript vs. LuaJIT vs. PyPy vs. PHP vs. Python vs. Perl:

Language NUC Ryzen Odroid
C 0.17 0.15 0.44
Java 1.8.0 0.31 0.22 108.17
node.js 16.4 0.34 0.21 1.67
LuaJIT 0.49 0.33 2.06
PyPy3 7.3.5 1.57 0.86 n/a
PHP 8 3.23 2.35 42.38
Python 3.9.6 12.29 7.65 168.17
Perl 5.34 25.87 21.14 209.47

I compiled the COBOL program with GnuCOBOL using cobc -O2 -x, and for IBM COBOL I used cob2 -q'OPTIMIZE(FULL)'. Running the two programs is:

1$ time xdamcnt 1 12

So the GnuCOBOL program is slower than almost everything except Python and Perl. While the IBM COBOL is two times slower than the C program and in the range of Java and JavaScript, but still faster than LuaJIT. The slow performance of GnuCOBOL was not expected, while the performance of IBM COBOL is inline with expectations.

Some notes on comparison:

  1. Performancewise IBM COBOL is a welcome alternative to GnuCOBOL. On the other hand IBM COBOL is 32-bit with all its shortcomings. As I remarked in Memory Limitations with IBM Enterprise COBOL Compiler: No big-data with IBM COBOL.
  2. GnuCOBOL is way more permissive with its input format than IBM COBOL, which is still very mainframe oriented.
  3. Also GnuCOBOL offers an easier way to handle command-line arguments. Command-line handling in IBM COBOL is a little bit brittle, although it is not in any way difficult.
  4. GnuCOBOL runs on ARM, while IBM COBOL is x86 only. So IBM COBOL will not run on Graviton or Ampere.

Here is the COBOL program used for the tests:

  1       IDENTIFICATION DIVISION.
  2       PROGRAM-ID. xdamcnt.
  3       AUTHOR.       Elmar Klausmeier.
  4       DATE-WRITTEN. 03-Oct-2021.
  5      *
  6      * entworfen am 31.03.1985
  7      * geschrieben am 02.04.1985
  8      * revidiert am 18.04.1985
  9      * Umgeschrieben auf COBOL: 03.10.2021
 10      *
 11      *     2   4    6     8      10         12           14
 12      *   1 0 0 2 10 4 40 92 352 724 2680 14200 73712 365596
 13      *
 14       DATA DIVISION.
 15       WORKING-STORAGE SECTION.
 16       77 i             pic 9(8) comp-5.
 17       77 j             pic 9(8) comp-5.
 18       77 k             pic 9(8) comp-5.
 19       77 N             pic 9(8) comp-5.
 20       77 N2            pic 9(8) comp-5.
 21       77 l             pic s9(8) comp-5.
 22       77 z             pic 9(8) comp-5.
 23       77 configOKret   pic 9(8) comp-5.
 24       01 A_vector.
 25          10  A         pic 9(8) comp-5 occurs 100 value 0.
 26       77 istart        pic 9(8) comp-5 VALUE 1.
 27       77 iend          pic 9(8) comp-5 VALUE 0.
 28       77 cnt           pic 9(8) comp-5 VALUE 0.
 29       77 slen          pic 9(8) comp-5 value 0.
 30       77 argc          pic 9(8) comp-5 VALUE 0.
 31       77 argv          PIC X(100) VALUE SPACES.
 32
 33       LINKAGE SECTION.
 34      *01 argc          pic s9(8) comp-5.
 35      *01 argv.
 36      *   02 argvTable OCCURS 1 TO 100 TIMES DEPENDING ON argc.
 37      *      03 pargv   pointer.
 38      *01 argviStr      pic x(8).
 39
 40       PROCEDURE DIVISION.
 41      *PROCEDURE DIVISION USING BY VALUE argc BY REFERENCE argv.
 42       Pmain section.
 43           DISPLAY "N-Queens Problem in COBOL".
 44           display '  2   4    6     8      10         12           14'.
 45           display '1 0 0 2 10 4 40 92 352 724 2680 14200 73712 365596'.
 46
 47      *    GnuCOBOL command line handling
 48           ACCEPT argc from ARGUMENT-NUMBER.
 49           display "argc=", argc.
 50           if argc >= 1 then
 51               ACCEPT iend FROM ARGUMENT-VALUE.
 52               if iend <= 0  or  iend > 14 then
 53                   move 10 to iend
 54               end-if.
 55           if argc >= 2 then
 56               move iend to istart
 57               accept iend from argument-value
 58           end-if.
 59
 60      *    IBM COBOL command line handling
 61      *    display "argc=", argc.
 62      *    if argc > 1 then
 63      *        set address of argviStr to pargv(2)
 64      *        move zero to slen
 65      *        inspect argviStr tallying slen for characters
 66      *            before initial X"00"
 67      *        move argviStr(1:slen) to iend
 68      *        if iend <= 0  or  iend > 14 then
 69      *            move 10 to iend
 70      *        end-if.
 71      *    if argc > 2 then
 72      *        move iend to istart
 73      *        set address of argviStr to pargv(3)
 74      *        move zero to slen
 75      *        inspect argviStr tallying slen for characters
 76      *            before initial X"00"
 77      *        move argviStr(1:slen) to iend
 78      *    end-if.
 79
 80           display "istart=", istart, " iend=", iend.
 81
 82           PERFORM VARYING i FROM istart BY 1 UNTIL i > iend
 83               perform nqsolve
 84               DISPLAY "D(", i, ") = ", cnt
 85           END-PERFORM.
 86
 87           STOP RUN.
 88
 89
 90
 91      * Return number of positions for N queens.
 92       nqsolve section.
 93           move zero to cnt.
 94           move 1 to k.
 95           move 1 to A(1).
 96           move i to N.
 97           move i to N2.
 98
 99       lloop.
100           perform configOK.
101           if configOKret = 1 then
102               if k < N then
103                   add 1 to k
104                   move 1 to A(k)
105                   go to lloop
106                else
107                   add 1 to cnt
108                end-if
109           end-if.
110
111           perform with test after varying k from k by -1 until k <= 1
112              if A(k) < N then
113                  add 1 to A(k)
114                  go to lloop
115               end-if
116           end-perform.
117
118           add 1 to A(1).
119           if A(1) > N2 then
120               exit section
121           end-if.
122           move 2 to k.
123           move 1 to A(2).
124           go to lloop
125
126           exit.
127
128
129
130      * Check if k-th queen is attacked by any other prior queen.
131      * Return nonzero if configuration is OK, zero otherwise.
132       configOK section.
133           move zero to configOKret.
134           move A(k) to z.
135
136           perform varying j from 1 by 1 until j >= k
137               compute l = z - A(j)
138               if l = 0 then
139                   exit section
140               end-if
141               if l < 0 then
142                   compute l = 0 - l
143               end-if
144               if l = k - j then
145                   exit section
146               end-if
147           end-perform.
148
149           move 1 to configOKret.
150
151           exit.
152
153

Added 01-Sep-2024: Referenced in Performance of GnuCOBOL: A free COBOL compiler.