A REXX Program is available to calculate Line of Codes.
I have replaced the below piece of code
Code:
/**********************************REXX****************************/
SAY 'ENTER INPUT PDS'
/*PULL INPDS */
INPDS ='N141129.FIRST.PDS'
INPDS = STRIP(INPDS)
INPDS1 = INPDS
INPDS = "'"||INPDS||"'"
UID = USERID()
T=OUTTRAP('OUTLIST.')
OUTDSN = "R107PB.LOC.OUTFILE." || UID
"LISTDS "INPDS" MEMBERS"
SAY OUTLIST.0
J=1;MEMLIST.0=0;MEMLIST.='';
DO I=1 TO OUTLIST.0
IF(STRIP(OUTLIST.I)='--MEMBERS--') THEN
ST='START'
ELSE
NOP
IF((ST='START') & (STRIP(OUTLIST.I) /= '--MEMBERS--')) THEN
DO
MEMLIST.J=OUTLIST.I
J=J+1
END
ELSE
NOP
END
J=J-1
L = 1
TOTAL = 0
I = 0
MESG.0 = 0
TOTAL_INPUT = 0
TOTAL_CMNTS = 0
TOTAL_BLNKS = 0
TOTAL_CODE = 0
DO I = 1 TO J
PDSMEM= "'"||INPDS1||"("||STRIP(MEMLIST.I)||")'"
"ALLOCATE F(INPUT) DA("||PDSMEM||")SHR"
"EXECIO * DISKR INPUT (FINIS STEM INPUT."
"FREE DD(INPUT)"
COMMENTS = 0
BLANKS = 0
CODE = 0
DO M=1 TO INPUT.0
IF SUBSTR(INPUT.M,7,1) = '*' THEN
COMMENTS = COMMENTS + 1
ELSE
IF SUBSTR(INPUT.M,7,66) = ' ' THEN
BLANKS = BLANKS + 1
ELSE
CODE = CODE + 1
END
COMMENTS = FORMAT(COMMENTS,4)
BLANKS = FORMAT(BLANKS,4)
CODE = FORMAT(CODE,5)
INPUT.0 = FORMAT(INPUT.0,5)
MESG.0 = MESG.0 + 1
MESG.I = SUBSTR(MEMLIST.I,3,8) || " COMMENTS:" || COMMENTS
MESG.I = MESG.I || ' BLANKS:' BLANKS || ' CODE:' CODE
MESG.I = MESG.I || ' TOTAL:' || INPUT.0
TOTAL_INPUT = TOTAL_INPUT + INPUT.0
TOTAL_CMNTS = TOTAL_CMNTS + COMMENTS
TOTAL_BLNKS = TOTAL_BLNKS + BLANKS
TOTAL_CODE = TOTAL_CODE + CODE
END
MESG.I = ' '
I = I + 1
MESG.I = 'INPUT PDS : ' || STRIP(INPDS,'B',"'")
I = I + 1
MESG.I = 'NO. OF MEMBERS: ' || J
I = I + 1
MESG.I = 'BLANKS : ' || TOTAL_BLNKS
I = I + 1
MESG.I = 'COMMENTS : ' || TOTAL_CMNTS
I = I + 1
MESG.I = 'TOTAL LINES : ' || TOTAL_INPUT
I = I + 1
MESG.I = ' '
/*--WRITTING FILE - JCL AND CONTROL CARD--*/
ADDRESS TSO "ALLOC DA('"OUTDSN"') REUSE MOD UNIT(SYSDA)
LRECL(80) RECFM(F B) SPACE(10,10) TRACK RELEASE DSO(PS)
BLKSIZE(8000) FI(OUTDD1)"
IF RC \= 0 THEN
DO
SAY "CAN'T ALLOCATE JCL.CNTL PS" RC
EXIT
END
ADDRESS TSO "EXECIO * DISKW OUTDD1 (STEM MESG. FINIS"
IF RC \= 0 THEN
DO
SAY "CAN'T WRITE TO JCL.CNTL PS"
EXIT
END
ADDRESS TSO "FREE FI(OUTDD1)"
IF RC \= 0 THEN
DO
SAY "CAN'T FREE JCL.CNTL PS"
EXIT
END
SAY 'SEE ' OUTDSN ' FOR STATS'
EXIT
with the below piece of code
Code:
/*******REXX**********/
ADDRESS ISPEXEC
"ISREDIT MACRO"
ADDRESS ISPEXEC
"CONTROL ERRORS RETURN"
CNTS1 = 00000000
CNTS2 = 00000000
CNTS3 = 00000000
USEID = USERID()
DS = USEID||'.R107YB.REXX.OUTPUT'
ADDRESS TSO
"ALLOC F(OUT) DA('"DS"') MOD"
ADDRESS ISPEXEC
"ISREDIT (MEMNAME) = MEMBER"
IF MEMNAME = ' ' THEN
DO
ADDRESS ISPEXEC
"ISREDIT (DSN) = DATASET"
END
ADDRESS ISPEXEC
"ISREDIT F IDENTIFICATION 8"
IF RC <> 0 THEN
DO
IF MEMNAME <> ' ' THEN
DO
OUT.1 = MEMNAME 'IS NOT A COBOL PGM'
END
ELSE
DO
OUT.1 = DSN 'IS NOT A COBOL PGM'
END
ADDRESS TSO
'EXECIO * DISKW OUT(STEM OUT. FINIS)'
'FREE F(OUT)'
CALL PGM_EXIT
END
/* macro to filter only the comments in a cobol pgm */
ADDRESS ISPEXEC
"ISREDIT X ALL"
"ISREDIT F ALL '*' 7 "
IF RC = 0 THEN
DO
/* macro to get the count value for comments */
ADDRESS ISPEXEC
"ISREDIT (CNTS1) = FIND_COUNTS"
END
ADDRESS ISPEXEC
/* macro to find the total lines used in a cobol pgm */
"ISREDIT X ALL"
"ISREDIT F ALL P'=' 7 "
IF RC = 0 THEN
DO
/* macro to get the count value for total lines */
ADDRESS ISPEXEC
"ISREDIT (CNTS2) = FIND_COUNTS"
END
/* macro to find the blank lines used in a cobol pgm */
ADDRESS ISPEXEC
"ISREDIT X ALL"
"ISREDIT F ALL P'@' 7 72"
"ISREDIT DEL ALL NX"
"ISREDIT F ALL X'40' 7"
IF RC = 0 THEN
DO
/* macro to get the count value for blank lines */
ADDRESS ISPEXEC
"ISREDIT (CNTS3) = FIND_COUNTS"
END
IF MEMNAME <> ' ' THEN
DO
NOP
END
ELSE
DO
MEMNAME = DSN
END
L1= SUBSTR(MEMNAME,1,43)
X1= SUBSTR(COMMENTS,1,10)
X2= SUBSTR(CODE,1,10)
X3= SUBSTR(BLANKS,1,10)
Y1= SUBSTR(CNTS1,1,10)
Y2= SUBSTR(CNTS2,1,10)
Y3= SUBSTR(CNTS3,1,10)
OUT.1 = L1 || X1 || Y1
OUT.2 = ' ' || X2 || Y2
OUT.3 = ' ' || X3 || Y3
ADDRESS TSO
'EXECIO * DISKW OUT(STEM OUT. FINIS)'
'FREE F(OUT)'
PGM_EXIT:
ADDRESS ISPEXEC "ISREDIT CANCEL"
EXIT
the above code is executed for each member of an pds with the run macro
Code:
/***********REXX******************/
SAY 'Enter Input PDS'
/*PULL DSNNAME */
/*DSNNAME='N141129.FIRST.PDS'*/
PARSE ARG DSNNAME
DSNNAME = STRIP(DSNNAME)
Y = SYSDSN("'"DSNNAME"'")
IF Y <> 'OK' THEN
DO
SAY 'ENTERED DATASET' DSNNAME 'IS INVALID'
NOP
EXIT
END
USRID = USERID()
DSNNAME = STRIP(DSNNAME)
DS = STRIP(USRID||'.R107YB.REXX.OUTPUT')
MACLIST = N141129.R107YB.REXX.MACLIST
MAC = "'N141129.R107YB.REXX.MACLIST'"
MACLIS = STRIP(MACLIST)
DSN = "'"DSNNAME"'"
DSORG = LISTDSI(DSN)
/* IF SYSDSORG = 'PS' */
PARM1 = ''
DS = STRIP(DS)
SAY 'DS = ' DS
X = SYSDSN("'"DS"'")
SAY 'X = ' X
IF X = 'OK' THEN
DO
ADDRESS TSO
"DELETE '"DS"'"
END
ADDRESS TSO
"ALLOC DA ('"DS"') NEW ",
"LRECL(80) RECFM(F B) ",
"DSORG(PS) SPACE(10,10) TRACKS"
ADDRESS ISPEXEC
"ISREDIT MACRO"
ADDRESS ISPEXEC
"CONTROL ERRORS RETURN"
/*********************************************************************
MEMBER = ' '
LMRC = 0
/**********************************************************/
CALL T0001_LMINIT
CALL T0002_LMOPEN
/***********************************************************/
DO WHILE LMRC = 0
IF SYSDSORG= 'PO' THEN
DO
CALL T0003_LMLIST
END
SELECT
WHEN LMRC = 8 THEN
DO
SAY 'END OF PROCESSING DATASET: ' DSNNAME
EXIT
END
WHEN LMRC = 0 THEN
DO
IF SYSDSORG = 'PS' THEN
CALL T0004_EDITMACRO DSNNAME MACLIST
ELSE NOP
IF SYSDSORG = 'PO' THEN
CALL T0005_LISTMACRO MEMBER MACLIST
ELSE NOP
END
OTHERWISE
DO
SAY 'ERROR IN PROCESSING PDS: ' DSNNAME 'MEMBER :' MEMBER
SAY 'FAILED IN (LMMLIST) MEM LISTING'
CALL T9999_LMENDING
END
END
END
EXIT
/*********************************************************************/
T0001_LMINIT:
ADDRESS ISPEXEC
"LMINIT DATAID("MYDI") DATASET('"DSNNAME"') ENQ(SHR)"
RETURN
/*********************************************************************/
T0002_LMOPEN:
ADDRESS ISPEXEC
"LMOPEN DATAID("MYDI") OPTION(INPUT)"
IF RC = 0
THEN
NOP
/* SAY '*** SUCCESSFULLY OPENED PDS :' DSNNAME '***' */
ELSE
DO
SAY 'PROBLEM IN OPENING DATASET : ' DSNNAME
"LMFREE DATAID("MYDI")"
EXIT
END
LMRC = RC
RETURN
/********************************************************************/
T0003_LMLIST:
ADDRESS ISPEXEC 'LMMLIST DATAID('MYDI') OPTION(LIST),
MEMBER(MEMBER) STATS(NO)'
LMRC = RC
RETURN
/*******************************************************************/
T0004_EDITMACRO:
ARG MBR1 MCFILE
ADDRESS TSO
"ALLOC F(INDD) DA('"STRIP(MCFILE)"') SHR REUSE"
ADDRESS TSO
"EXECIO * DISKR INDD (STEM VAR. FINIS)"
ADDRESS TSO
"FREE F(INDD)"
DO I = 1 TO VAR.0
MACRO('SUBSTR(STRIP(VAR.I),1,8)')'
IF RC = 0 | RC = 4
THEN
DO
LMRC = 8
SAY 'END OF PROCESSING DATASET: ' DSNNAME
END
ELSE
DO
SAY 'PROBLEM IN MACRO :' MCFILE 'MEMBER :'
MEMBER 'RC :' RC
CALL T9999_LMENDING
END
END
RETURN
/*******************************************************************/
T0005_LISTMACRO:
ARG MBRN MCFILE
DISMAC = ''
ADDRESS TSO
"ALLOC F(INDD) DA('"STRIP(MCFILE)"') SHR REUSE"
ADDRESS TSO
"EXECIO * DISKR INDD (STEM VAR. FINIS)"
ADDRESS TSO
"FREE F(INDD)"
DO I = 1 TO VAR.0
/* SAY '*** PROCESSING MEMBER & APPLYING MACRO :' MEMBER */
ADDRESS ISPEXEC 'VIEW DATAID('MYDI') MEMBER('MBRN')
MACRO('SUBSTR(STRIP(VAR.I),1,8)')'
IF RC = 0 | RC = 4 THEN
IF RC = 0 | RC = 4
THEN
DO
/* SAY '*** PROCESSED MEMBER :' MEMBER 'MACRO :' DISMAC ,
'RC :' RC '***'*/
LMRC = 0
END
ELSE
DO
CALL T9999_LMENDING
END
END
RETURN
T9999_LMENDING:
"LMMLIST DATAID("MYDI") OPTION(FREE)"
"LMCLOSE DATAID("MYDI")"
"LMFREE DATAID("MYDI")"
EXIT
RETURN
The CPU Time utilized by Rexx Program is 8 secs whereas for Edit macros it consumes 25 secs. The Rexx program reads the input file sequentially and checks for the blanks,comments and total number of lines whereas Edit macro program uses the filter functions like F all '*' 7 which should be more efficient than sequential processing. Please let me know how this edit macro program fails it's mission.
Joined: 23 Nov 2006 Posts: 19244 Location: Inside the Matrix
Hello,
Quote:
Edit macro program uses the filter functions like F all '*' 7 which should be more efficient than sequential processing.
Only if you limited the number of edit macros to 1. . .
There are multiple full passes of the member in the code that uses the edit macros. The REXX sequential code only accesses each record once (if i read it correctly).
Joined: 23 Nov 2006 Posts: 19244 Location: Inside the Matrix
Hello,
It is both. . .
Invoking ispf services is not cheap (it wasn't designed to be), which is why doing volume processing using rexx/ispf is not permitted many places.
In addition of the expense of invoking the ispf service, the process posted does this multiple times - each requiring processing the entire input data.
ISPF services may be a little slower but should not be significantly slower. Check the program logic. You are allocating, opening writing and closing DD name OUT for each member. That is expensive. You can just allocate it once in the caller, don't use (FINIS in the macro and close it in the caller. There are probably other optimizations you can do also. Any call to ALLOC, LISTDSI, SYSDSN or open/close(as in EXECIO..(FINIS ) is going to be expensive so do them only when you have to. There is also lots of unnecessary Rexx processing like MACRO('SUBSTR(STRIP(VAR.I),1,8)')' where "MACRO('var.i') would suffice. It looks like you are doing lots and lots of extra I/O and catalog searches. Reexamine the algorithm.