/********************************************************************** * AUTOSMSH NetView Automation Table Usage Analysis Tool * * * * (C) COPYRIGHT IBM CORP. 1993 * * This NetView command list is provided "AS-IS" with no * * warranty provided of any kind. Use at your own risk. * * * * This command list uses output generated using the NetView * * AUTOCNT command, which is new with NetView V2R4, so NetView * * V2R4 is required to use AUTOSMSH. * * * * Author: Nate Gaffaney IBM Corp. * * IBM VNET: NJGAFFAN at RALVM14 * * IBMMAIL : USIB2DMG at IBMMAIL * * INTERNET: njgaffan@ralvm14.vnet.ibm.com * * * * Suggestions for improvements are welcome! * * * * ------------------------------------------------------------------ * * * * Combines a NetView Automation Table Usage Report and a NetView * * Automation Table Listing to make one readable report. * * The combined report can make it easier to spot statements that * * are misplaced (causing unnecessary CPU usage) and automation * * table statement coding errors. * * * * INPUT: usage_file listing_file output_file * * (all files must be in dataset(member) format) * * * * OUTPUT: A combined usage report showing the automation statements * * from the automation table listing combined with the * * comparison counts and match counts from the detailed * * automation table usage report will be generated and * * written to the member specified. For reports where the * * SORT option is NOT specified, possible problem areas * * identified by the usage report statistics (such as a * * statement that never gets compared, or always matches but * * isn't an ALWAYS automation statement) will be indicated in * * the combined output. * * * * The combined report can be used to more easily match up * * the usage report statistics with the source automation * * statements. The automation table statement number found * * in both the usage report and the listing provides the * * determination of which records in the usage report * * match up' with which statements in the listing. * * * * For sorted reports, only the first record in the automation* * table listing corresponding to each statement will be * * shown in the combined, sorted report. For non-sorted * * reports (the default), all comments and all records from * * the automation table (via the listing) will be shown. * * * * If the optional SORT parameter is specified, the combined * * report will be sorted in descending order of matches. * * In order to ensure statement match counts are being * * compared against each other correctly, you should note in * * the actual statement source data from the listing * * whether: * * - the statement is a BEGIN statement * * - the statement is a "generic" statement * * (such as "IF MSGID = 'DSI' . THEN...") * * - the statement is an ALWAYS * * All of the above types of statements could have a large * * number of matches as compared to statements that are * * meant to match on one particular message, for example. * * Having a high match rate on these types of statements * * does not necessarily mean the statement needs reordering * * in the automation table. Use caution when reordering * * statements in the table - moving statements could alter * * the logical order in which statements are matched, causing * * unintended matches on automation table statements. * * * * Example of execution: * * - Prior to calling this command list, an automation * * table usage report needs to be generated to a file. * * You must specify STATS=DETAIL on the command. * * For example, * * * * AUTOCNT REPORT=BOTH,STATS=DETAIL,FILE=U1 * * * * will create a usage report called U1 on the first * * dataset defined in the NetView DSILIST DD. So, if the * * first dataset in DSILIST is USER.INIT, you would * * specify the usage report input file to this command * * list as: * * * * USER.INIT(U1) * * * * - Prior to calling this command list, an automation * * table listing needs to be generated. * * For example, * * * * AUTOTBL MEMBER=DSITBL01,LISTING=L1 * * * * will create a listing member called L1 on the first * * dataset defined in the NetView DSILIST DD. So, if the * * first dataset in DSILIST is USER.INIT, you would * * specify the listing input file to this command list * * as: * * * * USER.INIT(L1) * * * * Note: To ensure the validity of the combined report, * * it is best if the listing is generated when the * * current active automation table was activated * * using the AUTOTBL command. This will ensure * * that the listing and usage report were generated * * from the same automation table so that any * * changes to the source automation table members * * after the automation table was activated will * * not be reflected in the listing member. * * * * - Decide what dataset and member you would like the * * combined report written to, for example, you might * * select: * * * * USER.INIT(O1) * * * * - Once the automation table listing input member, the * * automation table usage report input member, and the * * combined report output member have been determined, * * this command list can be executed to generate a * * combined automation table report. For example: * * * * AUTOSMSH USER.INIT(U1) USER.INIT(L1) USER.INIT(R1) SORT * * * * Change Activity: * * July 1993 Nate Gaffaney IBM Corp. - Created command list * * 27 Sept 1993 Nate Gaffaney - Added more error * * checking/handling * * * **********************************************************************/ signal on halt /* Verify input parameters */ parse upper arg usage_file listing_file output_file sort if usage_file = '' | listing_file = '' | output_file = '' then do say 'Required parameter missing....must provide three member names' exit 99 end if sort ^= '' & sort ^= 'SORT' then do say 'If specified, the fourth parameter must be SORT' exit 99 end /* read data from usage file */ 'TRAP AND SUPPRESS MESSAGES CNM272I' 'ALLOCATE F('USAGEFLE') DA('USAGE_FILE') SHR FREE' if rc ^= 0 then do say 'AUTOSMSH: Allocate of usage report failed' exit 99 end 'TRAP NO MESSAGES' 'FLUSHQ' ADDRESS MVS 'EXECIO * DISKR ' USAGEFLE '(STEM USAGE. FINIS' if rc ^= 0 then do say 'AUTOSMSH: EXECIO failure' 'FREE F('USAGEFLE')' exit 99 end /* read data from listing file */ 'TRAP AND SUPPRESS MESSAGES CNM272I' 'ALLOCATE F('LSTNGFLE') DA('LISTING_FILE') SHR FREE' if rc ^= 0 then do say 'AUTOSMSH: Allocate of listing file failed' exit 99 end 'TRAP NO MESSAGES' 'FLUSHQ' ADDRESS MVS 'EXECIO * DISKR ' LSTNGFLE '(STEM LSTNG. FINIS' if rc ^= 0 then do say 'AUTOSMSH: EXECIO failure' 'FREE F('USAGEFLE')' 'FREE F('LSTNGFLE')' exit 99 end /* verify that usage report file and listing file match */ /* - grab time statistics started from usage report */ do i = 1 to usage.0 until word(usage.i,1) = 'DWO812I' end parse var usage.i stuff '=' usage_time /* - grab time listing generated from listing */ do i = 1 to lstng.0 until word(lstng.i,1) = 'Executed' end parse var lstng.i 'Executed by' opid lstng_time /* - issue warning if not the same */ if usage_time ^= lstng_time then do say 'WARNING - Usage Report time statistics started and Listing' say ' time generated are not the same...possible' say ' mismatch in automation tables.' end /* Set up output file for receiving data */ filename = OPID() 'TRAP AND SUPPRESS MESSAGES CNM272I' 'ALLOCATE F('FILENAME') DA('OUTPUT_FILE') SHR FREE' if rc ^= 0 then do say 'AUTOSMSH: Allocate of output file failed' exit 99 end 'TRAP NO MESSAGES' 'FLUSHQ' RECORD = 'Combined automation table report generated '||DATE() TIME() CALL WRITEREC CALL WRITEREC record = 'Listing input file generated 'strip(lstng_time,'L') CALL WRITEREC record = ' (member = 'listing_file')' CALL WRITEREC record = 'Usage data started 'usage_time CALL WRITEREC record = ' (member = 'usage_file')' CALL WRITEREC CALL WRITEREC CALL WRITEREC /* Grab header records for use later in SORTed report - about to be erased... */ do i = 1 to usage.0 if word(usage.i,1) = 'DWO806I' then dwo806msg = usage.i if word(usage.i,1) = 'DWO807I' then dwo807msg = usage.i end /* Erase non-DETAILED data from usage stem variables */ do i = 1 to usage.0 if word(usage.i,1) ^= 'DWO809I' then usage.i = '' end /* Calculate average number of matches per statement */ totmatch = 0 numstat = 0 do i = 1 to usage.0 if substr(usage.i,43,8) ^= '' then do totmatch = totmatch + strip(substr(usage.i,43,8)) numstat = numstat + 1 end end record = 'Average matches per statement = ' totmatch/numstat call writerec call writerec /* If sort not specified... */ if sort = '' then do /* step through listing line by line and write it out to output file. When a line of the listing is read that has a statement number on it (4 digit number as first word)...write that out and then go look in usage report for 1 or 2 matching entries. (and then write the usage entry or entries out too). */ do lst = 1 to lstng.0 record = lstng.lst call writerec /* is it a listing record with a statement number? */ if length(word(lstng.lst,1)) = 4 & , DATATYPE(word(lstng.lst,1),W) = '1' then do /* try to find usage record(s) that match it */ do usg = 1 to usage.0 if word(usage.usg,2) = word(lstng.lst,1) then do record = ' Compared count = 'substr(usage.usg,34,8) , ' Match count = 'substr(usage.usg,43,8) call writerec /* Check to see if the sequence numbers match */ if substr(usage.usg,16,8) ^= substr(lstng.lst,73,8) then do record = ' WARNING - Seq. number mismatch.' call writerec record = ' LISTING does not match the USAGE!!!' call writerec end /* Check to see if it was never compared */ if substr(usage.usg,34,8) = ' 0' then do record = ' Note: This statement was never compared.' call writerec record = ' Another statement may be blocking it' call writerec end /* Check to see if it was never matched */ if substr(usage.usg,34,8) ^= ' 0' & , substr(usage.usg,43,8) = ' 0' then do record = ' Note: This statement was never matched.' call writerec record = ' This may be a dead statement or' call writerec record = ' there could be a coding error' call writerec end /* Check to see if it always matches */ if substr(usage.usg,34,8) = substr(usage.usg,43,8) & , substr(usage.usg,34,8) ^= ' 0' & , substr(usage.usg,59,1) ^= 'X' then do record = ' Note: This statement always matched.' call writerec record = ' There could be a coding error.' call writerec end end end end end end else /* SORT must have been specified */ do /* sort usage report records. Write the sorted records out one at a time, then go look in listing report records for a statement with a matching statement number, and write that out too. */ /* sort the usage records */ /* this is done using a crude 'bubble sort' ... */ /* first, write out header messages */ record = substr(dwo806msg,9) call writerec record = substr(dwo807msg,9) call writerec done = 'NO' /* do the entire sort until gone through and nothing "bubbled" */ do i = 1 to usage.0 while done = 'NO' done = 'YES' /* do one pass through the records */ do j = 1 to usage.0 if usage.j ^= '' then do k = j + 1 if j = usage.0 then /* if at bottom, do nothing */ nop else if substr(usage.k,43,8) > substr(usage.j,43,8) then do /* need to "bubble" */ done = 'NO' temp = usage.j usage.j = usage.k usage.k = temp end end end end /* usage records are sorted....now write them all out */ do i = 1 to usage.0 /* some of them are null because we wiped out all non-DWO809I's */ if usage.i = '' then nop else do /* Write out the usage report record */ record = substr(usage.i,9) call writerec stmt_num = word(usage.i,2) /* Find the matching record in the Listing file */ found_lst = 'NO' do lst = 1 to lstng.0 while found_lst = 'NO' if word(lstng.lst,1) = stmt_num then do /* Found the match - write it out */ found_lst = 'YES' record = lstng.lst call writerec end end end end end say 'Combined automation table report generation complete.' /* write a line to the output file */ writerec: RECORD.1 = RECORD ADDRESS MVS 'EXECIO 1 DISKW ' FILENAME '(STEM RECORD.' if rc > 2 then do say 'AUTOSMSH: EXECIO failure. Return Code = 'rc address mvs 'EXECIO 0 DISKW ' filename '(STEM RECORD. FINIS' 'FREE F('USAGEFLE')' 'FREE F('LSTNGFLE')' 'FREE F('FILENAME')' exit 99 end RECORD = '' return /* Handle EXECIO failures that will terminate the command list */ HALT: address mvs 'EXECIO 0 DISKW ' filename '(STEM RECORD. FINIS' 'FREE F('USAGEFLE')' 'FREE F('LSTNGFLE')' 'FREE F('FILENAME')' return