|
||||||||||
|
||||||||||
Verb Performance
Bill Seitz of Retriever Interactive recently suggested I do a column showing some of the performance hits made by some of the COBOL verbs such as INSPECT, STRING and UNSTRING. This reminded me of an experience I had years ago with my e-mail product and a template processor I had written for it. You might recall a column I did last year that showed the overhead of using the MOVE FUNCTION CURRENT-DATE verb as opposed to parsing out CALENDAR. Sometimes the benefit of using something like CURRENT-DATE for standardization purposes far outweighs the trivial impact the verb has over a system specific call like CALENDAR.
The way this template processor worked is that it used UNSTRING all over the place to parse out the tokens on a line, allowing me to easily look for keywords. It worked and the code was very simple, in general. However, I have always kept in mind some wisdom I got from Wirt Atmar of AICS about 10 years ago. Wirt at the time said he still had a Series 30 or 33 (I forget which) that he tested all of his code on because if it ran efficiently there, then it would be fine on anything else.
So up until last year I was still compiling and testing on my old Series 37 to make sure that I wouldnt have a problem. At the time I wrote the template processor I did it on a Series 70, and it was quite zippy. But once I put it down on the 37, I could almost get a cup of coffee waiting for each field to come up. I then spent a few days re-writing all the parsing routines into in-line PERFORM loops to speed it up, and the difference was dramatic.
These days, with all the fast machines and memory, it may not make much difference anymore but its still worth understanding the overhead associated with how you write code. We are both going to discover the answer to this at the same time, because I am writing the sample programs as I write this to test the timing.
The first test (Figure 1) will be INSPECT versus an in-line PERFORM to find the first blank character in a fairly long string. Im going to use the same WORKING-STORAGE SECTION for each example. I am using the ACCEPT VAR FROM TIME so that I can get time resolution down to the tenth of a second. Since a single iteration wont necessarily show a difference, I will perform each function 10,000 times. These tests were run on a Series 996-200.
Figure 1
$CONTROL USLINIT, BOUNDS, POST85 IDENTIFICATION DIVISION. PROGRAM-ID. STUFF. * Test various cobol functions ENVIRONMENT DIVISION. CONFIGURATION SECTION. DATA DIVISION. WORKING-STORAGE SECTION. * 01 MY-TIME PIC X(08) VALUE SPACES. 01 S1 PIC S9(4) COMP VALUE 0. 01 S2 PIC S9(4) COMP VALUE 0. 01 S3 PIC S9(4) COMP VALUE 0. * 01 MY-BUFF PIC X(200) VALUE SPACES. 01 DEASSEMBLE-PARMS. 03 DP1 PIC X(50) VALUE SPACES. 03 DP2 PIC X(50) VALUE SPACES. 03 DP3 PIC X(50) VALUE SPACES. 03 DP4 PIC X(50) VALUE SPACES. * PROCEDURE DIVISION. A1000-INIT. DISPLAY 'ENTER STRING: ' NO ADVANCING. ACCEPT MY-BUFF FREE. ACCEPT MY-TIME FROM TIME. DISPLAY 'Prior to INSPECT: ' MY-TIME. PERFORM 10000 TIMES MOVE ZEROES TO S1 INSPECT MY-BUFF TALLYING S1 FOR CHARACTERS BEFORE INITIAL " " END-PERFORM. ACCEPT MY-TIME FROM TIME. DISPLAY 'After INSPECT, before PERFORM: ' MY-TIME. PERFORM 10000 TIMES PERFORM VARYING S1 FROM 1 BY 1 UNTIL MY-BUFF(S1:1) = ' ' CONTINUE END-PERFORM END-PERFORM. ACCEPT MY-TIME FROM TIME. DISPLAY 'After PERFORM: ' MY-TIME. STOP RUN. :RUN STUFFO ENTER STRING: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFF SD Prior to INSPECT: 08330020 After INSPECT, before PERFORM: 08330350 After PERFORM: 08330400
As you can see, the inspect takes 3.3 seconds to execute 10,000 times and the PERFRM takes just .1 second to execute. Its a dramatic difference, but only on a huge number of iterations.
Our next test (Figure 2) will be for UNSTRING. As you can see below, the UNSTRING took 1.7 seconds to execute 10,000 times and the PERFORM loop took only 0.1 second.
Figure 2
DISPLAY 'ENTER STRING: ' NO ADVANCING. ACCEPT MY-BUFF FREE. ACCEPT MY-TIME FROM TIME. DISPLAY 'Prior to UNSTRING: ' MY-TIME. PERFORM 10000 TIMES UNSTRING MY-BUFF DELIMITED BY "," INTO DP1 DP2 DP3 DP4 END-PERFORM. ACCEPT MY-TIME FROM TIME. DISPLAY 'After UNSTRING, before PERFORM: ' MY-TIME. PERFORM 10000 TIMES MOVE 1 TO S2 PERFORM VARYING S1 FROM 1 BY 1 UNTIL MY-BUFF(S1:1) = ' ' IF MY-BUFF(S1:1) = ',' SUBTRACT S2 FROM S1 GIVING S3 MOVE MY-BUFF(S2:S3) TO DP1 ADD 1 TO S1 GIVING S2 END-IF END-PERFORM END-PERFORM. ACCEPT MY-TIME FROM TIME. DISPLAY 'After PERFORM: ' MY-TIME. STOP RUN. ENTER STRING: dog,cat,mouse,emu Prior to UNSTRING: 08143670 After UNSTRING, before PERFORM: 08143840 After PERFORM: 08143850
So what do we learn from all this? Apparently the computers have sped up to the point where we dont have to worry so much about the efficiency of these direct verbs. However, if you are processing a large number of records and using things like INSPECT, STRING and UNSTRING and are running into performance problems, its not a bad idea to invest some time to write your own processor. You can even make it a macro so that its reusable and easy to implement.
Shawn Gordon, whose
S.M. Gordon & Associates firm supplies HP 3000 utilities, has worked
with 3000s since 1983.
Copyright The 3000
NewsWire. All rights reserved.