Copycode-Interrnal Subroutine-External Subroutine-Subprogram

I would like to know how much CPU can i save (if any) if i use a copycode instead of an internal subroutine. I have a customer with many perform’s and the subroutines that are called are performed only once, so i figured that a copycode is more efficient. Is this true ?
How about “Copycode - Interrnal Subroutine - External Subroutine - Subprogram” what are the CPU costs of performing the same task using these diffrent options ?

I also often code a perform on an inline subroutine that appears only once in a program. I do it for structuring purposes to avoid a bunch of statements that disturb the program readabilitiy. For example:

 PERFORM FETCH-THE-CAR
PERFORM CALCULATE-THE-PRICE
PERFORM WRITE-THE-INVOICE
PERFORM DELIVERY

is much more readable than

 /* now we have to fetch the car
STATEMENT 1
STATEMENT 2
...
/* now we calculate the price
MUCH MORE STATEMENTS
MUCH MORE STATEMENTS
MUCH MORE STATEMENTS
MUCH MORE STATEMENTS
MUCH MORE STATEMENTS
MUCH MORE STATEMENTS
...
/* now we write the invoice
WRITE
WRITE
WRITE
WRITE
WRITE
WRITE
WRITE
WRITE
WRITE
WRITE
WRITE
WRITE
...
/* now we do the delivery
AND SO ON

You may save CPU time minimally, but you loose readbility. If you put code sequences into COPYCODE you will loose much more readability.

Happy maintenance! :wink:

Hi Yehuda;

In short, if the PERFORMs appear only once, AND, they are not in a loop of some sort (thus they are PERFORM’ed only once), you will probably not save very much.

HOWEVER, if you are in a loop; for example

READ MYFILE IN PHYSICAL SEQUENCE
PERFORM CHECK-FOR-SPECIAL
PERFORM CHECK-FOR-DISCOUNT
PERFORM WRITE-REPORT
etc

and MYFILE has a couple of million records, I would strongly suggest putting the code either inline, or using copycode.

I must disagree with the posting by Wilfried123 (sorry Wilfried), albeit a philosophical disagreement rather than a quantitative disagreement. I find the code shown by Wilfried to be quite readable. I tend to add a string of asterisks before and after the code, for example

********** compute discount ***************
*
code here
*
********* end of compute discount *************

But even as Wilfried showed, I find the code quite readable; and, since I can SCAN for text in a comment, I can find things quite simply.

But, to repeat from earlier in the post; if something will be PERFORM’ed just once, I would not bother.

If the code will be used elsewhere (other objects, other systems), and will be PERFORM’ed in a loop, AND, is likely to change, I would favor copycode, otherwise, I prefer, as implied above, simply incorporating the code inline.

steve

Hi Wilfried123;

Sorry for referencing you, when the posting I was addressing was from billiboy. Thats what happens when you have multiple windows open at once.

steve

Hi Steve,
So I understand that CPU/Performance-wise a copycode is more efficent than an internal subroutine.
How about the diffrences betwen an external subroutine and a subprogram ?
It’s clearer to write perform long-subroutine-name than a 8 byte name to call a subprogram, and the global is another reason to favor an external subroutine, but whats most important to me is performance. I can always (or atleast try to) “force” the user to add remarks to make it more understandable.

Steve,

I do not agree with you. Of course, you can read a book without having a table of contents, but if you search something, a table of contents is very useful.

If I code PERFORM one after the other, this is like a table of contents to show, what ist done in the program. The subroutines show me how it is done.

That’s what I mean with readability.

Hi Yehuda;

Comparison of the code for MOVE #A TO #B

Done in a loop from 1 to 500,000

Overhead of dummy FOR loop, - 10

Inline MOVE - 10 (less than a tenth second)

Internal PERFORM - 12 (minus the 10 = 2)

External PERFORM - 190 (minus the 10 = 180)

CALLNAT - 210 (minus the 10 = 200)

In the case of the CALLNAT and the external PERFORM, I used a LOCAL, not a PARAMETER, data area.

I was actually a bit surprised by the last two. I thought the extra lookup of the subroutine name (to get the object name) would cause that to be slightly slower than the CALLNAT. Not true.

These were run on a PC using Nat 6.1.1. When I get some time, I will get you mainframe times. But, having once run these on the mainframe, I do recall the numbers were in a similar ratio. You pay a big price for external subroutines and subprograms.

steve

Hi Steve,

Thanks for the valuable information.
Could you please send me the code that you used to get this information ?
You wrote:
“I was actually a bit surprised by the last two. I thought the extra lookup of the subroutine name (to get the object name) would cause that to be slightly slower than the CALLNAT. Not true.” - Then why is the subroutine really faster ? Besides looking up the object-name, is the process of running the external module(subroutine/subprogram) the same ? and therefore like you said it should take longer !!!

Hi Billiboy;

Just a comment about your post:


If I code PERFORM one after the other, this is like a table of contents to show, what is done in the program. The subroutines show me how it is done.

That’s what I mean with readability.


I would argue (not too vehemently, since it is not worth the time) that the approach I employ shows both what is done, and how it is done. During development, I am mainly concerned with how something is done, since I am debugging the code. Similarly, when maintaining/enhancing the code I am mainly concerned with how something is done.

“What” is being done can easily be handled by comments, which is what they were invented for.

Were it not for the performance price, I would be less inclined to argue. If someone prefers what they perceive as more readable code (PERFORMs), fine. HOWEVER, there is a large performance price to be paid, especially if one goes outside an object (CALLNAT or external PERFORM). See my last posting regarding performance.

steve

Hi Yehuda;

The code is rather simple. However, since I have the actual code on another computer, I will type (hopefully without typos) the code here

seta. settime
for #loop = 1 to 30000
ignore
end-for
write ‘dummy loop time’ *timd (seta.)
*
setb. settime
for #loop = 1 to 30000
move #a to #b
end-for
write ‘inline move time’ *timd (setb.)
*
setc. settime
for #loop = 1 to 30000
perform mover
end-for
write ‘internal perform time’ *timd (setc.)
*
setd. settime
for #loop = 1 to 30000
perform exmover
end-for
write ‘external perform time’ *timd (setd.)
*
sete. settime
for #loop = 1 to 30000
callnat ‘mymove’
end-for
write ‘dummy loop time’ *timd (sete.)
*

#a and #b were both defined as A3. in both the external subroutine and the subprogram, there are no parameter data areas, just a local with #a and #b. SO, this is not totally an accurate comparison since no data is being “passed” between the program and the subprogram/subroutine.

steve

1 Like