?MENU ProductInfo CACHE 1 ------------------------------------------------------------------------------ ASAPDBA --> ASAP DB Analysis & Aggregation utility - T0402v3.3 - (17AUG2012) ------------------------------------------------------------------------------ ASAP DBA administers, analyzes, aggregates, sorts, merges, & loads long-term history from one/many ZMMDD* files into a single compacted DB history file. For more about ASAP ZMMDD files, enter HELP SET DBMaxDays from the ASAP CI. ASAP DBA provides significant data reduction of ASAP long-term DB stats using record-compression, hourly-aggregation, and time-of-day filtering. As a result instead of 1440 records/object/day, only 24 records/object/day or even less are saved in the DB resulting in 200x-5000x improvement in performance. ASAP DBA sorts & merges multi-day DB files into a single historical DB file suitable for long-term analysis. DBA can combine many days of DB files into one long-term DB file allowing long-term analysis. DBA History is saved in the ASAPDB subvol with an "H" suffix. For example, a Cpu or Disk "H"istory file is saved as DBCpuH and DBDskH, along-side your DBCpu and DBDsk files. ASAP DBA: Prompts you for Entity, Date, Time, Days, Hours, and Node options.. ------------------------------------------------------------------------------ ?MENU Prompts {------------ { <#var> {23456789.123456789.123456789.123456789.123456789.123456789.123456789.12345678 {----------------------------------------------------------------------------- <#entity> ASAP DBA can aggregate DB history to a NEW file, or ADD to an existing file. NEW - if you want to create an entirely new file <#dbSV>.DB<#entity>H then enter NEW. The NEW option uses a FUP LOAD operation to create a new DB file and as a result is much faster than an ADD operation. ADD - if you want to add history to an existing file <#dbSV>.DB<#entity>H then enter ADD. The ADD option uses FUP COPY to add to a file and as a result is slower than a NEW operation. For this reason it is recommended you only add 1 day of statistics for an ADD operation. <#DBNewAdd> ASAP DBA can analyze and aggregate multiple-days of database statistics, or it can focus on a single day to perform hourly aggregation. To do either, please specify the oldest starting date you want to aggregate. <#mmstart> <#ddstart> <#days> ASAP DBA can analyze and aggregate either a whole day of statistics, eg from 00:00 for 24 hours, or it can focus on a particular time range you specify, eg 11:00 for 3 hours. Please specify the starting hour of the day you want to analyze and the number of hours you want to aggregate. <#HourFrom> <#Hours> ASAP DBA can select all nodes, or one particular node for analysis and aggregation. Specify either \* or a particular \sysname below. <#nodes> ASAP DBA will analyze & aggregate ZMMDD files in subvol <#hiSV> If you want ASAP DBA to use another subvolume for ZMMDD files, then input the subvol name below, otherwise press the ENTER key. <#hiSV> ASAP DBA will use DICT files and save/update files in subvol <#dbSV> If you want ASAP DBA to use another subvolume for DICT and output files, then input the subvol name below, otherwise press the ENTER key. <#dbSV> ?proc PromptsInput(tid,okDone) {----------------------------- { Prompts, validates, and assigns input using rules in cache "tid" { Format of each Tid cache prompt is: <#InVar> { Where: { ::= prompt string { <#InVar> ::= Var name to store input { ::= Check proc of form CALL PROC(#prompt,#input,ok) { OK=TRUE => means input ok { OK=FALSE=> ckproc displayed error { and we re-prompt with same prompt {---------------------------------------------------------------------- parm tid IN { Taskid of cache containing prompts & rules , okDone:=0 OUT { 0=> input error, should quit, 1=> input good ; var r,c,c2,#prompt, #input, #invar, #ckproc, #z, #zz, err, ok; DO BEGIN #z:=""; read tid cache r:=r+1,#z,err; { read next prompt if err then begin okDone:=1; { no more prompts if trace then msg ""; RETURN; end; #prompt:="?"; { Parse SCAN #z WHILE " " -> c; { scan for "<" THEN BEGIN { Not a Line DO BEGIN SCAN #z UNTIL "<#" ->c; { ck if <#varname> if c THEN BEGIN { <#varname> is present #invar:=#TAKE #z[c+2:132];{ get varname in #invar exe "#zz:=#" & #invar; { #zz := variable value #z:=#z[1:c-1] & #zz & #z[c+#SIZE#invar+3:132]; c:=c+#SIZE#invar+3; end; END UNTIL (c<=0); MSG #z; { Just output the LINE END ELSE BEGIN { <#InVar> SCAN #z[c] UNTIL ">" -> c2; { scan for prompt end> IF NOT c2 THEN BEGIN if trace then msg "' missing>"; RETURN; { missing prompt> END; #z[c]:=" "; #prompt:=#z[1:c2-1]; { set #prompt #invar:=""; { Parse <#InVar> SCAN #z UNTIL "<#" -> c; { scan for <#invar IF NOT c THEN BEGIN if trace then msg ""; RETURN; { no <#invar END; SCAN #z[c] UNTIL ">" -> c2; { scan for #invar> IF NOT c2 THEN BEGIN if trace then msg "' at end of #invar>"; RETURN; { no #invar> END; #invar := #z[c+1:c2-1]; { set #invar name #ckproc:=""; { Parse optional SCAN #z[c2] UNTIL "<" -> c; { scan for "->c2; { scan for ckproc> if c2 then begin { ckproc> #ckproc:= #z[c+1:c2-1]; { set #ckproc #zz:=#PROC #ckproc; { see if proc exists if #zz=""then #ckproc:="";{ no such proc name END; END; DO BEGIN { error check loop PROMPT #prompt &": " { PROMPT #prompt,#input; ,#input , err; if err then begin if trace then msg ""; RETURN; { input err okDone will = 0 end; ok:=1; { assume ok IF #ckproc<>"" THEN { if have ckproc EXE "CALL " & #ckproc { execute call & "(#prompt,#input,ok)"; { ckProc (#prompt,#input,ok) IF ok THEN { Assign #invar:=#input EXE #invar&":='"& #input&"'"; END UNTIL ok; { loop if not ok END;{ END UNTIL 0; ?proc PromptsList(tid) {--------------------- { Lists Prompt values based on rules in cache tid { where cache contins <#InVar> {----------------------------------------------- parm tid; var r,c,c2,#prompt, #input, #invar, #z; do begin #z:=""; read tid cache r:=r+1,#z; { read next prompt scan #z until "<" -> c; { scan for " -> c2; { scan for prompt> if not c2 then return; { no prompt> #prompt:=#z[c+1:c2-1]; { set #prompt scan #z until "<#" -> c; { scan for <#invar if not c then return; { no <#invar scan #z[c] until ">" -> c2; { scan for #invar> if not c2 then return; { no #invar> #invar := #z[c+1:c2-1]; { set #invar exe "#input:=" & #invar; msg #prompt & ": " & #input; end until 0; ?PROC ckAlpha(#prompt,#input,ok) {------------------------------- { Checks that first letter is #alpha { RETURN OK = false if not alpha { RETURN OK = TRUE if it is alpha, upcase it {------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; IF NOT #ALPHA #input THEN BEGIN MSG #prompt & ": << alpha required"; RETURN; {first letter must be alpha END; #input[1] := #UPCASE #input[1]; ok := 1; ?PROC ckDays(#prompt,#input,ok) {-------------------------------- { Checks that #s is all #numeric { RETURN OK = false if not numeric and dashes { RETURN OK = true if it is numeric {------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; VAR i:=0,DaysFor; IF #input="" THEN BEGIN #input:=#days; MSG #prompt & ": " & #input; ok:=1; RETURN; END; { default is 1 day FOR #SIZE #input DO BEGIN i:=i+1; IF (NOT (#NUMERIC #input[i])) AND (#input[i]<>"-") THEN BEGIN MSG #prompt & ": <<< numeric required"; RETURN; END; END; IF (I>3) THEN BEGIN MSG #prompt & ": days too long"; return; END; DaysFor:=#input; IF(DaysFor<1)or(DaysFor>366) THEN BEGIN MSG #prompt & ": <<< Expect value from 1..366"; RETURN; END; ok := 1; ?PROC ckdd(#prompt,#input,ok) {---------------------------- { Checks that #s is all #numeric and less than or =31 { RETURN OK = false if not numeric and dashes { RETURN OK = true if it is numeric {------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; { 123456789.123 VAR i:=0,mm,dd; IF #input="" THEN BEGIN { default use yesterday's DB file mm:=#mmstart; { start month dd:=#ddstart; { start day #input:=dd; msg #prompt & ": " & #input; ok:=1; RETURN; END; FOR #SIZE #input DO BEGIN i:=i+1; IF (NOT (#NUMERIC #input[i])) THEN BEGIN MSG #prompt & ": <<< numeric required"; RETURN; END; END; IF (i>2) THEN BEGIN MSG #prompt & ": <<< Day of month too long"; RETURN; END; dd:=#input; IF (dd>31) THEN BEGIN MSG #prompt & ": <<< Day of month too large"; RETURN; END; ok := 1; ?PROC DateBefore(#mmIn,#ddIn,#mmOut,#ddOut) {------------------------------------------ { Determines the Date one day before the date passed in mmIN/ddIN. { Values of the date before mmIN/ddIN are returned in parms mm/dd. {----------------------------------------------------------------- PARM #mmIn IN ,#ddIn IN ,#mmOut OUT ,#ddOut OUT ; VAR i,mm,dd,yy:=2000+#date[1:2]; mm:=#mmIN; dd:=#ddIN; if mm=1 and dd=1 then begin { Date - January 1 yy := yy - 1; { Prior year #hiSV := "ASAP" & yy; { ASAPyyyy of prior year mm := 12; { December dd := 31; { 31 end else begin { Not January 1 i:=(mm-2)*3+1; { i is index for last month computation if dd>1 then begin { Not the first of the month dd := dd-1; { Day Before is #ddIn minus one, month same end else begin { First of the month, but not January dd := #DaysMonth[i:(i+2)]; { Get last day of prior month mm := mm-1; { Month before is #mmIn minus one end; end; #mmOut:=mm; #ddOut:=dd; ?PROC ckmm(#prompt,#input,ok) {---------------------------- { Checks that #s is all #numeric and less than or =12 { RETURN OK = false if not numeric and dashes { RETURN OK = true if it is numeric {------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; VAR i:=0,mm,dd; IF #input="" THEN BEGIN { default use yesterday's DB file mm:=#mmstart; { current month dd:=#ddstart; { current day if (dd=1) and (mm=1)then begin msg #prompt & ": must specify date on Jan 1";return;end; i:=(mm-2)*3+1; { compute number of days last month if dd>1 then begin { not the first of the month dd:=dd-1; { use day minus one #ddstart := dd; end else begin { First of the month dd:=#DaysMonth[i:(i+2)]; { use last day of prior month mm:=mm-1; #ddstart := dd; { Set default start day to yesterday end; #input:=mm; msg #prompt & ": " & #input; ok:=1; RETURN; END; FOR #SIZE #input DO BEGIN i:=i+1; IF (NOT (#NUMERIC #input[i])) THEN BEGIN MSG #prompt & ": <<< numeric required"; RETURN; END; END; IF (i>2) THEN BEGIN MSG #prompt & ": <<< Month too long"; RETURN; END; mm:=#input; IF (mm>12) THEN BEGIN MSG #prompt & ": <<< Month too large"; RETURN; END; ok := 1; ?PROC ckHour(#prompt,#input,ok) {-------------------------------- { Checks that #input is all #numeric and from 00 to 24 { RETURN OK = false if not numeric and within range { RETURN OK = true if it is numeric and in range {----------------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; VAR i:=0, hh, len; if #SIZE #input<=0 then begin { default is 8:00 am #input:="09"; msg #prompt & ": " & #input; ok:=1; return; end; FOR #SIZE #input DO BEGIN i:=i+1; IF (NOT (#NUMERIC #input[i])) THEN BEGIN MSG #prompt & ": <<< Expect HH from 0 to 23"; RETURN; END; END; hh:=#input; if (hh<0) or (hh>23) then begin msg #prompt & ": <<< Expect HH from 0 to 23"; return; end; if hh<10 then #input:="0" & #input; #HourFrom:=#input; #Hours := 24-hh; {default Hours ok := 1; ?PROC ckHours(#prompt,#input,ok) {-------------------------------- { Checks that #input is all #numeric and from 1 to 24 { RETURN OK = false if not numeric and within range { RETURN OK = true if it is numeric and in range {----------------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; VAR i:=0, hh, hrs, len; hh:=#HourFrom; if #SIZE #input<=0 then begin #input:=8; { Default hours #HourUntil:=hh+#input; msg #prompt & ": " & #input; ok:=1; return; end; FOR #SIZE #input DO BEGIN i:=i+1; IF (NOT (#NUMERIC #input[i])) THEN BEGIN MSG #prompt & ": <<< Expect numeric Hours 1 to 24"; RETURN; END; END; hrs:=#input; if (hrs<1) or (hrs>24) then begin msg #prompt & ": <<< Expect Hours from 1 to 24"; return; end; if hrs>(24-hh) then hrs:=(24-hh); #input := hrs; #HourUntil:= hh + hrs; if #SIZE#HourUntil=1 then #HourUntil:="0" & #HourUntil; ok := 1; ?PROC ckNewAdd(#prompt,#input,ok) {-------------------------------- { Checks that #input is NEW/ADD token { RETURN OK = false if not NEW/ADD { RETURN OK = TRUE if it is NEW/ADD {-------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; VAR i, #opts:="=NEW. =ADD."; IF #input="" THEN BEGIN #input := "NEW"; msg #prompt & ": " & #input; ok:=1; RETURN; END; #input := #UPCASE #input; SCAN #opts until "=" & #input & "."->i; IF (i<=0) THEN BEGIN MSG #prompt & ": <<< 'NEW' or 'ADD' required"; RETURN; END; ok := 1; ?PROC ckNumber(#prompt,#input,ok) {-------------------------------- { Checks that #s is all #numeric and/or "-" { RETURN OK = false if not numeric and dashes { RETURN OK = true if it is numeric {------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; VAR i:=0; if #SIZE #input<=0 then return; FOR #SIZE #input DO BEGIN i:=i+1; IF (NOT (#NUMERIC #input[i])) AND (#input[i]<>"-") THEN BEGIN MSG #prompt & ": <<< numeric required"; RETURN; END; END; ok := 1; ?PROC ckNodes(#prompt,#input,ok) {-------------------------------- { Checks that #input is \* or \sysname { RETURN OK = false if not correct node name { RETURN OK = TRUE if \* or \sysname {-------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; VAR i, #s, AlphaName; IF (#input="\*") THEN BEGIN OK:=1; RETURN; END; IF (#input="") THEN BEGIN #input := "\*"; msg #prompt & ": " & #input; ok:=1; RETURN; END; #input:=#upcase#input; #s:=#TAKE #input[2:132]; { get token just past \... i:=#SIZE #s; AlphaName:=#ALPHA #s; IF (i>7) or (NOT AlphaName) THEN BEGIN MSG #prompt & ": <<< \SYSNAME invalid"; RETURN; END; ok := 1; ?PROC ckEntity(#prompt,#input,ok) {-------------------------------- { Checks that #input is an entity name { RETURN OK = false if not entity name { RETURN OK = TRUE if it is entity, upcase it {-------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; VAR i, #entities:="=CPU. =DSK."; IF #input="" THEN BEGIN #input := #entity; msg #prompt & ": " & #input; ok:=1; RETURN; END; #input:=#upcase#input; SCAN #entities until "=" & #input & "."->i; IF (i<=0) THEN BEGIN MSG #prompt & ": <<< 'CPU' or 'DSK' required"; RETURN; END; ok := 1; ?PROC ckPid(#prompt,#input,ok) {----------------------------- { Checks that first letter is "$" followed by XX { RETURN OK = false if not $XX ok { RETURN OK = TRUE if it is "$XX" or "" {------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; if #input="" then begin ok:=1; return; end; IF NOT (#input[1]="$") or NOT (#ALPHA#input[2]) or NOT (#ALPHA#input[3]) THEN BEGIN MSG #prompt & ": <<< PID prefix $XX required"; RETURN; {Pid ck END; ok := 1; ?PROC ckSubvol(#prompt,#input,ok); {---------------------------------- { Checks that first letter is "$" followed by volume.subvol { RETURN OK = false if not $volume.subvol ok { RETURN OK = TRUE if it is "$Volume.subvol" or "" { note "" => just return, we'll use #dbSV or #hiSV {------------------------------------------------- PARM #prompt, #input IO, ok:=0 OUT; var i:=0, #z; IF #input="" THEN BEGIN SCAN #prompt until "HISTORY" -> i; if i then #input:=#hiSV { Prompt for HISTORY subvol else #input:=#dbSV;{ Prompt for Database subvol msg #prompt & ": " & #input; ok:=1; RETURN; END; IF NOT (#input[1]="$") or NOT (#ALPHA#input[2]) THEN BEGIN MSG #prompt & ": <<< $Volume invalid"; RETURN; END; {$Volume. ck SCAN #input[3] until "." ->i; IF (I<=0) or (I> 9) THEN BEGIN MSG #prompt & ": <<< Expected $vol.subvol separator"; RETURN; END; {$Volume. ck IF NOT (#ALPHA#input[i+1]) THEN BEGIN MSG #prompt & ": <<< Subvol not AlphaNumeric"; RETURN; END; { alpha subvol ck i:=#size#input-i; { i is subvol length IF (i>8) THEN BEGIN MSG #prompt & ": <<< Subvol too long"; RETURN; END; {subvol ck ok := 1; ?PROC FilePresent(#filename,yes) {------------------------------- { Check if #filename is present in same subvol as the #shell script. { If it is, then return yes = 1 else yes = 0 {------------------------------------------------------------------- PARM #filename IO, yes:=0 OUT; VAR #file:=#shell ,#fileinfo , err , i ; SCAN BACK #file UNTIL "." -> i; if i<=0 then return; #file[i] := "." & #filename; #fileinfo := #INFO #file; err := #TAKE #fileinfo; if err then return; { file is not present yes:=1; { file is present ?PROC AsapDefaults(#nodes,ok) {---------------------------- { Determine Cpu and Disk counts, and DB, DICT, and HISTORY subvols. {---------------------------------------------------------------------------------------- PARM #nodes:="\*" { either \* (default) or \sysname , ok:=0 OUT { 0=> error, 1=> OK ; VAR #dbVolume { $Volume of DB and History subvols , i { Scratch variables , j ,#s ,#z , err ; MSG "Analyzing environment at " & #date & " ..."; { Turn off IOCONTROL WRITE ASAP, "SET IOC 0"; IF #nodes="\*" THEN BEGIN { implies first call to AsapDefaults { Determine DB and History subvol var values #dbSV and #hiSV WITH asap; DO BEGIN END UNTIL #TASKPROMPTING or #TASKSTOPPED; DELETE ASAP!; { clear cache WRITE ASAP,"SET"; WITH asap; DO BEGIN { READ output looking for DB..., DBRollover... READ ASAP, #z, err; if err then #z:=""; { Determine DB subvolume SCAN #z UNTIL " DB..."-> j; if #z<>"" and (j) then begin { set #dbSV scan #z until "$" -> i; if i then begin #dbSV := #z[i:132]; scan #z[i] until "." -> j; { find end of $volume. name IF (j<=0) THEN BEGIN MSG "AsapDefaults: ERROR SET DB.... $volume. delimeter missing"; RETURN; END; #dbVolume := #z[i:j-1]; { remove .DB from end of $vol.subvol.db and save in #dbSV j:=j+1; scan #z[j] until "." -> j; #dbSV:=#z[i:j-1]; end; end; { Determine History DB rollover prefix SCAN #z UNTIL " DBRolloverSubvolPrefix.." -> j; if (#z<>"") and (j) then begin { set #hiSV scan #z[4] until " " -> i; { find start of subvol name if i then begin #hiSV := #dbVolume & "." & #z[i+1:132] & "20" & #date[1:2]; { e.g. $ASAP.ASAP2012 end else begin MSG "AsapDefaults: ERROR SET DBRolloverSubvolPrefix.. not found"; RETURN; end; end; END UNTIL #TASKPROMPTING or #TASKSTOPPED; if #dbSV="" then begin msg "AsapDefaults: ERROR could not determine DB... subvolume"; return; end; if #hiSV="" then begin msg "AsapDefaults: ERROR could not determine DB Rollover subvol"; return; end; END;{#nodes=\* { Determine Cpu object count WITH asap; DO BEGIN END UNTIL #TASKPROMPTING or #TASKSTOPPED; DELETE ASAP!; { clear cache WRITE ASAP,"C" & #nodes & ",RAW"; CpuCnt:=0; DO BEGIN READ ASAP,#z; #s:= #TAKE #z; if #s="\" then CpuCnt := CpuCnt+1; END UNTIL #TASKPROMPTING or #TASKSTOPPED; { Determine DISK object count WITH asap; DO BEGIN END UNTIL #TASKPROMPTING or #TASKSTOPPED; DELETE ASAP!; { clear cache WRITE ASAP,"D" & #nodes & ",AVG,RAW"; DiskCnt:=0; DO BEGIN READ ASAP,#z; #s:= #TAKE #z; if #s="\" then DiskCnt := DiskCnt+1; END UNTIL #TASKPROMPTING or #TASKSTOPPED; ok:=1; ?PROC AnalyzeMemory(ok) {---------------------- { Compute value of global "CachePerObj" needed for each object based on { number of days and the number of hours/day. { { First we assume 24 hours per day, then if fewer hours reduce cache needed. { { The formula CachePerObj := Days + Days/10; for Days=30 implies CachePerObj would { equal 30+30/10 = 33. Note that actual empirical testing of SeeView shows { that 30 days x 24 hours/day = 720 lines which for 70 char/line output uses 33 pages. { { Also note: If Hours<24 then CachePerObj := ((CachePerObj*Hours)+15)/24); { { Finally CacheAvail per object is computed and compared to CachePerObj, and { if avail for each hour of day. ! Select statistics within HOUR range with SET HourFrom & HourUntil below. !---------------------------------------------------------------------------- CLOSE CPU; ! incase prior assign was in affect OPEN CPU; ! open with new assign DECLARE x,CpuBusy,CpuQ,CpuDisp,DiscRate,ChitRate,SwapRate,MemQ,PcbMaxPct,LcbMax; DECLARE HourFrom,HourUntil,MinFrom,MinUntil; set @target-records 0 @stats on; SET HourFrom to <#HourFrom>;! hh hour to start "from" SET HourUntil to <#HourUntil>;! hh hour to end "until" SET MinFrom to 00;! mm minute to start "from" SET MinUntil to 00;! mm minute to end "until" TITLE ""; SUBTITLE ""; LIST by sysno noprint by cpuno noprint by ihour noprint x := ( (event.ts - 211024440000000000) /10000 * 65536 ) noprint CpuBusy := avg (busy over ihour) noprint CpuQ := avg (qlen over ihour) noprint CpuDisp := avg (disps over ihour) noprint DiscRate := avg (discs over ihour) noprint ChitRate := avg (chits over ihour) noprint SwapRate := avg (swaps over ihour) noprint MemQ := avg (mqlen over ihour) noprint PcbMaxPct := max ((pcb-use*100+128)/pcb-cnf over ihour) noprint LcbMax := max (lcb-use over ihour) noprint where (sysname = "<#nodes>") and (zhourb <= (24- HourFrom ) ) and (zhourb > (24- HourUntil) ) and (zminb<>60) after change on cpuno print skip 1 "Nodename Cpu yy/mm/dd Time Busy CpuQ Disc Swap PCB% "skip 1 "-------- -------- -------- ----- ---- ---- ----- ---- ---- " after change on ihour print sysname space cpuno as i8.2 space timestamp-date(x) as date "y2/m2/d2" space timestamp-time(x) as time "h2:m2" space CpuBusy as i4 space CpuQ as i4 space DiscRate as i5 space SwapRate as i4 space PcbMaxPct as i4 space ! cpudisp as "[bz] i5" space ! chitrate as "[bz] i4" space ! memq as "[bz] i2" space ! lcbmax as "[bz] i4" space ; ?MENU DDLDB CACHE 3 !------------------ ! DDL must be synchronized with CpuQuery and DskQuery !------------------------------------------------------------------------ DELETE RECORD CPUH. ! Note Delete errors are ok DELETE RECORD DSKH. ! Note Delete errors are ok DELETE DEF cpuh-stats. ! Note Delete errors are ok DELETE DEF dskh-stats. ! Note Delete errors are ok DELETE DEF p-keyh. ! Note Delete errors are ok DEF p-keyh. 03 Nodename type character 8. ! \sysname 03 filler type character 1. 03 Domain type character 8. ! $data001 (or) 03 filler type character 1. 03 zDate type character 8. ! yy/mm/dd 03 filler type character 1. 03 zTime type character 5. ! hh:mm 03 filler type character 1. END. DEF cpuh-stats. 02 p-keyh type *. 02 Busy type character 4. ! Cpu Busy from 00 - 100 02 filler type character 1. 02 CpuQ type character 4. ! Cpu queue length 02 filler type character 1. 02 Disc type character 5. ! Disk i/o's per second 02 filler type character 1. 02 Swap type character 4. ! page faults per second 02 filler type character 1. 02 Pcb type character 4 heading "PCB%". ! Max% low pin PCBs used 02 filler type character 1. END. RECORD CpuH. File is DBCPUH. Def is cpuh-stats. Key 0 is p-keyh. END. DEF dskh-stats. 02 p-keyh type *. 02 Full type character 4. ! Percent full 02 filler type character 1. 02 Requests type character 5. ! Requests received per second 02 filler type character 1. 02 Busy type character 4. ! Disk Busy 02 filler type character 1. 02 Write type character 4. ! Disk Write Busy 02 filler type character 1. 02 Read type character 4. ! Disk Read Busy 02 filler type character 1. END. RECORD DskH. File is DBDSKH. Def is dskh-stats. Key 0 is p-keyh. END. ! ?MENU DskQuery CACHE 4 { DiskByHour !---------------------------------------------------------------------------- ! Display Disk statistics by \node and $volume for each hour of the day. ! Select statistics within HOUR range with SET HourFrom & HourUntil below. ! 2011/8/26 includes fix for Used% calculation per solution 10-110824-9356 !---------------------------------------------------------------------------- CLOSE DSK; ! incase prior assign was in effect OPEN DSK; ! open with new assign DECLARE x,vcpu,vpin,vcap,vavail,vbusy,vWbusy,vRbusy,vreqs,vchit,vswap; DECLARE HourFrom,HourUntil,MinFrom,MinUntil; set @target-records 0 @stats on; SET HourFrom to <#HourFrom>;! hh hour to start "from" SET HourUntil to <#HourUntil>;! hh hour to end "until" SET MinFrom to 00;! mm minute to start "from" SET MinUntil to 00;! mm minute to end "until" TITLE ""; SUBTITLE ""; LIST by sysno noprint by linename noprint by ihour noprint x := ( (event.ts - 211024440000000000) /10000 * 65536 ) noprint vcpu := cpu noprint vpin := pin noprint vcap := max (capacity over ihour) noprint vavail := max (avail-space over ihour) noprint vreqs := avg ((requests+50)/100 over ihour) noprint vbusy := avg (((disk-devices[1].busy + disk-devices[2].busy + 5) /10)/2 over ihour) noprint vWbusy := avg (((disk-devices[1].write-busy + disk-devices[2].write-busy + 5) /10)/2 over ihour) noprint vRbusy := avg (((disk-devices[1].read-busy + disk-devices[2].read-busy + 5) /10)/2 over ihour) noprint vchit := avg (chit over ihour) noprint vswap := avg (swaps/10 over ihour) noprint where (sysname = "<#nodes>") and (zhourb <= (24- HourFrom ) ) and (zhourb > (24- HourUntil) ) and (zminb<>60) after change on linename print skip 1 "Nodename DiskName yy/mm/dd Time Full Reqs Busy Wrte Read Chit " skip 1 "-------- -------- -------- ----- ---% ----- ---% ---% ---% -----" after change on ihour print sysname space linename space timestamp-date ( x ) as date "y2/m2/d2" space timestamp-time ( x ) as time "h2:m2" space (((vcap*10 - vavail)*100+(vcap*10/2))/(vcap*10)) as "i4" space vreqs as i5 space vbusy as i4 space vWbusy as i4 space vRbusy as i4 space vchit as i5 space ! vswap as "[bz] i4" space ; ?MENU QueryEnf CACHE 4 {--------------------- Working Query cache ?PROC CacheChange(Cacheid,#target,#newtext) {------------------------------------------ { Change all #target to #newtext for "Cacheid". { Note that the cache search is NOT case sensitive. {-------------------------------------------------- PARM Cacheid { taskid of cache to scan ,#target { target text to change ,#newtext { text to replace target ; VAR #s { scratch string var ,#before { text before target ,#after { text after target , r:=0 { record no in cache , c:=0 { column no in cache ; DO BEGIN { Loop while target found SEARCH Cacheid CACHE #Target STARTING r,c -> r,c LINEFOUND #s; IF r<0 THEN RETURN; { Target not found, done. #before:=""; { text in #s before target #after :=""; { text in #s after target IF c>1 THEN { there is text before #before:=#s[1:c-1]; IF (c+#SIZE #target) <= (#SIZE #s) THEN #after := #s[c+#SIZE #target:132]; #s:= #before & #newtext & #after; { #s updated, now update record in cache WRITE Cacheid CACHE r UPDATE,#s; c:= c + #size #newtext; END UNTIL r<0; ?PROC CacheCopy(FromTid,ToTid) {----------------------------- { Copies from cache FromTid to cache ToTip { Note ENFORM comment lines starting with "!" are NOT copied to ToTid {-------------------------------------------------------------------- PARM FromTid, ToTid; VAR i:=-1,#z,err; DELETE ToTid!; DO BEGIN READ FromTid CACHE (i:=i+1),#z,err; IF not err THEN BEGIN IF #TAKE#z<>"!" THEN PUSH #z onto ToTid; { skip ENFORM comment lines END; END UNTIL err; ?PROC CacheShow(Tid,inx,head) {---------------------------- { Displays contents of Cache Tid { If inx then start at inx (note may be negative) { inx:=-5 => show last 5 lines of cache Tid {------------------------------------------------ PARM Tid IN ,inx := 0 IN ,head := 0 IN ; VAR i,#z,err; i:=inx; { note may be negative if head then begin WITH tid; if head=1 then MSG "---------------------> CACHE " & #TaskSymbol & " <---------------------" else MSG #spaces[1:65] & #TaskSymbol; end; DO BEGIN READ Tid CACHE i,#z,err; i:=i+1; IF not err THEN BEGIN MSG #z; END; END UNTIL err; ?PROC CacheShowObjs {------------------ var #s,i,err,tid; msg ""; DO BEGIN { Read each record in ObjInx and CacheShow each Tid in the ObjInx READ ObjInx CACHE (i:=i+1),#s,err; IF err=0 THEN BEGIN if i=0 then begin msg #Qheading; msg #QheadingUn; end; tid:=#s[colTaskid:colTaskid+4]; CALL CacheShow(tid,,2); END; END UNTIL err; ?PROC CiCmds(Ci,Cmds,Ok) {----------------------- { Sends parm CI the commands contained in cache CMDS { Ok indicates whether there were any errors sending the commands. {----------------------------------------------------------------------------- PARM ci IN { Taskid of the command interperter to send "Cmds". , cmds IN { Cache taskid containing commands to be sent to "ci". , Ok := 0 OUT { Ok=1 if cmds went to CI without errors ; VAR #s , i:=-1 , err ; WITH ci; EXE "TASK " & #tasksymbol; { Re-assert task, incase it had stopped DELETE ci!; { clear ci cache DO BEGIN { send commands in Cmds to ci READ Cmds CACHE (i:=i+1),#s,err; IF (err=0) THEN BEGIN WRITE ci,#s,,err; IF (err) THEN BEGIN MSG "WRITE " & #tasksymbol & " error in procedure CiCmds, err: " & err; RETURN; { note OK is 0 by default END; END; END UNTIL err; Ok := 1; IF trace THEN CALL CacheShow (ci); ?MENU DBCreateCmds CACHE 1 {------------------------- { FUP commands to create #DBentH database file {--------------------------------------------- < BEGIN DBCreateCmds > VOLUME <#dbSV> ALLOW 1 WARNINGS PURGE <#DBentH> ! SET TYPE K SET REC 132 SET EXT(1024,1024) SET MAXEXTENTS 512 SET KEYOFF 0 SET KEYLEN 32 SET BLOCK 4096 SET CODE 2001 CREATE <#DBentH> < END DBCreateCmds > ?PROC DBCreate(LoadCnt,OK) {------------------------- { Uses FUP LOAD to load stats in ObjInx to #dbSV & DBentH from ObjInx caches {-------------------------------------------------------------------------------- PARM LoadCnt:=0 IO { Count of Records FUP LOAD-ed , ok:=0 OUT { 0 => error, 1 => completed ok ; VAR err { Contains WRITE FUP FE err values , ObjInxI:=-1 { cache line index in ObjInx cache , SysObjI:=-1 { cache line index in TidSysObj cache , TidSysObj { Taskid of Sysnname Object cache ,#sObjInx { \sysname Cpu/$vol Taskid TaskSymbol ,#sSysObj { \sysname Cpu/$vol ,#s { scratch ,#z { scratch ; { Fix vars in DbCreateCmds and WRITE those commands to FUP CALL CacheChange(DBCreateCmds, "<#dbSV>", #dbSV); CALL CacheChange(DBCreateCmds, "<#DBentH>", #DBentH); CALL CiCmds( FUP, DbCreateCmds ); DELETE fup!; { Clear cache WRITE fup,""; { FUP LOAD #myprocessname, #DBentH, SORTED #z := "LOAD " & #myprocessname & "," & #DBentH & ",SORTED"; WRITE FUP,#z,,err; IF err THEN BEGIN MSG "DBCreate: WRITE FUP LOAD err: " & err; RETURN; END; MSG ""; MSG "ASAPDBA ->FUP LOAD Object Load "; MSG "\sysname Cpu/$Vol Cache Tid Time "; MSG "-------- -------- --------- --------" WITH fup; { FUP LOAD ObjInx stats loop DO BEGIN { Read ObjInx sorted cache of cache taskids READ ObjInx CACHE (ObjInxI:=ObjInxI+1), #sObjInx, err; IF err=0 THEN BEGIN { Have another TidSysObj to load MSG "\" & #SObjInx[1:29] & " " & #time; { show taskid TidSysObj := #TAKE #sObjInx[colTaskid:colTaskid+8]; SysObjI:=-1; DO BEGIN { Read TidSysObj stats into #sSysObj for LOAD READ TidSysObj CACHE (SysObjI:=SysObjI+1), #sSysObj, err; IF trace>1 THEN MSG #sSysObj; IF err=0 THEN BEGIN { Have another stats record do begin { Get with next FUP LOAD blank " " prompt read fup,#z,err; end until err; IF err>1 THEN BEGIN MSG "DBCreate: FUP LOAD get with blank prompt, error: " & err; CALL CacheShow(fup); RETURN; END; IF (#TASKPROMPT=" ") THEN BEGIN { Reply to FUP LOAD prompt with #sSysObj WRITE fup,#sSysObj,,err; IF err THEN BEGIN MSG "DBCreate: WRITE FUP LOAD error: " & err; RETURN; END; IF LoadCnt<32766 THEN LoadCnt:=LoadCnt+1; END ELSE BEGIN MSG "DBCreate: FUP LOAD unexpectedly terminated, error: " & err; CALL CacheShow(fup); RETURN; END; END; END UNTIL err;{Load TidSysObj stats loop err:=0; END;{err=0 END UNTIL err;{Read ObjInx loop #s:=""; WRITE fup,#s,1,err; {SEND EOF to FUP to indicate end of LOAD INPUT ok:=1; MSG " Records Loaded = " & LoadCnt; ?PROC DBCopy(CopyCnt,OK) {----------------------- { Uses FUP COPY to copy stats in ObjInx to #dbSV & DBentH from ObjInx caches {-------------------------------------------------------------------------------- PARM CopyCnt:=0 IO { Count of Records FUP COPY-ed , ok:=0 OUT { 0 => error, 1 => completed ok ; VAR err { Contains WRITE FUP FE err values , ObjInxI:=-1 { cache line index in ObjInx cache , SysObjI:=-1 { cache line index in TidSysObj cache , TidSysObj { Taskid of Sysnname Object cache ,#sObjInx { \sysname Cpu/$vol Taskid TaskSymbol ,#sSysObj { \sysname Cpu/$vol ,#s { scratch ,#z { scratch ; DELETE fup!; { Clear cache WRITE fup,""; { FUP COPY #myprocessname, #DBentH #z := "COPY " & #myprocessname & "," & #DBentH; WRITE FUP,#z,,err; IF err THEN BEGIN MSG "DBCopy: WRITE FUP COPY err: " & err; RETURN; END; MSG ""; MSG "ASAPDBA ->FUP COPY Object COPY "; MSG "\sysname Cpu/$Vol Cache Tid Time "; MSG "-------- -------- --------- --------" WITH fup; { FUP COPY ObjInx stats loop DO BEGIN { Read ObjInx sorted cache of cache taskids READ ObjInx CACHE (ObjInxI:=ObjInxI+1), #sObjInx, err; IF err=0 THEN BEGIN { Have another TidSysObj to COPY MSG "\" & #SObjInx[1:29] & " " & #time; { show taskid TidSysObj := #TAKE #sObjInx[colTaskid:colTaskid+8]; SysObjI := -1; DO BEGIN { Read TidSysObj stats into #sSysObj for COPY READ TidSysObj CACHE (SysObjI:=SysObjI+1), #sSysObj, err; IF trace>1 THEN MSG #sSysObj; IF err=0 THEN BEGIN { Have another stats record do begin { Get with next FUP COPY blank " " prompt read fup,#z,err; end until err; IF err>1 THEN BEGIN MSG "DBCopy: FUP COPY get with blank prompt, error: " & err; CALL CacheShow(fup); RETURN; END; IF (#TASKPROMPT=" ") THEN BEGIN { Reply to FUP COPY prompt with #sSysObj WRITE fup,#sSysObj,,err; IF err THEN BEGIN MSG "DBCopy WRITE FUP COPY error: " & err; RETURN; END; IF CopyCnt<32766 THEN CopyCnt:=CopyCnt+1; END ELSE BEGIN MSG "DBCopy: FUP COPY unexpectedly terminated, error: " & err; CALL CacheShow(fup); RETURN; END; END; END UNTIL err;{Load TidSysObj stats loop err:=0; END;{err=0 END UNTIL err;{Read ObjInx loop #s:=""; WRITE fup,#s,1,err; {SEND EOF to FUP to indicate end of COPY INPUT ok:=1; MSG " Records Copied = " & CopyCnt; ?PROC Initialize(ok) {------------------- { Initializes various variables and caches {-------------------------------------------------------------------------------- PARM ok:=0 OUT; VAR #z, #TasksAlloc, TasksFree, i; { Init dependent variables #DBentH := #dbSV & ".DB" & #entity & "H"; { DBentH output file name IF #entity="CPU" THEN BEGIN ObjectCnt := CpuCnt; END ELSE BEGIN ObjectCnt := DiskCnt; END; { Check if PARAM TASKS provides enough by doing STATUS to "free" { cache, then do a SEARCH * CACHE -/tasks:/ line #Z starting -1, and then { parse "Tasks: /" and compute number of free tasks. STATUS; #z:=""; SEARCH * CACHE -/Tasks:/ LINE #z STARTING -1; if #z<>"" then begin { Parse .... Tasks: 48/512 SCAN #Z until "/" ->i; if i then begin { found / #TasksAlloc:= #TAKE #z[i+1:132]; if #NUMERIC #TasksAlloc then begin TasksFree := #TasksAlloc - #TaskCount - 1; if TasksFree" & TasksFree; i:=(ObjectCnt+#TaskCount+1); MSG "Please increase the value of PARAM TASKS to " & i & " in following:"; MSG "SEEVIEW/ IN