Topic
31 replies Latest Post - ‏2013-04-02T23:43:22Z by BillWoodger
md1972
md1972
5 Posts
ACCEPTED ANSWER

Pinned topic Cobol: Performance of subscripts vs. indexes

‏2012-06-21T12:33:45Z |
Hello all.

In his paper "IBM Enterprise COBOL Version 3 Release 1 Performance Tuning" (http://www-01.ibm.com/support/docview.wss?uid=swg27001475&aid=1) from 2002, R. J. Arellanes underlined the performance superiority of using indexes over the usage of subscripts.

He delivered astoundingly concrete statistics, I quote from page 32:

"Performance considerations for indexes vs subscripts (PIC S9(8)):
| using binary data items (COMP) to address a table is 30% slower than using indexes
| using packed decimal data items (COMP-3) to address a table is 300% slower than using indexes
| using DISPLAY data items to address a table is 450% slower than using indexes"

We tried to verify these statistics, but not a single one of them appeared to be valid. Not even close. (We use IBM Enterprise COBOL for z/OS 3.4.1, btw.)

Can anybody help to explain this phenomenon?

Test conditions: Using a cobol table with "OCCURS 1000" and five table elements per line, we fill all 1,000 lines in a PERFORM loop with five MOVEs each. This logic is embraced by another PERFORM loop of 50,000, summing up to a total of 250,000,000 MOVE statements. Quite like this:
code
PERFORM 50000 TIMES
PERFORM VARYING IND FROM 1 BY 1
MOVE "A" TO FIELD-1(IND)
MOVE "B" TO FIELD-2(IND)
MOVE "C" TO FIELD-3(IND)
MOVE ZERO TO FIELD-4(IND)
MOVE 1 TO FIELD-5(IND)
END-PERFORM
END-PERFORM
[/code]
The results were:
5,59 seconds - when using the table's index

3,18 seconds - when using subscript PIC S9(4) binary
5,68 seconds - when using subscript PIC S9(9) binary

5,45 seconds - when using subscript PIC S9(4) packed-decimal
5,31 seconds - when using subscript PIC S9(5) packed-decimal
6,17 seconds - when using subscript PIC S9(9) packed-decimal

6,04 seconds - when using subscript PIC S9(4) display with sign
7,09 seconds - when using subscript PIC 9(4) display without sign
6,70 seconds - when using subscript PIC 9(9) display without sign

So the test tended to confirm some of the statements: Using variables with a length of 9 digits is slower than a length of 4 or 5 digits; using display data items is (usually) a bad decision, and using unsigned variables is even worse.

BUT the foremost statement seems to have proved wrong: In contradiction to the performance tuning guide, using a subcript with PIC S9(4) binary was considerably faster than using the table's index.
And besides that, none of the quoted percentage numbers ("30%", "300%", even "400%) appeared anywhere near confirmability.
The differences between the performance guide statements and the own test results can have several reasons, of course:
  • The paper is based on Cobol V3R1, we use V3R4.1. Maybe there have been some vast improvements for subscripts since V3R1, and this part of the guide is out-dated.
  • Maybe we use compiler settings that disadvantage the use of indexes.
  • Maybe we misinterpreted the propositions, and what we tested was something else than what R. J. Arellanes meant. (In this case, I would tend to say that this segment ot the guide was written too ambiguously and should be more differentiated.)
  • Maybe we corrupted the advantages of indexes by not handling indexes properly all through the experiment - e.g. by not using "SET IND UP BY 1", but simply modifying it in the PERFORM phrase.
  • etc.

In any case, we would be glad to hear your opinions about that matter, and perhaps you can explain some of the discrepancies.

Thank you in advance. :)
Updated on 2013-04-02T23:43:22Z at 2013-04-02T23:43:22Z by BillWoodger
  • dbzThedinosaur
    dbzThedinosaur
    57 Posts
    ACCEPTED ANSWER

    Re: Cobol: Performance of subscripts vs. indexes

    ‏2012-06-22T08:45:11Z  in response to md1972
    you spent a lot of time quoting statistics,
    but your code:
    
    PERFORM 50000 TIMES PERFORM VARYING IND FROM 1 BY 1 MOVE 
    "A" TO FIELD-1(IND) MOVE 
    "B" TO FIELD-2(IND) MOVE 
    "C" TO FIELD-3(IND) MOVE ZERO TO FIELD-4(IND) MOVE 1 TO FIELD-5(IND) END-PERFORM END-PERFORM
    

    sorta sucks because you have no terminating condition for the inner perform. perform varying from by until what

    look at the object code generated using subscript vs index.

    that plus most statistics are taken during a SEARCH and SEARCH ALL
    vs Perform.

    you can't bother to post good code,
    i can't be bothered to even think about your results,
    much less take them seriously.
    • SystemAdmin
      SystemAdmin
      403 Posts
      ACCEPTED ANSWER

      Re: Cobol: Performance of subscripts vs. indexes

      ‏2012-06-22T21:40:49Z  in response to dbzThedinosaur
      Thanx Dino ;-) for your quick answer. I wanted to check that code later but you've been faster.

      I was very astonished reading that indexing should be slower than subscripting. No, no!! I did several optimization of code (in different releases of the compiler) with using indexing instead of binary subscripting (with TRUNC(OPT)) and I won at about 30% in loops.
    • md1972
      md1972
      5 Posts
      ACCEPTED ANSWER

      Re: Cobol: Performance of subscripts vs. indexes

      ‏2012-06-25T11:58:23Z  in response to dbzThedinosaur
      Thank you for the warm welcome, dbzThedinosaur! Feels really cosy here in the IBM board, where everyone can expect to be treated like a grown-up, not like a school kid.

      Do we know each other? What legitimates you to patronize me in such a snotty way? Did I offend you somehow personally, because this is your board and I lightheadedly violated one of your rules? Or are you just looking for opportunities to feel superior, important or maybe entertaining, no matter how flimsy the reason is? (In this case, a missing line of code.) Hard to decide. And doesn't really matter in this thread, of course.
      But if you can't bother to post a somehow reasonable answer in any way, and you have nothing to contribute to the subject matter, then the logical choice would be to post nothing at all instead of making quite a big deal emphasizing your lack of interest. If you are not willing or able to answer a question, you can be sure that you have not been addressed by the question in the first place. It's that simple.
      See? Even morons like me can be patronizing. Nothing superior in this.
      Never had an encounter like this before, fortunately. And then it happens here of all boards, in a technical and issue-driven board. Congratulations!

      Back to topic, and I hope we can stay there.

      My code quote was in fact missing the line "UNTIL IND > 1000". That was actually careless, sorry for this. Unfortunately, I can't edit the post.
      Nevertheless, it should be clear that this code snippet was not an exact copy from the test program. My misquote doesn't affect the results listed above.
      Having clarified this detail, all questions of my first post still remain unanswered.
      Short responses to dbzThedinosaur's "hints":

      1) "look at the object code generated using subscript vs index."
      I know the differences in the assembly. What you're indicating is: The code for subscript conversions is more complex (and therefore more time-consuming) than the one using indexes, so it's slower.
      That's common knowledge. Does this help to understand the main test results? No. On the contrary, because this evident conclusion contradicts the test results.
      That's why we asked.

      2) "that plus most statistics are taken during a SEARCH and SEARCH ALL vs Perform."
      SEARCH has nothing to do with our questions or R. J. Arellanes general(!) propositions about index vs. subscripts. (The word GENERAL is important here.)
      a) SEARCHing has his own paragraph on page 35. Although it only compares sequential SEARCH to SEARCH ALL and doesn't contrast it with a PERFORM loop. Unfortunately.
      b) In his paragraph on "Indexes vs Subscripts", the author did not restrict his statements/statistics to SEARCH operations or any other specific constraints. He didn't even use SEARCH as an example. If his propositions are only true under certain circumstances or in particular situations, these circumstances should have been mentioned there. But instead, the statements read like this, I quote again: "using packed decimal data items (COMP-3) to address a table is 300% slower than using indexes" (etc.) - where the author could easily have written more moderately "...UP TO 300% slower..." or "...300% slower on average".
      We all know the difference between "equal" and "less or equal". Using the mindset of strict logic, the phrasing of the guide's statements seems to be wrong, and raising too high expectations.

      Judging from dbzThedinosaur's "hints", it seems that our real questions and intentions have not been understood.
      If dbzThedinosaur or anybody else got the impression that my first post wanted to somehow attack R. J. Arellanes, his work, or some generally acknowledged principles of programming, I want to point out that this is a misunderstanding. We all agree that the guide is a good help and was written to the best of the author's knowledge. But it's not a sacrilege to ask for more details about some long-term basic assumptions, as long as some evidence seems to contradict them.
      Where did these percentage numbers come from? Are they always true, no matter in which context?
      And: Things tend to evolve, even in cobol. Previous insights may lose validity or power over time. E.g. by optimizations of the cobol compiler.

      Meanwhile, a colleague sent me a link to a newer version of the guide, referring to Cobol V4R2: http://www.ibm.com/support/docview.wss?uid=swg27018287&aid=1
      The new percentage numbers (page 36) are: 40%, 220%, 300%. Still no "less or equal" or "on average" or any restrictionmentioned. I consider the differences to the percentage numbers from V3R1 to be a result of compiler changes.
      On a brighter side, dbzThedinosaur's post already confirmed our basic suspicion that the guide was too broad in this paragraph and needs more detail, because the advantages of using indexes seem to differ depending on how indexes or subscripts are used. So the circumstances ARE relevant.


      Hello RalfSeidler,

      also thanks (without irony) for your reply!

      • Your offer "I wanted to check that code" sounds promising, because own testing is the only way to validate any of the statements (guide vs. our test) and to compare the circumstances afterwards, trying to solve the case.
      • "I was very astonished reading that indexing should be slower than subscripting" - So were we, believe me. That's why we asked.
      • "I did several optimization of code http://... (with TRUNC(OPT)) and I won at about 30% in loops." - If you could deliver details about the contexts, it would be very much appreciated. The more, the better.

      This reminds me to mention that our compiler uses TRUNC(BIN) as default. I am aware that this is the slowest TRUNC option, but unfortunately I'm not a compiler admin.
      In a nutshell:
      Nothing has been fully explained or analyzed so far. (Just in case anybody got another impression.)
      So help and explanations are still very welcome.
      • dbzThedinosaur
        dbzThedinosaur
        57 Posts
        ACCEPTED ANSWER

        Re: Cobol: Performance of subscripts vs. indexes

        ‏2012-06-25T14:17:53Z  in response to md1972
        There is a Preview function for posting. When a poster can not even take the time to insure that what he/she posts is accurate/complete, they are definitely not professional nor is spending a long paragraph whining about being 'offended'. Hey, your code did suck. That coupled with your definition of
        Test conditions: Using a cobol table with "OCCURS 1000" and five table elements per line, we fill all 1,000 lines in a PERFORM loop with five MOVEs each

        I would have said, OCCURS 1000, each item consisting of 5 elements, each element of the 1000 items populated by a move in a PERFORM loop.

        so, bad code, rather poor verbiage, no mention of how the time was ascertained, only 1000 table items, 5 moves (spending more time on the moves than anything else)... I was not moved to take your post seriously.

        Actually, your post, i am still not, but for the benefit of others I will respond with my thoughts on the subject:

        years ago (80's and 90's) the difference between subscripts and indexes was significant on all but small tables (< 256 items). With today's processor speeds I imagine the break even point is many more than 256.
        But the problem with these statistics, is that with today's processor speeds (multi-millions vs hundreds-of-thousands) the only place you see the difference is within the whole system, not within the program.
        As humans we notice seconds, but not micro-seconds. If you remove 100 instructions from a program, it is very difficult to measure the difference when we isolate ourselves to a program's performance. But if you have a computer system with hundreds-of-thousands of programs (I include sys-software/db2,...) then each of these modules is competing for a time slice. With that perspective, 100 lines of code means something.

        I personally always code with indexes, so that if the table OCCURS clause is increased (to a point of relevance) nothing else need be changed (i.e. code modified to covert subscripting to indexing).
        • md1972
          md1972
          5 Posts
          ACCEPTED ANSWER

          Re: Cobol: Performance of subscripts vs. indexes

          ‏2012-06-25T17:32:04Z  in response to dbzThedinosaur
          It seems you just can't switch off the inner school master when writing. Now it's also my (indeed) poor command of the english language that drew you to the conclusion that my post is something like a prank and not worth commenting. Well, don't comment it then! Please. All you wrote so far only showed that it still didn't strike you what this thread is about. Maybe due to my insufficient explanations, can't decide.
          • "no mention of how the time was ascertained"
          That's quite irrelevant in this context, as long as we measure CPU time and not just some execution time. Our point of interest is to compare the results and relate them to each other. We are not interested in absolute CPU times. So it doesn't matter too much which method is used; it's more important that the same method is applied to each and every test run.
          To deliver the information anyway: The source for the CPU times was SDSF, after we noticed that this tool provided approximately the same results as our company's own assembler routine for CPU measurement. In addition, we did every test run several times, and the CPU times according to SDSF varied only very little.

          • "only 1000 table items, 5 moves"
          Yes, that's right. Without knowing it, you might come slightly closer to the thread's purpose after all. As mentioned again and again, the guide does NOT make any restriction to it's propositions whatsoever.
          Your complaint implies that the design of our test in inadequate. Too little of this, too little of that, wrong operations etc.
          But (that's the point): Deducing from the guide's generality, the test design was absolutely adequate. Because the guide implicitly claims to be valid in every case. If you would actually take a look in the guide for once, you might agree that it keeps completely quiet about circumstances, e.g. table size, compiler settings, operations, etc. It says: One thing is 300% slower than the other thing - period.
          If the performance advantages of index usage depend on table size etc., it would at least be worth mentioning in the guide. Agreed?
          Otherwise, a naive reader could conclude that he's able to considerably speed up certain parts of his own programs just by changing from subscripts to indexes, maybe even doubling the performance of these particular code segments. That's what the guide implicates. And this naive implication seems to have proved wrong.
          If somebody would compare two cars, stating "the red car is 50% faster than the blue car", it's obvious that this sentence is not true, but instead misleading. What's actually meant is perhaps "...up to 50% faster, depending on the situation", or "the maximum speed of the red car is 150% of the blue car's maximum speed".
          And besides this, a responsible driver might want to know if there could occur situations that even disadvantage the red car.

          • "for the benefit of others I will respond with my thoughts on the subject"
          It might be true that random, free associations about performance, processor speed improvements and processor sharing can find an audience. But they, too, have nothing to do with the thread's subject. Please start an own thread about that, if you think it's worth sharing. But this is the wrong place.

          dbzThedinosaur, please stop posting in this thread. Nobody asked you in the first place to post, now I specifically uninvite you to. You keep leading away from the subject. This thread is not about your (or anyone else's) personal preferences. It's supposed to be about backgrounds.

          Thank you.
  • SystemAdmin
    SystemAdmin
    403 Posts
    ACCEPTED ANSWER

    Re: Cobol: Performance of subscripts vs. indexes

    ‏2012-06-25T17:55:38Z  in response to md1972
    Attempting to add light rather than heat...

    
    Identification Division. Program-ID. INDXSBSC. * * Benchmark subscripts and indexes in COBOL table processing. * Data Division. Working-Storage Section. 01  CONSTANTS. 05  MYNAME                PIC X(008)   VALUE 
    'INDXSBSC'.   01  WORK-AREA. 05  SBSC-F      PIC S9(008) COMP SYNC. 05  SBSC-H      PIC S9(004) COMP SYNC. 05  SBSC-P      PIC S9(005) COMP-3 SYNC. 05  SBSC-D      PIC S9(005) DISPLAY SYNC. 05  WORK-TABLE OCCURS 1000 INDEXED INDX. 10  FIELD-1 PIC X(001). 10  FIELD-2 PIC X(001). 10  FIELD-3 PIC X(001). 10  FIELD-4 PIC 9(001). 10  FIELD-5 PIC 9(001).   Linkage Section. 01  PARM. 05  PARM-LN    PIC S9(004) Binary. 05  PARM-VAL   PIC X(100).   Procedure Division Using PARM.   DISPLAY MYNAME 
    ' Begin ' FUNCTION CURRENT-DATE   IF PARM-LN < 1 DISPLAY MYNAME 
    ' a 1 byte parm is required ' 
    '(F, H, P, D, I)' MOVE 8 TO RETURN-CODE GOBACK END-IF   EVALUATE PARM-VAL(1:1) WHEN 
    'F' PERFORM 50000 TIMES PERFORM VARYING SBSC-F FROM 1 BY 1 UNTIL SBSC-F > 1000 MOVE 
    "A"  TO FIELD-1(SBSC-F) MOVE 
    "B"  TO FIELD-2(SBSC-F) MOVE 
    "C"  TO FIELD-3(SBSC-F) MOVE ZERO TO FIELD-4(SBSC-F) MOVE 1    TO FIELD-5(SBSC-F) END-PERFORM END-PERFORM WHEN 
    'H' PERFORM 50000 TIMES PERFORM VARYING SBSC-H FROM 1 BY 1 UNTIL SBSC-H > 1000 MOVE 
    "A"  TO FIELD-1(SBSC-H) MOVE 
    "B"  TO FIELD-2(SBSC-H) MOVE 
    "C"  TO FIELD-3(SBSC-H) MOVE ZERO TO FIELD-4(SBSC-H) MOVE 1    TO FIELD-5(SBSC-H) END-PERFORM END-PERFORM WHEN 
    'P' PERFORM 50000 TIMES PERFORM VARYING SBSC-P FROM 1 BY 1 UNTIL SBSC-P > 1000 MOVE 
    "A"  TO FIELD-1(SBSC-P) MOVE 
    "B"  TO FIELD-2(SBSC-P) MOVE 
    "C"  TO FIELD-3(SBSC-P) MOVE ZERO TO FIELD-4(SBSC-P) MOVE 1    TO FIELD-5(SBSC-P) END-PERFORM END-PERFORM WHEN 
    'D' PERFORM 50000 TIMES PERFORM VARYING SBSC-D FROM 1 BY 1 UNTIL SBSC-D > 1000 MOVE 
    "A"  TO FIELD-1(SBSC-D) MOVE 
    "B"  TO FIELD-2(SBSC-D) MOVE 
    "C"  TO FIELD-3(SBSC-D) MOVE ZERO TO FIELD-4(SBSC-D) MOVE 1    TO FIELD-5(SBSC-D) END-PERFORM END-PERFORM WHEN 
    'I' PERFORM 50000 TIMES PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > 1000 MOVE 
    "A"  TO FIELD-1(INDX) MOVE 
    "B"  TO FIELD-2(INDX) MOVE 
    "C"  TO FIELD-3(INDX) MOVE ZERO TO FIELD-4(INDX) MOVE 1    TO FIELD-5(INDX) END-PERFORM END-PERFORM END-EVALUATE   DISPLAY MYNAME 
    ' End   ' FUNCTION CURRENT-DATE   GOBACK.
    


    ...the results...

    
    PROCSTEP  STEPNAME  PROGRAM      CPUTIME SN        F         INDXSBSC   00:00:01.49 SN        H         INDXSBSC   00:00:01.52 SN        P         INDXSBSC   00:00:03.29 SN        D         INDXSBSC   00:00:03.38 SN        I         INDXSBSC   00:00:00.50 SS        F         INDXSBSC   00:00:01.54 SS        H         INDXSBSC   00:00:01.47 SS        P         INDXSBSC   00:00:03.27 SS        D         INDXSBSC   00:00:03.37 SS        I         INDXSBSC   00:00:00.30 SF        F         INDXSBSC   00:00:01.54 SF        H         INDXSBSC   00:00:01.47 SF        P         INDXSBSC   00:00:03.28 SF        D         INDXSBSC   00:00:03.37 SF        I         INDXSBSC   00:00:00.30 ON        F         INDXSBSC   00:00:01.08 ON        H         INDXSBSC   00:00:01.15 ON        P         INDXSBSC   00:00:03.28 ON D         INDXSBSC   00:00:03.37 ON        I         INDXSBSC   00:00:00.50 OS        F         INDXSBSC   00:00:01.18 OS        H         INDXSBSC   00:00:01.10 OS        P         INDXSBSC   00:00:03.27 OS        D         INDXSBSC   00:00:03.37 OS        I         INDXSBSC   00:00:00.30 OF        F         INDXSBSC   00:00:01.19 OF        H         INDXSBSC   00:00:01.10 OF        P         INDXSBSC   00:00:03.27 OF        D         INDXSBSC   00:00:03.37 OF        I         INDXSBSC   00:00:00.30 BN        F         INDXSBSC   00:00:02.69 BN        H         INDXSBSC   00:00:01.15 BN        P         INDXSBSC   00:00:03.29 BN        D         INDXSBSC   00:00:03.38 BN        I         INDXSBSC   00:00:00.50 BS        F         INDXSBSC   00:00:02.46 BS        H         INDXSBSC   00:00:01.11 BS        P         INDXSBSC   00:00:03.28 BS        D         INDXSBSC   00:00:03.37 BS        I         INDXSBSC   00:00:00.30 BF        F         INDXSBSC   00:00:02.47 BF        H         INDXSBSC   00:00:01.11 BF        P         INDXSBSC   00:00:03.27 BF        D         INDXSBSC   00:00:03.36 BF        I         INDXSBSC   00:00:00.30
    


    ...where the first byte of the procstep indicates the value of the TRUNC compile option (S = STD, O = OPT, B = BIN) and the second byte of the procstep indicates the value of the OPT compile option (N = NOOPT, S = STD, F = FULL) and the stepname indicates the type of subscripting or indexing used (F = fullword, H = halfword, P = Packed Decimal, D = Display, I = Index).
    • dbzThedinosaur
      dbzThedinosaur
      57 Posts
      ACCEPTED ANSWER

      Re: Cobol: Performance of subscripts vs. indexes

      ‏2012-06-25T18:47:15Z  in response to SystemAdmin
      craig-s,
      thx for beacon.
      i was surprised at results. i did not think that they would be so demonstrative.

      also, thx for the method of accessing the time.

      any CALL to a service - sdsf, db2, whatever - would also include the time spent on the queue to that service to answer the request.

      a simple accept would negate the time involved for another task to service the request.

      Since md actually called me at home to complain of my treatment,
      i am glad someone else entered the conversation.
      • SystemAdmin
        SystemAdmin
        403 Posts
        ACCEPTED ANSWER

        Re: Cobol: Performance of subscripts vs. indexes

        ‏2012-06-26T07:42:13Z  in response to dbzThedinosaur
        only a quick point to think about; I have to check my testprogram for using indexes to answer md1972 in better quality.

        Sorry, I must write that! It is right, that the values of the percentages in the Perfomance Tuning paper aren't correct in every case. In most cases - I haven't much documented but I will do so from now on, therefor I have to cripple my mind - we got much less improvements. ( -- One example (not that topic) is, that in very old broshures I found that application could spare about 7% with using LE-Option ALL31. We tested with one appication and didn't found anything - with optimism nearly 0,5%. ;-)) I stated that in an GSE working group . . "unbelievable". Later the values had been corrected. --)

        Therefor: I use that information as hints.

        About the differences in numeric items used in perform-statements you could have a look on (all in German) http://www.cps4u.de/wikifiles/Schulungen_cps4it/cp-01-11-02_Workshop_PMA.pdf (Begin with "Seite 129" till "Seite 132") The links don't work. The source I used: http://www.cps4u.de/wikifiles/Schulungen_cps4it/cp-01-11-02_Workshop_PMA_Beispiel_07_Loops_nummerische_Felder_Programm_Source.txt
        I will upgrade my programm with using indexes. ;-))

        btw: The values in the performance guide I've seen the first time in a presentation of Tom Ross hold at Share 2002. And: I think that they haven't changed a lot so far.

        I've written about 30% improvement by using indexes. I have no documnet about it. What I've done was: I optimized 3 programs with using correct nummeric fields for looping, for looking at INITIALZE (for tables) and so on. The elapsed time was decreased from 9 minutes to 40 seconds. The last point was changing table subscripts to indexes. I used Strobe befor and after the changes. In the relevant loops I got at about 30% of optimization. (That was the first value of the performance paper I could reproduce. :-) and :-(.)

        Ralf
    • md1972
      md1972
      5 Posts
      ACCEPTED ANSWER

      Re: Cobol: Performance of subscripts vs. indexes

      ‏2012-07-04T15:26:31Z  in response to SystemAdmin
      craig-s, thank you for your elaborate test!
      We will rerun our tests and compare our results as well as our code, trying to track down the crucial differences.
    • md1972
      md1972
      5 Posts
      ACCEPTED ANSWER

      Re: Cobol: Performance of subscripts vs. indexes

      ‏2012-07-17T14:07:52Z  in response to SystemAdmin
      Sorry for being so late with our own new test results.

      We took craig-s's program code, just changing some minor details to fit in our company's general program framework.
      In addition, instead of using constants in the moves, we used variables (K-A, K-B, etc.) and stirred the five move instructions in the perform loops. Both alterations were made trying to ensure that no unwanted optimization would take place. ("Unwanted" would have been when the optimizer merged the five single moves to one big "MOVE 'ABC01' TO table line".)

      Here's the relevant code body (still very similar to craig-s's code):
      
      01  PGM-VERSION                        PIC  X(01). 01  K-A                                PIC  X(01) VALUE 
      "A". 01  K-B                                PIC  X(01) VALUE 
      "B". 01  K-C                                PIC  X(01) VALUE 
      "C". 01  K-0                                PIC  9(01) VALUE 0. 01  K-1                                PIC  9(01) VALUE 1. 01  WORK-AREA. 05  SBSC-F      PIC S9(008) COMP SYNC. 05  SBSC-H      PIC S9(004) COMP SYNC. 05  SBSC-P      PIC S9(005) COMP-3 SYNC. 05  SBSC-D      PIC S9(005) DISPLAY SYNC. 05  WORK-TABLE OCCURS 1000 INDEXED INDX. 10  FIELD-1 PIC X(001). 10  FIELD-2 PIC X(001). 10  FIELD-3 PIC X(001). 10  FIELD-4 PIC 9(001). 10  FIELD-5 PIC 9(001).   PROCEDURE DIVISION. *    PERFORM [company routine: read PGM-VERSION from file] EVALUATE PGM-VERSION WHEN 
      "F" PERFORM 50000 TIMES PERFORM VARYING SBSC-F FROM 1 BY 1 UNTIL SBSC-F > 1000 MOVE K-A  TO FIELD-1(SBSC-F) MOVE K-0  TO FIELD-4(SBSC-F) MOVE K-B  TO FIELD-2(SBSC-F) MOVE K-1  TO FIELD-5(SBSC-F) MOVE K-C  TO FIELD-3(SBSC-F) END-PERFORM END-PERFORM WHEN 
      "H" PERFORM 50000 TIMES PERFORM VARYING SBSC-H FROM 1 BY 1 UNTIL SBSC-H > 1000 MOVE K-A  TO FIELD-1(SBSC-H) MOVE K-0  TO FIELD-4(SBSC-H) MOVE K-B  TO FIELD-2(SBSC-H) MOVE K-1 TO FIELD-5(SBSC-H) MOVE K-C  TO FIELD-3(SBSC-H) END-PERFORM END-PERFORM WHEN 
      "P" PERFORM 50000 TIMES PERFORM VARYING SBSC-P FROM 1 BY 1 UNTIL SBSC-P > 1000 MOVE K-A  TO FIELD-1(SBSC-P) MOVE K-0  TO FIELD-4(SBSC-P) MOVE K-B  TO FIELD-2(SBSC-P) MOVE K-1  TO FIELD-5(SBSC-P) MOVE K-C  TO FIELD-3(SBSC-P) END-PERFORM END-PERFORM WHEN 
      "D" PERFORM 50000 TIMES PERFORM VARYING SBSC-D FROM 1 BY 1 UNTIL SBSC-D > 1000 MOVE K-A  TO FIELD-1(SBSC-D) MOVE K-0  TO FIELD-4(SBSC-D) MOVE K-B  TO FIELD-2(SBSC-D) MOVE K-1  TO FIELD-5(SBSC-D) MOVE K-C  TO FIELD-3(SBSC-D) END-PERFORM END-PERFORM WHEN 
      "I" PERFORM 50000 TIMES PERFORM VARYING INDX FROM 1 BY 1 UNTIL INDX > 1000 MOVE K-A  TO FIELD-1(INDX) MOVE K-0  TO FIELD-4(INDX) MOVE K-B  TO FIELD-2(INDX) MOVE K-1  TO FIELD-5(INDX) MOVE K-C  TO FIELD-3(INDX) END-PERFORM END-PERFORM END-EVALUATE GOBACK.
      


      Here are the results. The absolute numbers are irrelevant, of course. We are just interested in the relations to each other.
      
      PROCSTEP  PGM-VERSION CPUTIME (avg) SN        F           00:00:00.83 SN        H           00:00:00.92 SN        P           00:00:01.87 SN        D           00:00:01.86 SN        I           00:00:00.51 SS        F           00:00:00.84 SS        H           00:00:00.90 SS        P           00:00:01.83 SS        D           00:00:01.90 SS        I           00:00:00.56   ON        F           00:00:00.49 ON        H           00:00:00.52 ON        P           00:00:01.89 ON        D           00:00:01.85 ON        I           00:00:00.51 OS        F           00:00:00.48 OS        H           00:00:00.51 OS        P           00:00:01.89 OS        D           00:00:01.77 OS        I           00:00:00.55   BN        F           00:00:01.81 BN        H           00:00:00.49 BN        P           00:00:01.92 BN        D           00:00:01.84 BN        I           00:00:00.50 BS        F           00:00:01.82 BS        H           00:00:00.52 BS        P           00:00:01.89 BS        D           00:00:01.78 BS        I           00:00:00.58
      


      The terminology is the same as in craig-s's post. We didn't try OPT FULL.
      To get the average CPU times, we did five runs of each "program constellation", summed up all CPU times (according to SDSF) and divided the result by five. Sometimes we did 10 or 15 runs, the results were always nearly the same; the maximum difference between the single runs was 0.02 seconds.

      Some significant results in words:
      1) Indexes were the (relatively) fastest method only when using TRUNC(STD). With TRUNC(BIN) and TRUNC(OPT), some binary subscripts were faster than indexes. This result contradicts the common knowledge.
      2) COMP-3 and DISPLAY always belonged to the slowest method, which matches the common knowledge.
      3) The only situation where COMP-3 was (slightly) faster than DISPLAY was when using TRUNC(STD) and OPT(STD). In all other cases, DISPLAY was slightly faster than COMP-3. This result contradicts the common knowledge.
      4) With TRUNC(BIN) and NOOPT, S9(8) COMP is nearly as slow as DISPLAY. And when using OPT(STD), it's even slower. This result was at least unexpected.
      5) With OPT(STD), the index method was slower than with NOOPT. Some of the subscript also suffered from OPT(STD). This result was also unexpected.
      Of course, we are unhappy with these results.

      The performance guide's concrete percentage numbers could not been confirmed by anybody in this thread so far. (Okay - a confirmation would have been a huge surprise. Because the author didn't write what exactly his numbers are referring to. The CPU time to calculate the memory address of a certain table item?)
      Since craig-s's results correspond to the performance guide's statements - at least as a tendency, not in actual numbers -, it seems that our compiler defaults are abnormal and/or unfavorable.

      But: Still no clue where's the rub.



      P.S.: Here's a list of all other compiler settings used in the program:
      
      NOADATA NOADV QUOTE ARITH(EXTEND) NOAWO BUFSIZE(4096) NOCICS CODEPAGE(273) NOCOMPILE(S) NOCURRENCY DATA(31) NODATEPROC DBCS NODECK NODIAGTRUNC NODLL NODUMP NODYNAM NOEXIT NOEXPORTALL NOFASTSRT FLAG(W,E) NOFLAGSTD INTDATE(ANSI) LANGUAGE(EN) LIB LINECOUNT(55) NOLIST MAP NOMDECK NONAME NSYMBOL(NATIONAL) NONUMBER NUMPROC(NOPFD) OBJECT OFFSET OUTDD(SYSOUT) PGMNAME(COMPAT) RENT RMODE(AUTO) NOSEQUENCE SIZE(MAX) SOURCE SPACE(1) NOSQL SQLCCSID NOSSRANGE NOTERM TEST(NONE,SYM,SEPARATE) NOTHREAD NOVBREF WORD(TAB1) NOXREF YEARWINDOW(1900) NOZWB
      
      • BillWoodger
        BillWoodger
        99 Posts
        ACCEPTED ANSWER

        Re: Cobol: Performance of subscripts vs. indexes

        ‏2012-12-06T00:06:46Z  in response to md1972
        I was wondering about a reference in PeteInOxford's latest topic, and I guess it is to this topic.

        I am surprised, but not, yet, in the way that others state.

        There are four of R. J. Arellanes' papers on the Internet. The first does not mention indexes vs subscripts, but the other three do. Here are the figures reported:

        IBM COBOL for MVS & VM Version 1 Release 2
        Performance Tuning
        January 26, 1996

        "| Performance considerations for indexes vs subscripts (PIC S9(8)):
        | using binary data items (COMP) to address a table is 56% slower than using indexes
        | using decimal data items (COMP-3) to address a table is 426% slower than using indexes
        | using DISPLAY data items to address a table is 680% slower than using indexes"

        IBM Enterprise COBOL Version 3 Release 1
        Performance Tuning
        January 16, 2002

        "| Performance considerations for indexes vs subscripts (PIC S9(8)):
        | using binary data items (COMP) to address a table is 30% slower than using indexes
        | using packed decimal data items (COMP-3) to address a table is 300% slower than using indexes
        | using DISPLAY data items to address a table is 450% slower than using indexes"

        IBM Enterprise COBOL Version 4 Release 2
        Performance Tuning
        March 15, 2010

        "Performance considerations for indexes vs subscripts (PIC S9(8)):
        | Using binary data items (COMP) to address a table is 40% slower than using indexes
        | Using packed decimal data items (COMP-3) to address a table is 220% slower than using indexes
        | Using DISPLAY data items to address a table is 300% slower than using indexes"

        The figures change. Different compiler, different results, no surprise. What it shows which is of interest to the discussion is that each set of results has the same general pattern - the "what we always knew" thing. The figures also show that the tests are done for each compiler, and are not figures left from some previous work. Note the "change bars". Implication being that the figures even changed in the latest Edition (the 4.2 is on its sixth edition) of each of the papers.

        Anything else to argue that the figures broadly show something which is accurate?

        "In general, we do most of our measurements on MVS batch and CMS, but sometimes we also measure the
        language products on CICS and IMS. In measuring the performance of the language products on MVS
        batch and CMS, we use a variety of different tools that we have developed specifically for this purpose. Our
        tools can collect data such as CPU time used by a program (Virtual and Total CPU Time on CMS; TCB
        and SRB Time on MVS), elapsed time, SIO or EXCP counts, virtual storage usage, and paging activity
        (CMS only). When measuring on CICS and IMS, we usually enlist the help of other departments that are
        more familiar with transaction environments in collecting and analyzing data from RMF and SMF."

        These people are Cobol, Cobol, Cobol, or, more accurately, Language, Language, Language. They have tools developed specifically for the purpose of measuring the performance of the "language products". For CICS and IMS, they usually go elsewhere. So, they know what they are doing.

        "In measuring COBOL, we have three different types of benchmarks: compile-only, compile and execute, and
        kernels. The compile-only set contains programs which are designed to be compiled but not executed. These
        programs measure the compiler performance as a function of program size and range from 200 statements to
        more than 7,000 statements. The compile and execute set contains programs which are either subsets of
        "real" application programs or are entire application programs. These programs are somewhat representative
        of "real" application programs. Some are actual customer programs and the rest have been written by IBM.
        *The kernel set contains programs which are a collection of specific language statements enclosed in a loop of
        1,000 to 100,000 times. Each kernel program consists of several of these loops, with each loop having a
        different variation of that language statement. Each loop is surrounded by a call to a timing routine so that
        we can measure the performance of the individual statements."

        "Each loop is surrounded by a call to a timing routine so that
        we can measure the performance of the individual statements" it says. So who's done that here? What are the implications of not doing it?

        Taking the CPU time from the step gives you what? All the program start-up, LE initialisation, all the closing down stuff. You get all the "overhead" of the loops. You get ancillary code. You get the actual execution of the code of interest.

        Without being able to abstract that last from all the rest, it is like adding percentages together. You can do it, but the answer has no direct meaning.

        I want to demonstrate the relative densities of cooking oil and water. I get a measured volume of each (Olive Oil and Salt Water) and I know that if I weigh them I will get the answer. I get a big old black pot and put the oil in and another big old black pot and the water in. I weigh the two pots. Wow! I have proved that physics doesn't work because the answer is wrong. I'm really surprised.

        Yes, if I put enough oil and water in the pots such that the mass of the pots is negligible in relation to the mass of the liquids, I'll tend towards the correct answer (and more so if I also use the actual, specific, liquids used in the figures that I'm trying to match).

        Let's say that the volume of loops is sufficient to "outweigh" any "once-off" stuff. What about the overhead of the loops themselves? How much of the CPU is "looping" and how much is subscripted MOVEing? The overhead for the looping in the examples shown is not fixed per test case as, for unstated reasons, the item used for subscripting is also the loop control. Ralf had a better shot, with TIMES for the loops and SET/ADD for the index/subscript.

        We don't have the code which produced the original figures. We don't have the compile options. So we have to make some guesses.

        The compile options are easier. Everything for performance. ARITH(COMPAT),NUMPROC(PFD),TRUNC(OPT),NOSSRANGE

        Idea being that the optimum values would have been chosen, otherwise people could moan about the results. Just a guess, remember.

        What about OPT? With both. Not with OPT(FULL), as that has no further code-generation effect over OPT (at least as documented).

        What about the data? Index is obvious. Subscripts, COMP S9(8). COMP S9(4). COMP-3 with eight digits (so nine, of course) and four digits (so five). DISPLAY with eight digits (so nine, as it'll become packed along the way) and with four digits (so five).

        Loops to become TIMES and have embedded SET/ADD with appropriate initialisation prior to the loop.

        "Empty" loop.

        CPU timings around the loops.

        Hey, but how about that suggestion to look at the generated code?

        Un-optimized,

        Halfword subscript, four digits
        LH
        MH
        AR

        Fullword subscript, eight digits
        LH
        M
        AR

        Index, I suppose a theoretical nine digits
        L
        AR

        Why not write three tiny Assembler programs to execute each group a scrillion times or so? CPU from the step will be fine for that. We then know for certain which way is up. And the relative performance will give us more information for guessing some more.

        Anyone up for it?
  • SystemAdmin
    SystemAdmin
    403 Posts
    ACCEPTED ANSWER

    Re: Cobol: Performance of subscripts vs. indexes

    ‏2013-01-04T07:51:42Z  in response to md1972
    here is a test that i ran using Enterprise COBOL 4.2 in a Z/OS environment
    test001 --> binary full word subscripts
    test002 --> packed decimal subscripts
    test003 --> usage display subscripts
    test006 --> indexes
    test006a -> indexes plus compares against elementary usage index variables in the UNTIL clause of the PERFORM STATEMENT.
    02.31.47 J0147374 - TIMINGS (MINS.)

    02.31.47 J0147374 -JOBNAME STEPNAME PROCSTEP RC EXCP CPU SRB CLOCK

    02.31.47 J0147374 -TSUCZ1KT TEST001 TEST01 00 20 .76 .00 .81

    02.33.24 J0147374 -TSUCZ1KT TEST002 TEST01 00 20 1.50 .00 1.61

    02.35.51 J0147374 -TSUCZ1KT TEST003 TEST01 00 20 2.28 .00 2.44

    02.36.16 J0147374 -TSUCZ1KT TEST006 TEST01 00 20 .38 .00 .43

    02.36.35 J0147374 -TSUCZ1KT TEST006A TEST01 00 20 .28 .00 .30

    Notice the difference between the TEST006 and TEST006A with both using indexes…

    first the perform-epilog for TEST006 indexes compared to binary in the UNTIL clause

    000033 PERFORM-EPILOGUE

    0002FE 5820 98D8 L 2,2264(0,9) TBL-2-INDEX

    000302 4A20 A016 AH 2,22(0,10) PGMLIT AT +18

    000306 5020 98D8 ST 2,2264(0,9) TBL-2-INDEX

    00030A GN=13 EQU *

    00030A 5840 912C L 4,300(0,9) BLW=0

    00030E 5820 4008 L 2,8(0,4) MAX-2

    000312 8E20 0020 SRDA 2,32(0)

    000316 4B30 A01A SH 3,26(0,10) PGMLIT AT +22

    00031A 5C20 A014 M 2,20(0,10) PGMLIT AT +16

    00031E 5930 98D8 C 3,2264(0,9) TBL-2-INDEX

    000322 47B0 B09E BC 11,158(0,11) GN=12(0002EA)

    000034 PERFORM-EPILOGUE

    000326 5820 98D4 L 2,2260(0,9) TBL-1-INDEX

    00032A 4A20 A012 AH 2,18(0,10) PGMLIT AT +14

    00032E 5020 98D4 ST 2,2260(0,9) TBL-1-INDEX

    000332 GN=10 EQU *

    000332 5840 912C L 4,300(0,9) BLW=0

    000336 5820 4000 L 2,0(0,4) MAX-1

    00033A 8E20 0020 SRDA 2,32(0)

    00033E 4B30 A01A SH 3,26(0,10) PGMLIT AT +22

    000342 5C20 A010 M 2,16(0,10) PGMLIT AT +12

    000346 5930 98D4 C 3,2260(0,9) TBL-1-INDEX

    00034A 47B0 B094 BC 11,148(0,11) GN=9(0002E0)

    Now the perform-epilog from TEST006A indexes compared to elementary usage index variables in UNTIL clause

    000042 PERFORM-EPILOGUE

    000316 5820 98D8 L 2,2264(0,9) TBL-2-INDEX

    00031A 4A20 A016 AH 2,22(0,10) PGMLIT AT +18

    00031E 5020 98D8 ST 2,2264(0,9) TBL-2-INDEX

    000322 GN=13 EQU *

    000322 5830 912C L 3,300(0,9) BLW=0

    000326 5820 3018 L 2,24(0,3) SVIDX-TBL-2-IND

    00032A 5920 98D8 C 2,2264(0,9) TBL-2-INDEX

    00032E 47B0 B0B6 BC 11,182(0,11) GN=12(000302)

    000043 PERFORM-EPILOGUE

    000332 5820 98D4 L 2,2260(0,9) TBL-1-INDEX

    000336 4A20 A014 AH 2,20(0,10) PGMLIT AT +16

    00033A 5020 98D4 ST 2,2260(0,9) TBL-1-INDEX

    00033E GN=10 EQU *

    PP 5655-S71 IBM Enterprise COBOL for z/OS 4.2.0 TEST006A Date 01

    00033E 5830 912C L 3,300(0,9) BLW=0

    000342 5820 3010 L 2,16(0,3) SVIDX-TBL-1-IND

    000346 5920 98D4 C 2,2260(0,9) TBL-1-INDEX

    00034A 47B0 B0AC BC 11,172(0,11) GN=9(0002F8)
    IDENTIFICATION DIVISION.
    PROGRAM-ID. TEST001.
    AUTHOR. CHUCK HAATVEDT
    ENVIRONMENT DIVISION.
    DATA DIVISION.
    WORKING-STORAGE SECTION.

    01 SUB-1 PIC S9(9) COMP.
    01 SUB-2 PIC S9(9) COMP.

    01 TBL.
    05 TBL-ENTRY-LVL-1 OCCURS 100000 TIMES
    INDEXED BY TBL-1-INDEX.
    10 TBL-ENTRY-LVL-2 OCCURS 10 TIMES
    INDEXED BY TBL-2-INDEX.
    15 TBL-TEXT-1 PIC X.
    15 TBL-CHAR-1 PIC X.

    PROCEDURE DIVISION.

    PERFORM 5000 TIMES
    PERFORM VARYING SUB-1 FROM 1 BY 1
    UNTIL SUB-1 > 100000
    PERFORM VARYING SUB-2 FROM 1 BY 1
    UNTIL SUB-2 > 10
    MOVE SPACES TO TBL-TEXT-1 (SUB-1, SUB-2)
    MOVE 'A' TO TBL-CHAR-1 (SUB-1, SUB-2)
    END-PERFORM
    END-PERFORM
    END-PERFORM.

    GOBACK.
    IDENTIFICATION DIVISION.
    PROGRAM-ID. TEST002.
    AUTHOR. CHUCK HAATVEDT
    ENVIRONMENT DIVISION.
    DATA DIVISION.
    WORKING-STORAGE SECTION.

    01 SUB-1 PIC S9(9) COMP-3.
    01 SUB-2 PIC S9(9) COMP-3.

    01 TBL.
    05 TBL-ENTRY-LVL-1 OCCURS 100000 TIMES
    INDEXED BY TBL-1-INDEX.
    10 TBL-ENTRY-LVL-2 OCCURS 10 TIMES
    INDEXED BY TBL-2-INDEX.
    15 TBL-TEXT-1 PIC X.
    15 TBL-CHAR-1 PIC X.

    PROCEDURE DIVISION.

    PERFORM 5000 TIMES
    PERFORM VARYING SUB-1 FROM 1 BY 1
    UNTIL SUB-1 > 100000
    PERFORM VARYING SUB-2 FROM 1 BY 1
    UNTIL SUB-2 > 10
    MOVE SPACES TO TBL-TEXT-1 (SUB-1, SUB-2)
    MOVE 'A' TO TBL-CHAR-1 (SUB-1, SUB-2)
    END-PERFORM
    END-PERFORM
    END-PERFORM.

    GOBACK.

    ---> i'll post the source for the other 3 program in another reply.
  • SystemAdmin
    SystemAdmin
    403 Posts
    ACCEPTED ANSWER

    Re: Cobol: Performance of subscripts vs. indexes

    ‏2013-01-04T07:54:15Z  in response to md1972
    IDENTIFICATION DIVISION.
    PROGRAM-ID. TEST003.
    AUTHOR. CHUCK HAATVEDT
    ENVIRONMENT DIVISION.
    DATA DIVISION.
    WORKING-STORAGE SECTION.

    01 SUB-1 PIC 9(9).
    01 SUB-2 PIC 9(9).

    01 TBL.
    05 TBL-ENTRY-LVL-1 OCCURS 100000 TIMES
    INDEXED BY TBL-1-INDEX.
    10 TBL-ENTRY-LVL-2 OCCURS 10 TIMES
    INDEXED BY TBL-2-INDEX.
    15 TBL-TEXT-1 PIC X.
    15 TBL-CHAR-1 PIC X.

    PROCEDURE DIVISION.

    PERFORM 5000 TIMES
    PERFORM VARYING SUB-1 FROM 1 BY 1
    UNTIL SUB-1 > 100000
    PERFORM VARYING SUB-2 FROM 1 BY 1
    UNTIL SUB-2 > 10
    MOVE SPACES TO TBL-TEXT-1 (SUB-1, SUB-2)
    MOVE 'A' TO TBL-CHAR-1 (SUB-1, SUB-2)
    END-PERFORM
    END-PERFORM
    END-PERFORM.

    GOBACK.
    IDENTIFICATION DIVISION.
    PROGRAM-ID. TEST006.
    AUTHOR. CHUCK HAATVEDT
    ENVIRONMENT DIVISION.
    DATA DIVISION.
    WORKING-STORAGE SECTION.

    01 MAX-1 PIC S9(9) COMP.
    01 MAX-2 PIC S9(9) COMP.

    01 TBL.
    05 TBL-ENTRY-LVL-1 OCCURS 100000 TIMES
    INDEXED BY TBL-1-INDEX.
    10 TBL-ENTRY-LVL-2 OCCURS 10 TIMES
    INDEXED BY TBL-2-INDEX.
    15 TBL-TEXT-1 PIC X.
    15 TBL-CHAR-1 PIC X.

    PROCEDURE DIVISION.

    MOVE +100000 TO MAX-1.
    MOVE +10 TO MAX-2.

    PERFORM 5000 TIMES
    PERFORM VARYING TBL-1-INDEX FROM 1 BY 1
    UNTIL TBL-1-INDEX > MAX-1
    PERFORM VARYING TBL-2-INDEX FROM 1 BY 1
    UNTIL TBL-2-INDEX > MAX-2
    MOVE SPACES
    TO TBL-TEXT-1 (TBL-1-INDEX, TBL-2-INDEX)
    MOVE 'A'
    TO TBL-CHAR-1 (TBL-1-INDEX, TBL-2-INDEX)
    END-PERFORM
    END-PERFORM
    END-PERFORM.

    GOBACK.
    IDENTIFICATION DIVISION.
    PROGRAM-ID. TEST006A.
    AUTHOR. CHUCK HAATVEDT
    ENVIRONMENT DIVISION.
    DATA DIVISION.
    WORKING-STORAGE SECTION.

    01 MAX-1 PIC S9(9) COMP.
    01 MAX-2 PIC S9(9) COMP.
    01 SVIDX-TBL-1-INDEX USAGE INDEX.
    01 SVIDX-TBL-2-INDEX USAGE INDEX.

    01 TBL.
    05 TBL-ENTRY-LVL-1 OCCURS 100000 TIMES
    INDEXED BY TBL-1-INDEX.
    10 TBL-ENTRY-LVL-2 OCCURS 10 TIMES
    INDEXED BY TBL-2-INDEX.
    15 TBL-TEXT-1 PIC X.
    15 TBL-CHAR-1 PIC X.

    PROCEDURE DIVISION.

    MOVE +100000 TO MAX-1.
    MOVE +10 TO MAX-2.

    SET TBL-1-INDEX TO 100000.
    SET TBL-2-INDEX TO 10.

    SET SVIDX-TBL-1-INDEX TO TBL-1-INDEX.
    SET SVIDX-TBL-2-INDEX TO TBL-2-INDEX.

    PERFORM 5000 TIMES

    PERFORM VARYING TBL-1-INDEX FROM 1 BY 1
    UNTIL TBL-1-INDEX > SVIDX-TBL-1-INDEX
    PERFORM VARYING TBL-2-INDEX FROM 1 BY 1
    UNTIL TBL-2-INDEX > SVIDX-TBL-2-INDEX
    MOVE SPACES
    TO TBL-TEXT-1 (TBL-1-INDEX, TBL-2-INDEX)
    MOVE 'A'
    TO TBL-CHAR-1 (TBL-1-INDEX, TBL-2-INDEX)
    END-PERFORM
    END-PERFORM
    END-PERFORM.

    GOBACK.
  • SystemAdmin
    SystemAdmin
    403 Posts
    ACCEPTED ANSWER

    Re: Cobol: Performance of subscripts vs. indexes

    ‏2013-01-16T11:45:51Z  in response to md1972
    Interesting discussion - and results.
    One aspect of INDEX is missing, however (at least one :-) )
    The code examples shown use subscript the "usual" way - while real index'ing should use SET indx UP BY <some>
    I will try yo describe it the way I was taught:
    In the examples previously in this discussion:
    PERFORM VARYING INDX FROM 1 BY 1
    UNTIL INDX > 1000
    MOVE "A" TO FIELD-1(INDX)
    MOVE "B" TO FIELD-2(INDX)
    MOVE "C" TO FIELD-3(INDX)
    MOVE ZERO TO FIELD-4(INDX)
    MOVE 1 TO FIELD-5(INDX)
    END-PERFORM
    the compiler will add code to re-calculate table index in each loop-step. Giving code something like index= indx * <length-of-row>.

    If you instead of this code like
    > set indx to 1
    PERFORM 1000 times
    MOVE "A" TO FIELD-1(INDX)
    MOVE "B" TO FIELD-2(INDX)
    MOVE "C" TO FIELD-3(INDX)
    MOVE ZERO TO FIELD-4(INDX)
    MOVE 1 TO FIELD-5(INDX)
    > set indx up by 1
    END-PERFORM
    the compiler will insert code that ADD <length-of-row> to INDX. Which is much faster.
    Back-side is, that you can not use INDX to reference into a similar table with other <length-of-row>
    • BillWoodger
      BillWoodger
      99 Posts
      ACCEPTED ANSWER

      Re: Cobol: Performance of subscripts vs. indexes

      ‏2013-01-17T13:14:01Z  in response to SystemAdmin
      Did you actually try that?

      
      .   PERFORM 00037C  47F0 B182               BC    15,386(0,11) 0003C6  47B0 B144               BC    11,324(0,11) 0003BE  5820 A010               L     2,16(0,10) 0003C2  5920 9138               C     2,312(0,9)   SET 00041A  4600 B198               BCT   0,408(0,11) 000416  5800 D150               L     0,336(0,13) 0003D0  5800 A00C               L     0,12(0,10) 0003D4  5000 D150               ST    0,336(0,13)
      


      The above are the "mismatched" instructions, in no particular order, from the two pieces of code you showed. Two branches, a load and a compare are going to be faster than one branch, two loads and a store, I feel.

      So I tried it. The PERFORM VARYING to set the index is faster than the PERFORM TIMES with SET. Think about it. It makes sense.

      With OPT, it is similar:

      
      .   PERFORM 000320  47F0 B0BA               BC    15,186(0,11) 000352  47B0 B094               BC    11,148(0,11) 00034A  5820 A00C               L     2,12(0,10) 00034E  5920 9138               C     2,312(0,9)   SET 00035C  4100 03E8               LA    0,1000(0,0) 000360  5000 D150               ST    0,336(0,13) 00038A  5800 D150               L     0,336(0,13) 00038E  4600 B0D0               BCT   0,208(0,11)
      


      The point about the method of the loop in this topic is the need to compare like-for-like.

      TIMES with a SET and TIMES with ADD 1 are a better comparison method, then VARYING because the different PERFORM VARYING code generated affects the results of any timings.

      You need the same loop to control each, and an "empty" loop to adjust the times so that the effects of subscript vs index can be seen. Or just time the generated instructions :-)
      • SystemAdmin
        SystemAdmin
        403 Posts
        ACCEPTED ANSWER

        Re: Cobol: Performance of subscripts vs. indexes

        ‏2013-01-24T15:02:59Z  in response to BillWoodger
        The point isn't really about "perform varying" or " - times".
        It is about the compiler really using the INDEX phrase.
        Therefore - looking at the assembler code presented in my case with SET indx UP - the complete program part looks like this:
        
        000025  SET 000360  D203 9138 A07C       MVC   312(4,9),124(10)       IDX=1 000026  PERFORM 000366  4100 03E8            LA    0,1000(0,0) 00036A              GN=10    EQU   * 00036A  5000 D100            ST    0,256(0,13)           PFM=1 000027  MOVE 00036E  5820 9138            L     2,312(0,9)            INDX 000372  1832                 LR    3,2 000374  5A20 912C            A     2,300(0,9)            BLW=0 000378  92C1 2004            MVI   4(2),X
        'C1'            FIELD-1() 000028  MOVE 00037C  92C2 2005            MVI   5(2),X
        'C2'            FIELD-2() 000029  MOVE 000380  92C3 2006            MVI   6(2),X
        'C3'            FIELD-3() 000030  MOVE 000384  92C4 2007            MVI   7(2),X
        'C4'            FIELD-4() 000031  MOVE 000388  92C5 2008            MVI   8(2),X
        'C5'            FIELD-5() 000032  SET 00038C  4A30 A014            AH    3,20(0,10)            PGMLIT AT +16 000390  5030 9138            ST    3,312(0,9)              INDX 000394  5800 D100            L     0,256(0,13)             PFM=1 000398  4600 B146            BCT   0,326(0,11)         GN=10(00036A)
        


        which is considerably less than any other case shown - those examples would need at least 6 asm-statements for each MOVE.
        So - the thing is NOT in how fields defined for the PERFORM statement its all about REALLY using the index in subscripting.
        Best Regards
        Asger K.
        • BillWoodger
          BillWoodger
          99 Posts
          ACCEPTED ANSWER

          Re: Cobol: Performance of subscripts vs. indexes

          ‏2013-01-25T00:52:12Z  in response to SystemAdmin
          What I posted was the instructions which were different between the PERFORM VARYING which was setting the index, and PERFORM ... TIMES with the SET to set the index.

          There is nothing "magic" about SET, it is just one, of the four, ways that an index can be changed or given an initial value.

          I believe the PERFORM VARYING with the index vs the PERFORM ... TIMES with SET is faster. Since the first can use the index for two purposes, and the second has to use two different things for the same two purposes, it is no big surprise. The difference is not big, however.

          Now, the topic started with the idea of trying to confirm/deny the figures in the Enterprise Cobol Tuning Guides. However, it immediately went off on something of a tangent.

          To attempt to verify the Tuning Guides' figures, I believe you need to compare the code generated for one reference using an index, halfword subscript, fullword subscript, packed-decimal subscript, USAGE DISPLAY numeric subscript. Take the code which obtains the reference to storage in the table in each case, and compare.

          Everything else is "ancilliary" to that. Yes, of course, if the index is calculated once to reference five fields and a subscript five times to reference five fields, then the performance of referencing five fields will be even better for the index, but it is not going to match, in any way, the figures in the Tuning Guide because those refer to something else - not to five, or 15, or 31, references to fields.

          An important point demonstrated in this topic is that although subscripting with an index is faster than subscripting with a subscript, you can still mess everything up and loose the "benefit" if you do something silly with the control of the loop.
          • SystemAdmin
            SystemAdmin
            403 Posts
            ACCEPTED ANSWER

            Re: Cobol: Performance of subscripts vs. indexes

            ‏2013-01-25T12:38:20Z  in response to BillWoodger
            OK - I thought that I contributed to the investigation of how the tuning paper corresponded to real world of execution. Sorry if I didn't - -
            Still:
            As pointed out - the way original example used indx actually is not the most efficient.
            Doing a real-world test on our mainframe - these are the figures:
            Doing a loop with 500.000 around the code shown gives these results:
            Using the "VARYING" counter as subscript costs 25 cpu-seconds
            Using INDX as subscript and SET INDX UP BY 1 - will cost 2.5 cpu-seconds

            Putting it in almost same way as the tuning guide
            • in this case using binary subscript is 1000% slower than using index

            Then for the original questions from MD1971 -
            • The paper is based on Cobol V3R1, we use V3R4.1. Maybe there have been some vast improvements for subscripts since V3R1, and this part of the guide is out-dated. This is probably not your problem
            • Maybe we use compiler settings that disadvantage the use of indexes. Compiler settings are important - but expectedly not touching index.
            • Maybe we misinterpreted the propositions, and what we tested was something else than what R. J. Arellanes meant. (In this case, I would tend to say that this segment of the guide was written too ambiguously and should be more differentiated.) The segment could be more differentiated. But it has the info and references that I needed.
            • Maybe we corrupted the advantages of indexes by not handling indexes properly all through the experiment - e.g. by not using "SET IND UP BY 1", but simply modifying it in the PERFORM phrase. Yes - this seems to be the case!

            As for comparing to all other formats of the subscript - I will leave that out, since the big question was about index.
            • BillWoodger
              BillWoodger
              99 Posts
              ACCEPTED ANSWER

              Re: Cobol: Performance of subscripts vs. indexes

              ‏2013-01-25T13:15:04Z  in response to SystemAdmin
              1000% slower? No-one else got anything like that. The Tuning Guide gives around 30-40% slower for fullword with eight digits. You want to show your code and relevant compile options? You want to try to explain the difference?
              • BillWoodger
                BillWoodger
                99 Posts
                ACCEPTED ANSWER

                Re: Cobol: Performance of subscripts vs. indexes

                ‏2013-01-25T14:17:02Z  in response to BillWoodger
                To get away from this and back to the figures reported in the document.

                Using an index is 30% faster than using an 8-digit binary as a subscript (or 40%, or 56% depending on version of the compiler).

                I assume that that is true. In what way can they have reasonably produced that? By looking at the code for using an index, comparing it to the code for using a subscript, and, through calculation or experimentation, finding the difference in CPU usage.

                If you want to subscript an item (as in use a subscript or index to reference it) then an index will be 30% faster.

                As yet, no-one has tried to show that that is true, or not (depending on compiler used for the expected difference).

                What they have not done is come up with some "benchmark" and say that "in average use" (how would they come up with that?) these figures are true.

                Nor do they say "for any number of references to different items under the same group". Nor do they say for OPT/NOOPT, TRUNC(OPT/STD/BIN) etc.

                All that they have said, all that they can reasonably say, the code for an index is "this", for a subscript is "that", and the way they consume CPU is in this ratio.

                By the way, no-one in the discussion has even mentioned a potential "special case" where you have a single byte which OCCURS, but why let that get in the way of a good old general confusion.
              • SystemAdmin
                SystemAdmin
                403 Posts
                ACCEPTED ANSWER

                Re: Cobol: Performance of subscripts vs. indexes

                ‏2013-01-25T19:33:20Z  in response to BillWoodger
                The code used is basically what has been used by all other contributors.
                The change I made is shown in my response on January 16th - using SET INDX UP BY 1.
                I suggest you try that out using your own measurements and definitions - then posting results.

                "No-one else got anything like that" - you are right.
                None of the code examples in this discussion included the "SET INDX UP BY 1" untill I did it.

                "Tuning guide gives around 30-40% slower - -".
                Yes - but as others already pointed out, we don't really know what code was executed when measuring the difference. The cases in this discussion all seem to do five MOVE statements inside the loop. Meaning that time to calculate subscript/index probably weighs higher in this discussion than in the tuning (but we can't actually know). The content of this is - our measurements probably would overdo the differences.

                "show your code - -"
                As said - the code has been shown in several versions - only not containg the "SET INDX UP BY 1". So - code is already there.

                "You want to try explain the difference?" Oh, yes.
                The difference between using subscript and index in my example comes from the fact that using real index (SET UP INDX ) results in fewer asm-statements - see compile example on 24th of January. There the first MOVE results in 4 asm-statements while the rest only need 1. When using subscript this results in 6 asm-statements for each of the MOVE-stmts. Also - using PERFORM x TIMES result in less code in total, since the PERFORM-epilogue is much shorter with TIMES than with PERFORM VARYING.
                To me this explains quite large differences between the two.
                But - how come it is around a factor 10?
                I think the "Tuning guide" is based on a single MOVE in a loop. The 30% in "Tuning Guide" then is a "total loss" for loop and MOVE. Adding four more MOVE stmt inside the loop - those MOVEs would make an even bigger difference as described above.
                • BillWoodger
                  BillWoodger
                  99 Posts
                  ACCEPTED ANSWER

                  Re: Cobol: Performance of subscripts vs. indexes

                  ‏2013-01-26T00:22:54Z  in response to SystemAdmin
                  Where to start?

                  Firstly, SET has been referred to in this topic before, and, although I can't check as it gets "404", I think it was in Ralf's code.

                  In my response to your first post I showed the only instructions which were different between a PERFORM VARYING with the index and PERFORM ... TIMES with SET ... TO 1 before, and SET ... UP ... inside the loop.

                  The code generated, both with and without OPT, has only minor differences and runs "about the same". Therefore, those who have tested with PERFORM VARYING for the index against a subscript should have got your 10 times slower, but no-one got close.

                  By the comparison of the code generated, it is clear that PERFORM VARYING is a perfectly reasonable way of setting an index to an initial value and incrementing/decrementing it, as most people probably have assumed. There is very little performance difference between the two. For your results to be correct, there would have to be a difference by a factor of around four in favour of SET.

                  If you show your actual code, we can see how you got to a factor of 10 different, by "slowing down" the subscripting in some way, I assume. If you don't show your code, we can't see how, but we know it has happened.

                  That which you ascribe to the power of SET (the one-time calculation of the location of the data being indexed) is in fact down to the Optimizer. If you turn the Optimizer off (NOOPT) you'll see additional code before each MOVE for the index, whether with SET or with PERFORM VARYING...

                  Here is the unoptimised code for the PERFORM VARYING... and the SET:
                  
                  VARYING   PERFORM 00056E  5850 8430               L     5,1072(0,8) 000572  1205                    LTR   0,5 000574  47D0 B2A6               BC    13,678(0,11) 000578                 GN=13    EQU   * 000578  5000 D178               ST    0,376(0,13) PERFORM 00057C  D203 9148 A028          MVC   328(4,9),40(10) 000582  47F0 B292               BC    15,658(0,11) 000586                 GN=15    EQU   * MOVE 000586  5820 9148               L     2,328(0,9) 00058A  5A20 912C               A     2,300(0,9) 00058E  92C1 2026               MVI   38(2),X
                  'C1' MOVE 000592  5820 9148               L     2,328(0,9) 000596  5A20 912C               A     2,300(0,9) 00059A  92C2 2027               MVI   39(2),X
                  'C2' MOVE 00059E  5820 9148               L     2,328(0,9) 0005A2  5A20 912C               A     2,300(0,9) 0005A6  92C3 2028               MVI   40(2),X
                  'C3' MOVE 0005AA  5820 9148               L     2,328(0,9) 0005AE  5A20 912C               A     2,300(0,9) 0005B2  92F0 2029               MVI   41(2),X
                  'F0' MOVE 0005B6  5820 9148               L     2,328(0,9) 0005BA  5A20 912C               A     2,300(0,9) 0005BE  92F1 202A               MVI   42(2),X
                  'F1' PERFORM-EPILOGUE 0005C2  5820 9148               L     2,328(0,9) 0005C6  4A20 A02C               AH    2,44(0,10) 0005CA  5020 9148               ST    2,328(0,9) 0005CE                 GN=16    EQU   * 0005CE  5820 A018               L     2,24(0,10) 0005D2  5920 9148               C     2,328(0,9) 0005D6  47B0 B24A               BC    11,586(0,11) 0005DA                 GN=14    EQU   * 0005DA  5800 D178               L     0,376(0,13) 0005DE  4600 B23C               BCT   0,572(0,11) 0005E2                 GN=12    EQU   *   SET   PERFORM 0005F2  5830 8430               L     3,1072(0,8) 0005F6  1203                    LTR   0,3 0005F8  47D0 B32A               BC    13,810(0,11) 0005FC                 GN=18    EQU   * 0005FC  5000 D17C               ST    0,380(0,13) SET 000600  D203 9148 A028          MVC   328(4,9),40(10) PERFORM 000606  5800 A014               L     0,20(0,10) 00060A                 GN=20    EQU   * 00060A  5000 D180               ST    0,384(0,13) MOVE 00060E  5820 9148               L     2,328(0,9) 000612  5A20 912C               A     2,300(0,9) 000616  92C1 2026               MVI   38(2),X
                  'C1' MOVE 00061A  5820 9148               L     2,328(0,9) 00061E  5A20 912C               A     2,300(0,9) 000622  92C2 2027               MVI   39(2),X
                  'C2' MOVE 000626  5820 9148               L     2,328(0,9) 00062A  5A20 912C               A     2,300(0,9) 00062E  92C3 2028               MVI   40(2),X
                  'C3' MOVE 000632  5820 9148               L     2,328(0,9) 000636  5A20 912C               A     2,300(0,9) 00063A  92F0 2029               MVI   41(2),X
                  'F0' MOVE 00063E  5820 9148               L     2,328(0,9) 000642  5A20 912C               A     2,300(0,9) 000646  92F1 202A               MVI   42(2),X
                  'F1' SET 00064A  5820 9148               L     2,328(0,9) 00064E  4A20 A02C               AH    2,44(0,10) 000652  5020 9148               ST    2,328(0,9) 000656  5800 D180               L     0,384(0,13) 00065A  4600 B2CE               BCT   0,718(0,11) 00065E                 GN=19    EQU   * 00065E  5800 D17C               L     0,380(0,13) 000662  4600 B2C0               BCT   0,704(0,11) 000666                 GN=17    EQU   *
                  

                  If you remove the instructions which are the same in the two pieces of code (and ignore the generated lables) you'll get the instructions I posted earlier. Nothing there is going to give you the four-fold improvement with "SET" that you need to get a 10-fold slowdown for the subscripts with the code that has already been shown in the topic (four-fold is the minimum you need to get 10-fold over one of the comparisons).

                  SET gives you nothing special when compared to PERFORM VARYING to set the index values.

                  I'll say it again. SET gives you nothing special when compared to PERFORM VARYING to set the index values, as demonstrated by the generated code.

                  Clear?

                  Using an index to reference one field is 30%, 56%, 40% faster than using an 8-digit binary field as a subscript.

                  Without the OPTimizer, this can be applied to referencing more than one field. With the OPTimizer, the benefits of using an index are increased when there is more than one field, but by nowhere close to a factor of 10 unless you are referencing hundreds, perhaps thousands of fields.

                  If you still know different, show your code, your actual code, not just describing it, and compile options (those which affect generated code) used.

                  With no significant difference between SET and PERFORM VARYING approaches, you state that you have achieved results which no-one else has. Show your code, and we'll know why.
                  • SystemAdmin
                    SystemAdmin
                    403 Posts
                    ACCEPTED ANSWER

                    Re: Cobol: Performance of subscripts vs. indexes

                    ‏2013-01-26T16:16:45Z  in response to BillWoodger
                    It's quite OK you question my results. Asking me to show my code is not - since it was published on 16.january as said previously.
                    You yourself could show your own code, compile options and performance measurements!
                    The cut-out you have doesn't show anything about such.

                    To me it still seems clear that using INDEX improves performance considerably.

                    Then - most performance-trouble is connected to database and other stuff external to COBOL.
                    Therefore the index discussion is fairly academic - few of us will meet heavy subscripting relevant to indexing anyway.

                    So - I will leave the index discussion here :-)
                    • BillWoodger
                      BillWoodger
                      99 Posts
                      ACCEPTED ANSWER

                      Re: Cobol: Performance of subscripts vs. indexes

                      ‏2013-01-27T11:10:53Z  in response to SystemAdmin
                      As I mentioned previously, the code I used was the code you posted. I showed the difference in the generated instructions and stated that the results were sufficiently similar that it would be impossible to get "reasonable" code for the use of subscripts (which you did not provide) to be 10 times slower when no-one else had got near that. People have shown A and B, where A is results of indexing from PERFORM VARYING and B is from using subscripts. C, with SET, is equivalent to A, so the results to subscripts will be in the same proportion, unless the use of subscripts was poorly coded.

                      If you still feel that something else is "clear" to you, then I doubt anything you can

                      How you feel you are able to "improve performance considerably" and regard the discussion as "academic" at the same time is "interesting", but there we go.
                      • SystemAdmin
                        SystemAdmin
                        403 Posts
                        ACCEPTED ANSWER

                        Re: Cobol: Performance of subscripts vs. indexes

                        ‏2013-01-28T11:15:37Z  in response to BillWoodger
                        OK - one last shot then - -
                        The code or the compiler is different. As an example - with NOOPT compile option I get 5 asm-statements for MOVE using subscript and 3 for index. With OPT STD it's 1 for MOVE using index.
                        I ran and measured the last one.

                        Also - take a look at craig and chaat measurements on first page. They show a factor 3-5 - so somebody are close.

                        About "academic" - it was related to the fact that business programs looping millions of times using subscript are VERY rare.

                        And - then I am out of here!
                        • BillWoodger
                          BillWoodger
                          99 Posts
                          ACCEPTED ANSWER

                          Re: Cobol: Performance of subscripts vs. indexes

                          ‏2013-01-28T12:23:43Z  in response to SystemAdmin
                          I suspect everyone is using Enterprise Cobol, although different versions, maybe, which can give different results, although not the factor that you are looking for.

                          PERFORM VARYING is pretty-much equivalent to PERFORM ... TIMES with SET (I believe I've already mentioned this) so your timings should be the same as Craig's, you can't expect a big difference from those with equivalent code.

                          Chuck is using two levels of subscripting, so you can't take that into account with your code against what you have shown with SET.

                          Anyway, even five is not "close" to 10.

                          Are you saying you compared the index with OPT(STD) to the subscript with NOOPT? Perhaps using TRUNC(BIN) as well? Looking at Craig's figures, that could give you 10, but is hardly a reasonable way to compare things.
                        • SystemAdmin
                          SystemAdmin
                          403 Posts
                          ACCEPTED ANSWER

                          Re: Cobol: Performance of subscripts vs. indexes

                          ‏2013-03-19T15:44:30Z  in response to SystemAdmin
                          >> About "academic" - it was related to the fact that business programs looping millions of times using subscript are VERY rare. <<

                          The companies, where I am working with, run several million transactions per day with long calling chains and programs in which many tables were used. If everyone would code optimized programs IBM would sell less z-machines. ;-)))

                          ----

                          Thinking about index or subscript is one point for improving performance. A few years ago I estimated the monetary advantages for one great German Bank if only the loops (PERFORM) would be coded "correct": It would have been about 1 processor / about 0,2%. For one CP you've to pay about 1 Mio. Euro.

                          ----

                          And: I haven't seen an answer why (my) code with binary fields is faster than code with indexes.

                          ----

                          Binary fields:
                          • pic s9(*9*) binary is different from pc s9(*8*) binary.
                          • binary fields with trunc(bin) have "terrible" performance.
                          • BillWoodger
                            BillWoodger
                            99 Posts
                            ACCEPTED ANSWER

                            Re: Cobol: Performance of subscripts vs. indexes

                            ‏2013-03-20T00:04:42Z  in response to SystemAdmin
                            Two things, Ralf. I thought they were both discussed, if not aimed directly to yours.

                            Firstly, a one-byte table entry is "special" for a subscript, as there needs to be no "calculation" - the value of the subscript is the address modification required from the start address of the table.

                            Your code comes like this for the subscript:

                            
                            000115  MOVE 000480  5840 2000               L     4,0(0,2)                I-BIN 000484  1A42                    AR    4,2 000486  92E7 4077               MVI   119(4),X
                            'E7'            TAB-INHALT()
                            


                            For the index:

                            
                            000606  5840 AF08               L     4,3848(0,10)            I-IDX 00060A  1854                    LR    5,4 00060C  1A42                    AR    4,2 00060E  92E7 4078               MVI   120(4),X
                            'E7'            TAB-INHALT()
                            


                            An extra instruction for the index, so it will be slower.

                            Changing the entry to a length of two (filler of one after the field you use, and reduce number of table entries by 50% :-) ) gives:

                            
                            000117  MOVE 000480  4850 3038               LH    5,56(0,3)               PGMLIT AT +12 000484  5C40 2008               M     4,8(0,2)                I-BIN 000488  1865                    LR    6,5 00048A  1A62                    AR    6,2 00048C  92E7 607E               MVI   126(6),X
                            'E7'            TAB-INHALT()
                            

                            And for the index:

                            
                            000173  MOVE 000636  5840 AF08               L     4,3848(0,10)            I-IDX 00063A  1854                    LR    5,4 00063C  1A42                    AR    4,2 00063E  92E7 4080               MVI   128(4),X
                            'E7'            TAB-INHALT()
                            


                            So now the index is faster.

                            Secondly, you are "killing" your index loop by comparing to a binary value.

                            
                            000170  PERFORM-EPILOGUE 000612  4A50 3036               AH    5,54(0,3)               PGMLIT AT +10 000616  5050 AF08               ST    5,3848(0,10)            I-IDX 00061A                 GN=57    EQU   * 00061A  5830 9188               L     3,392(0,9)              BLW=0 00061E  5820 3014               L     2,20(0,3)               I-BIN-MAX 000622  5840 C004               L     4,4(0,12)               CBL=1 000626  4B20 4036               SH    2,54(0,4)               PGMLIT AT +10 00062A  4C20 4036               MH    2,54(0,4)               PGMLIT AT +10 00062E  5920 AF08               C     2,3848(0,10)            I-IDX 000632  47B0 B28C               BC    11,652(0,11)            GN=56(0005F8)
                            

                            If you set the index to the binary value, then set a usage index to the index (to hold the maximum index value) and use that as the loop control:

                            
                            000174  PERFORM-EPILOGUE 000642  4A50 3038               AH    5,56(0,3)               PGMLIT AT +12 000646  5050 AF08               ST    5,3848(0,10)            I-IDX 00064A                 GN=57    EQU   * 00064A  5830 9188               L     3,392(0,9)              BLW=0 00064E  5820 3000               L     2,0(0,3)                MAX-FOR-INDEX 000652  5920 AF08               C     2,3848(0,10)            I-IDX 000656  47B0 B2BC               BC    11,700(0,11)            GN=56(000628)
                            
                  • SystemAdmin
                    SystemAdmin
                    403 Posts
                    ACCEPTED ANSWER

                    Re: Cobol: Performance of subscripts vs. indexes

                    ‏2013-03-19T15:12:24Z  in response to BillWoodger
                    Sorry. I've changed the provider and had forgotten to move "that" directory. All links should work now.
                    Ralf
  • BillWoodger
    BillWoodger
    99 Posts
    ACCEPTED ANSWER

    Re: Cobol: Performance of subscripts vs. indexes

    ‏2013-04-02T23:43:22Z  in response to md1972
    For anyone who wants to "play" with "inline" CPU timings:

    Define something like this in the LINKAGE SECTION:

    
    .       01  L-CPU-TIME PIC X(8).
    


    Put this somewhere before the CPU time is needed:

    
    .           CALL 
    "BBPFTC1" USING ADDRESS OF L-CPU-TIME
    


    This (code of BBPFTC1 below) sets the address of L-CPU-TIME to the CPU Time in the Address Space Control Block (ASCB). After the single CALL, the program is no longer needed, and may be even be CANCELled.

    Save the CPU time before and after the code to be "timed".

    When all else is done (this shows the calculations for an "empty loop" which can be used to modify the time for a loop with code you want to know about, "abstracting" the loop-control overhead from the results). The 4096 is the "granularity" of the raw time measurement. Dividing by 4096 and using the PICture for W-CPU-TIME-FOR-DISPLAY gets a result in seconds, and parts thereof:
    
    .          COMPUTE W-EMPTY-CPU          = ( W-SAVE-CPU-A-EMPT -   W-SAVE-CPU-B-EMPT ) / 4096 MOVE W-EMPTY-CPU             TO W-CPU-TIME-FOR-DISPLAY DISPLAY 
    "EMPT CPU>" W-CPU-TIME-FOR-DISPLAY 
    "<"
    


    
    .      01  W-SAVE-CPU-B-EMPT COMP-5 PIC 9(18). 01  W-SAVE-CPU-B-EMPTX REDEFINES W-SAVE-CPU-B-EMPT PIC X(8). 01  W-SAVE-CPU-A-EMPT COMP-5 PIC 9(18). 01  W-SAVE-CPU-A-EMPTX REDEFINES W-SAVE-CPU-A-EMPT PIC X(8). 01  W-CPU-TIME-FOR-DISPLAY   PIC Z(11)9,99,9999.
    


    The sub-program BBPFTC1:
    
    .      ID DIVISION. PROGRAM-ID. BBPFTC1. DATA DIVISION. WORKING-STORAGE SECTION. 01  W-PSA-POINTER                POINTER. LINKAGE SECTION. 01  PSA-CONTROL-BLOCK. 05  FILLER                   PIC X(548). 05  PSA-CB-ASCB-POINTER      POINTER. 01  ASCB-CONTROL-BLOCK. 05  FILLER                   PIC X(64). 05  ASCB-CB-CPUTIME          PIC X(8). 01  L-CPU-TIME-PTR         USAGE POINTER. PROCEDURE DIVISION               USING L-CPU-TIME-PTR. SET W-PSA-POINTER            TO NULL SET ADDRESS OF PSA-CONTROL-BLOCK TO W-PSA-POINTER SET ADDRESS OF ASCB-CONTROL-BLOCK TO PSA-CB-ASCB-POINTER SET L-CPU-TIME-PTR           TO ADDRESS OF ASCB-CB-CPUTIME GOBACK .