/* REXX VSPACE computes %-used from LISTCSUM output and recommends primary space allocation if different. Written by Frank Clarke 20070619 Impact Analysis . SYSEXEC TRAPOUT . ISPLLIB SYSPMON Modification History 20070723 fxc handle "not found"; 20070731 fxc report over-allocated; 20090309 fxc monitor with SYSPMON; */ arg argline address TSO /* REXXSKEL ver.20040227 */ arg parms "((" opts signal on syntax signal on novalue call TOOLKIT_INIT /* conventional start-up -*/ rc = Trace("O"); rc = Trace(tv) info = parms /* to enable parsing */ call A_INIT /* -*/ call B_LISTCAT /* -*/ if \sw.0error_found then, call C_COMPUTE /* -*/ if \sw.nested then call DUMP_QUEUE /* -*/ exit /*@ VSPACE */ /* Initialization . ----------------------------------------------------------------- */ A_INIT: /*@ */ if branch then call BRANCH address TSO call AA_SETUP_LOG /* */ call AK_KEYWDS /* parse parms -*/ parse value "0" with , chunktot data. dsn , chunk chunklist minsize msg. = "??" /* */ msg.0000 = "OK" /* exists */ msg.0005 = "NC" /* not catalogued */ msg.0009 = "MI" /* migrated */ if sw.0UseFile = 0 then, /* not a LIST */ parse var info dsn info monparm = "/USER" Userid() "TOOL" exec_name if tv = "O" then, "CALL 'NTIN.TS.D822.LIB.ISPLLIB(SYSPMON)'" "'" monparm"'" return /*@ A_INIT */ /* . ----------------------------------------------------------------- */ AA_SETUP_LOG: /*@ */ if branch then call BRANCH address TSO parse value "0" with, log# log. parse value Date("S") Time("S") Time("N") with, yyyymmdd sssss hhmmss . parse var yyyymmdd 4 yrdigit 5 mm 7 dd /* 9 12 14 maybe */ if Pos(yrdigit,"13579") > 0 then mm = mm + 12 /* mm=24 */ logtag = Substr("ABCDEFGHIJKLMNOPQRSTUVWX",mm,1) /* logtag=X */ subid = logtag""dd""Right(sssss,5,0) /* X1423722 ? */ vb4k.0 = "NEW CATALOG UNIT(SYSDA) SPACE(1 5) TRACKS", "RECFM(V B) LRECL(4096) BLKSIZE(0)" vb4k.1 = "SHR" /* if it already exists... */ logdsn = "@@LOG."exec_name"."subid".#CILIST" call ZL_LOGMSG(exec_name "started by" Userid() yyyymmdd hhmmss) call ZL_LOGMSG("Arg:" argline) return /*@ AA_SETUP_LOG */ /* Parse parms . ----------------------------------------------------------------- */ AK_KEYWDS: /*@ */ if branch then call BRANCH address TSO /* sw.0clear = SWITCH("CLEAR") */ sw.0Terse = SWITCH("TERSE") parse value KEYWD("INCR") "20" with , uplift . dispupl = uplift ldrc = LISTDSI("DSLIST FILE") sw.0UseFile = ldrc = 0 uplift = ( 100 + uplift ) / 100 /* 100+20/100 = 1.2 */ zerrlm = exec_name "("BRANCH("ID")")" , "Using uplift of" uplift call ZL_LOGMSG(zerrlm) return /*@ AK_KEYWDS */ /* Get catalog information . ----------------------------------------------------------------- */ B_LISTCAT: /*@ */ if branch then call BRANCH address TSO if sw.0Terse then do say, Left( " ",52 ) "Primary Current Recommended" say, Left( " ",52 ) " (uplift" dispupl"%)" end if sw.0UseFile then do /* it's a list of names */ call D_DO_LIST /* -*/ sw.0error_found = 1 return /* we're done */ end /* sw.0UseFile */ call BL_LOAD_STACK /* -*/ return /*@ B_LISTCAT */ /* Run LISTCSUM; load data strings from stack . ----------------------------------------------------------------- */ BL_LOAD_STACK: /*@ */ if branch then call BRANCH address TSO if Left( dsn,1 ) <> "'" then, /* unquoted */ dsn = "'"Strip( dsn )"'" zerrlm = exec_name "("BRANCH("ID")")" , "Processing DSN" dsn call ZL_LOGMSG(zerrlm) data. = "" /* purge any existing */ "NEWSTACK" "LISTCSUM" dsn "STACK" do queued() parse pull id ":" data.id end "DELSTACK" return /*@ BL_LOAD_STACK */ /* Manipulate SPACE information to produce a report . ----------------------------------------------------------------- */ C_COMPUTE: /*@ */ if branch then call BRANCH address TSO numeric digits 14 zerrlm = exec_name "("BRANCH("ID")")" , "DATA.dataallocation="data.dataallocation call ZL_LOGMSG(zerrlm) if data.dataallocation = "" then do call CL_LISTDSI /* -*/ return end if sw.0clear then "CLEAR" parse value "0" with chunktot chunklist dataassoc = Strip( data.dataassociations ) if sw.0Terse = 0 then, say "Information for" dataassoc info = data.dataallocation hiurba = KEYWD("HI U RBA") hiarba = KEYWD("HI A RBA") spacep = KEYWD("SPACE PRI") spacet = KEYWD("SPACE TYPE") fragused = (hiurba / hiarba) * 100 if sw.0Terse = 0 then, say "HI-U-RBA" hiurba , " HI-A-RBA" hiarba " " Format( fragused,3,2 )"%" if spacet = "CYLINDER" then facs = "15 c c"; else facs = "1 t t" parse var facs factor typinit typinitr . info = data.datavolume zerrlm = exec_name "("BRANCH("ID")")" , "DATA.datavolume="info call ZL_LOGMSG(zerrlm) do until chunk = "" chunk = KEYWD("TRACKS") if chunk <> "" then do chunklist = chunklist chunk chunktot = chunktot + chunk end end parse value "0 0" with, sw.0Small sw.0TooBig if chunktot > 0 then do if sw.0Terse = 0 then, say "Total tracks:" chunktot "in" Words(chunklist), "fragments" if chunktot > (spacep*factor) then do if sw.0Terse = 0 then, say "This is larger than the PRIMARY allocation of", spacet spacep minsize = Format( (chunktot/factor) * uplift , 6,0 ) + 0 if sw.0Terse = 0 then, say "Increase to at least" spacet minsize sw.0Small = 1 end else if fragused < 7.1 then do sw.0TooBig = 1 sw.0Footnote = 1 minsize = Format(( chunktot * hiurba / hiarba ) , 6,0 ) + 0 typinitr = "t *" end if sw.0Terse = 0 & sw.0Small = 0 then, say "PRIMARY allocation is", spacep spacet end if chunktot%factor <> chunktot/factor then, chunkadj = chunktot%factor + 1 else, chunkadj = chunktot%factor if sw.0Small | sw.0TooBig then, if sw.0Terse then say , Left( dataassoc,52 ) Right( spacep,5 )typinit, Right( chunkadj,7 )typinit, Right( minsize,9 )typinitr return /*@ C_COMPUTE */ /* It's non-VSAM; use LISTDSI to acquire info . ----------------------------------------------------------------- */ CL_LISTDSI: /*@ */ if branch then call BRANCH address TSO s. = "" if Left( dsn,1 ) <> "'" then, /* unquoted */ dsn = "'"Strip( dsn )"'" ldrc = LISTDSI(dsn "DIRECTORY NORECALL") if ldrc > 4 then do say dsn "not found" sw.0error_found = 1 return end if sw.0Terse then return /* no report for non-VSAM */ s.dset = SYSDSNAME s.alloc = SYSALLOC s.used = SYSUSED s.pri = SYSPRIMARY s.sec = SYSSECONDS s.unit = SYSUNITS s.ext = SYSEXTENTS dsstat = msg.sysreason s.m1 = SYSMSGLVL1 s.m2 = SYSMSGLVL2 if s.ext > 1 then extsuff = "s" else extsuff = ""; say "Dataset" s.dset "is allocated in" s.unit"s." if s.used = "N/A" then, say "It is a LIBRARY with a total of" s.alloc, "allocated" s.unit"s and is in" s.ext, "extent"extsuff"." else, say "It is currently using" s.used "of" s.alloc, "allocated" s.unit"s and is in" s.ext, "extent"extsuff"." return /*@ CL_LISTDSI */ /* Input is a list of DSNs; process each . ----------------------------------------------------------------- */ D_DO_LIST: /*@ */ if branch then call BRANCH address TSO dsl. = "" "EXECIO * DISKR DSLIST ( STEM DSL. FINIS" zerrlm = exec_name "("BRANCH("ID")")" , "FILE DSLIST held" dsl.0 "lines." do dx = 1 to dsl.0 dsn = dsl.dx /* unquoted */ call BL_LOAD_STACK /* -*/ call C_COMPUTE /* -*/ if sw.0Terse = 0 then, say " " end /* queued */ if sw.0Footnote & sw.0Terse then do say say "( * = over-allocated, uplift not applied )" end return /*@ D_DO_LIST */ /* . ----------------------------------------------------------------- */ LOCAL_PREINIT: /*@ customize opts */ address TSO return /*@ LOCAL_PREINIT */ /* subroutines below LOCAL_PREINIT are not selected by SHOWFLOW */ /* . ----------------------------------------------------------------- */ ZB_SAVELOG: /*@ */ if branch then call BRANCH address TSO if Symbol("LOG#") = "LIT" then return /* not yet set */ "ALLOC FI($LOG) DA("logdsn") REU" vb4k.0 "EXECIO" log# "DISKW $LOG (STEM LOG. FINIS" "FREE FI($LOG)" return /*@ ZB_SAVELOG */ /* . ----------------------------------------------------------------- */ ZL_LOGMSG: Procedure expose, /*@ */ (tk_globalvars) log. log# rc = Trace("O") address TSO parse arg msgtext parse value log#+1 msgtext with, zz log.zz 1 log# . if monitor then say, msgtext return /*@ ZL_LOGMSG */ /* . ----------------------------------------------------------------- */ HELP: /*@ */ address TSO;"CLEAR" ; say "" if helpmsg <> "" then do ; say helpmsg; say ""; end ex_nam = Left(exec_name,8) /* predictable size */ say " "ex_nam" computes %-used from LISTCSUM output and recommends " say " primary space allocation if different. Both VSAM and " say " non-VSAM datasets can be processed unless TERSE is " say " specified. " say " " say " " say " Syntax: "ex_nam" (Optional)" say " " say " " say " " say " dsn names the dataset entry to be analyzed. If it is a " say " non-data entry, the associated data part will be " say " analyzed. If FILE DSLIST is provided, is " say " ignored in favor of DSLIST's fully-qualified " say " unquoted DSNs. " say " " say " TERSE produces a report only for those VSAM clusters which" say " are candidates for expansion. " say " " say " uplift specifies a percentage value to be used in " say " calculating the recommended primary allocation. If " say " not specified, it defaults to '20'. " say " " "NEWSTACK"; pull ; "CLEAR" ; "DELSTACK" say " Debugging tools provided include: " say " " say " BRANCH: show all paragraph entries. " say " " say " TRACE tv: will use value following TRACE to place the " say " execution in REXX TRACE Mode. " say " " say " " say " Debugging tools can be accessed in the following manner: " say " " say " TSO "ex_nam" parameters (( debug-options " say " " say " For example: " say " " say " TSO "ex_nam" (( TRACE ?R " if sw.inispf then, address ISPEXEC "CONTROL DISPLAY REFRESH" exit /*@ HELP */ /* . ----------------------------------------------------------------- */ BRANCH: Procedure expose, /*@ */ sigl exec_name rc = trace("O") /* we do not want to see this */ arg brparm . origin = sigl /* where was I called from ? */ do currln = origin to 1 by -1 /* inch backward to label */ if Right(Word(Sourceline(currln),1),1) = ":" then do parse value sourceline(currln) with pgfname ":" . /* Label */ leave ; end /* name */ end /* currln */ select when brparm = "NAME" then return(pgfname) /* Return full name */ when brparm = "ID" then do /* wants the prefix */ parse var pgfname pgfpref "_" . /* get the prefix */ return(pgfpref) end /* brparm = "ID" */ otherwise say left(sigl,6) left(pgfname,40) exec_name "Time:" time("L") end /* select */ return /*@ BRANCH */ /* . ----------------------------------------------------------------- */ DUMP_QUEUE: /*@ Take whatever is in stack */ rc = trace("O") /* and write to the screen */ address TSO arg mode . "QSTACK" /* how many stacks? */ stk2dump = rc - tk_init_stacks /* remaining stacks */ if stk2dump = 0 & queued() = 0 then return if mode <> "QUIET" then, say "Total Stacks" rc , /* rc = #of stacks */ " Begin Stacks" tk_init_stacks , /* Stacks present at start */ " Excess Stacks to dump" stk2dump do dd = rc to tk_init_stacks by -1 /* empty each one. */ if mode <> "QUIET" then, say "Processing Stack #" dd " Total Lines:" queued() do queued();parse pull line;say line;end /* pump to the screen */ "DELSTACK" /* remove stack */ end /* dd = 1 to rc */ return /*@ DUMP_QUEUE */ /* Handle CLIST-form keywords added 20020513 . ----------------------------------------------------------------- */ CLKWD: Procedure expose info /*@ hide all except info */ arg kw kw = kw"(" /* form is 'KEY(DATA)' */ kw_pos = Pos(kw,info) /* find where it is, maybe */ if kw_pos = 0 then return "" /* send back a null, not found*/ rtpt = Pos(") ",info" ",kw_pos) /* locate end-paren */ slug = Substr(info,kw_pos,rtpt-kw_pos+1) /* isolate */ info = Delstr(info,kw_pos,rtpt-kw_pos+1) /* excise */ parse var slug (kw) slug /* drop kw */ slug = Reverse(Substr(Reverse(Strip(slug)),2)) return slug /*@CLKWD */ /* Handle multi-word keys 20020513 . ----------------------------------------------------------------- */ KEYWD: Procedure expose info /*@ hide all vars, except info*/ arg kw /* form is 'KEY DATA' */ kw_pos = wordpos(kw,info) /* find where it is, maybe */ if kw_pos = 0 then return "" /* send back a null, not found*/ kw_val = word(info,kw_pos+Words(kw))/* get the next word */ info = Delword(info,kw_pos,2) /* remove both */ return kw_val /*@ KEYWD */ /* . ----------------------------------------------------------------- */ KEYPHRS: Procedure expose, /*@ */ info helpmsg exec_name /* except these three */ arg kp /* form is 'KEY ;: DATA ;:' */ wp = wordpos(kp,info) /* where is it? */ if wp = 0 then return "" /* not found */ front = subword(info,1,wp-1) /* everything before kp */ back = subword(info,wp+1) /* everything after kp */ parse var back dlm back /* 1st token must be 2 bytes */ if length(dlm) <> 2 then /* Must be two bytes */ helpmsg = helpmsg "Invalid length for delimiter("dlm") with KEYPHRS("kp")" if wordpos(dlm,back) = 0 then /* search for ending delimiter*/ helpmsg = helpmsg "No matching second delimiter("dlm") with KEYPHRS("kp")" if helpmsg <> "" then call HELP /* Something is wrong */ parse var back kpval (dlm) back /* get everything b/w delim */ info = front back /* restore remainder */ return Strip(kpval) /*@ KEYPHRS */ /* . ----------------------------------------------------------------- */ NOVALUE: /*@ */ say exec_name "raised NOVALUE at line" sigl say " " say "The referenced variable is" condition("D") say " " zsigl = sigl signal SHOW_SOURCE /*@ NOVALUE */ /* . ----------------------------------------------------------------- */ SHOW_SOURCE: /*@ */ call DUMP_QUEUE /* Spill contents of stacks -*/ if sourceline() <> "0" then /* to screen */ say sourceline(zsigl) rc = trace("?R") nop exit /*@ SHOW_SOURCE */ /* . ----------------------------------------------------------------- */ SS: Procedure /*@ Show Source */ arg ssbeg ssct . /* 'call ss 122 6' maybe */ if ssct = "" then ssct = 10 if \datatype(ssbeg,"W") | \datatype(ssct,"W") then return ssend = ssbeg + ssct do ssii = ssbeg to ssend ; say Strip(sourceline(ssii),'T') ; end return /*@ SS */ /* . ----------------------------------------------------------------- */ SWITCH: Procedure expose info /*@ */ arg kw /* form is 'KEY' */ sw_val = Wordpos(kw,info) > 0 /* exists = 1; not found = 0 */ if sw_val then /* exists */ info = Delword(info,Wordpos(kw,info),1) /* remove it */ return sw_val /*@ SWITCH */ /* . ----------------------------------------------------------------- */ SYNTAX: /*@ */ errormsg = exec_name "encountered REXX error" rc "in line" sigl":", errortext(rc) say errormsg zsigl = sigl signal SHOW_SOURCE /*@ SYNTAX */ /* Can call TRAPOUT. . ----------------------------------------------------------------- */ TOOLKIT_INIT: /*@ */ address TSO info = Strip(opts,"T",")") /* clip trailing paren */ parse source sys_id how_invokt exec_name DD_nm DS_nm, as_invokt cmd_env addr_spc usr_tokn parse value "" with tv helpmsg . parse value 0 "ISR00000 YES" "Error-Press PF1" with, sw. zerrhm zerralrm zerrsm if SWITCH("TRAPOUT") then do "TRAPOUT" exec_name parms "(( TRACE R" info exit end /* trapout */ sw.nested = sysvar("SYSNEST") = "YES" sw.batch = sysvar("SYSENV") = "BACK" sw.inispf = sysvar("SYSISPF") = "ACTIVE" if Word(parms,1) = "?" then call HELP /* I won't be back */ "QSTACK" ; tk_init_stacks = rc /* How many stacks? */ parse value SWITCH("BRANCH") SWITCH("MONITOR") SWITCH("NOUPDT") with, branch monitor noupdt . parse value mvsvar("SYSNAME") sysvar("SYSNODE") with, #tk_cpu node . parse value KEYWD("TRACE") "O" with tv . tk_globalvars = "exec_name tv helpmsg sw. zerrhm zerralrm ", "zerrsm zerrlm tk_init_stacks branch monitor ", "noupdt" call LOCAL_PREINIT /* for more opts -*/ return /*@ TOOLKIT_INIT */