Thursday, May 11, 2017

Rexx to Aggregate statistics by 1 hour, check and report bad counters - The must have for all sites

Update 18/01/2017 :  More field for Workfile BufferPool usage and alerts
Merge pass degraded ..., check Sequential Prefetch Quantity

Update 12/10/2017 :  Track Workfile usage and others enhancements
Counters are checked and reports are sent to a dataset (which is then sent to our DB2 team e-mail account). 


update : 11/5/2017

This Rexx allows to aggregate the detailed stats in value corresponding to 1 hour interval : this allows me to have a quick view / analysis , and it is enough light to be loaded to a DB2 database on Windows, SQLlite ...for a quick report (Note : after testing several free database on Windows, i am satisfied with DB2 because it allows a one click export to Excel from any SQL query )
I submit this Rexx daily on every Production LPAR and get the files sent to my PC where i load it to the DB2 table ...
I do this for the accounting and the statistics.





/*REXX*/
/****************************************************************/
/*   DB2 STATS AGGREGATED BY HOUR                               */
/****************************************************************/
numeric digits 15
arg OPT OPT2
if OPT = '' then lpar = MVSVAR(SYSNAME)
else   lpar = OPT
clnt=''
temX=0 /* just open new one time */
temR=0 /* Report in LOGW  */
Call SetSmfDs
hlq='SYSTMP.DBDC.DB2'
vsm='Y'    /*virtual storage monitoring Yes/No*/

/* Start processing unit for one SSID */

Start_Pgm:

nbGBP=0
nbBP=0
Hour='00'
Max_QISTW4K=0
Max_QISTW32K=0
bp0_vpsize=0
ifcid1_seen=0
Max_SUD2_gp=0
SumBP_SUD2=0
SumBP_SUD2_all=0
SUD2_BpInact=0
tsaylocal=0
ope =0
rupture=0
rec.0  =1
recw   =0
RFlush =0

/* init compteurs divers */
call init_var

/* START PROCESSING */
DO FOREVER
  /* read SMF record one by one   */
  "EXECIO 1 DISKR INP"
  IF RC > 0 THEN DO
            if rc =  2 then
             do
              SAY 'End of input SMF file rc=' RC
              rcalloc = rc
             end
             else do
              SAY 'Error while reading SMF file rc=' RC
              rcalloc = 8
             end
              leave
            END
  PARSE PULL INPUT_REC
  reci=reci+1
  OFFSET = 1
  /* Decode SMF header */
  CALL DSNDQWST
  /* process only smf100 */
  IF (SM100RTY = 100    ) THEN
  DO
    if ope = 0 then call CrOutput /* do the first time only */
    if  sm100ssi <> ssid then iterate
    /* record SMF records period   */
    if min_time > run_fmt_time then min_time=run_fmt_time
    if Max_time < run_fmt_time then Max_time=run_fmt_time
    if min_date > sm100dte     then min_date=sm100dte
    if Max_date < sm100dte     then Max_date=sm100dte

    /*sauvegarde offset_self car on le reutilise */
    offset_selfdef= offset
    /* on va sur le self def. section pour aller vers prod section*/
    offset = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset - 4 + 1
    /* traitement product section*/
    CALL DSNDQWHS
    offset=offset_selfdef
    /* ifcid 1 must start the stats group */
    if   ifcid =  1 then ifcid1_seen = 1
    else if   ifcid <> 1 & ifcid1_seen = 0 then
                               do
                                      iterate
                                      say 'bypass' ifcid
                               end
    recs=recs+1
    Select
         When ifcid     = 1  Then do
                                      CALL DSNDQWS0
                                      OFFSET = QWS00PSO - 4 + 1
                                  end
         When ifcid     = 2  Then do
                                      CALL DSNDQWS1
                                      OFFSET = QWS10PSO - 4 + 1
                                  end
         When ifcid     = 225 Then do
                                      CALL QW0225
                                      OFFSET = QWS10PSO - 4 + 1
                                  end
         Otherwise      do
                  /* add line here to avoid excessive displays */
                          if  ifcid = 202 then nop
                          else
                              if  ifcid = 230 then nop
                          else
                              say 'ifcid ' ifcid ' not processed'
                        end
    end   /* select */

    /*write report quand on a fait le tour des ifcids */
    if ifcid = 1 & recs > 1 then
       do
          call ifcid_diff
          /* on bypass le 1er record qui comprend les totaux*/
          if reco > 0 then Call write_report
          else reco = 1
       end
    else
    do
         if ifcid = 1 & recs = 1 then
         do
              Old_Mstrtcb =       Mstrtcb
              Old_MstrSrb =       MstrSrb
              Old_MstrpSRB=       MstrpSRB
              Old_MstrpSRB_Ziip = MstrpSRB_Ziip
              Old_dbm1Tcb =       dbm1Tcb
              Old_dbm1srb =       dbm1srb
              Old_dbm1pSRB=       dbm1pSRB
              Old_dbm1pSRB_Ziip = dbm1pSRB_Ziip
              Old_irlmTcb =       irlmTcb
              Old_irlmsrb =       irlmsrb
              Old_irlmpSRB=       irlmpSRB
              Old_irlmpSRB_Ziip = irlmpSRB_Ziip
              Old_distTcb =       distTcb
              Old_distsrb =       distsrb
              Old_distpSRB=       distpSRB
              Old_distpSRB_Ziip = distpSRB_Ziip
         end
    end
  END /*    IF SM100RTY = 100  */
END
/* flush pending report (only at eof ) */
RFlush=1
call write_summary
"EXECIO" queued() "DISKW OUFL ( FINIS"
rcwrite = rc
if rcwrite<> 0 then Do
   say "**********************************************"
   say "   Error writting OUFL file: " rcwrite
   say "   Abnormal end   "
   say "**********************************************"
   Exit 8
end
"EXECIO 0 DISKR INP (STEM INL. FINIS"
/* Free REPORTS dataset */
"FREE DD(OUFL)"

rec.1= " "
call LOGW
call DisplayPref
rec.1= " "
call LOGW
rec.1= "Input records =" reci
call LOGW
rec.1=  "Output records=" reco
call LOGW
rec.1= 'SMF period : ' min_date "/" Max_date min_time "/" Max_time
call LOGW

/*-------------------------------------------------*/
/* F20 End of program display counters and figures */
/*-------------------------------------------------*/
call DisplayVStor
if lpar = 'SUD2' then
         call SUD2_report_bp_usage
"EXECIO 0 DISKW OUFw (FINIS"
/* Free REPORTSW dataset */
"FREE DD(OUFW)"
if lpar = 'IPO4' then
   do
         /* process DSNI now */
         if ssid = 'DSNI' then /* avoid forever loop */
         do
              say 'End processing for IPO4'
         end
         else
         do
              ssid = 'DSNI'
              signal start_pgm
         end
   end

if lpar = 'SUD2' then
   do
         if ssid = 'DBAP' then
         do
              ssid = 'DB2A'
              signal start_pgm
         end
         if ssid = 'DB2A' then
         do
              ssid = 'DB2C'
              signal start_pgm
         end
         if ssid = 'DB2C' then
         do
              ssid = 'DB2D'
              signal start_pgm
         end
         if ssid = 'DB2D' then
         do
              ssid = 'DB2G'
              signal start_pgm
         end
         if ssid = 'DB2G' then
         do
              ssid = 'DB2I'
              signal start_pgm
         end
         if ssid = 'DB2I' then
         do
              ssid = 'DB2P'
              signal start_pgm
         end
         if ssid = 'DB2P' then
         do
              ssid = 'DB2R'
              signal start_pgm
         end
         if ssid = 'DB2R' then
         do
              ssid = 'DFEI'
              signal start_pgm
         end
         if ssid = 'DFEI' then
         do
              ssid = 'DFLI'
              signal start_pgm
         end
         if ssid = 'DFLI' then
         do
              ssid = 'DPEI'
              signal start_pgm
         end
         if ssid = 'DPEI' then
         do
              ssid = 'DPLI'
              signal start_pgm
         end
         if ssid = 'DPLI' then
         do
              ssid = 'DQE3'
              signal start_pgm
         end
         if ssid = 'DQE3' then
         do
              ssid = 'DRC2'
              signal start_pgm
         end
         if ssid = 'DRC2' then
         do
              say 'All DB2 of SUD2 processed - Ending'
         end
   end

if lpar = 'ZPR1' then
   do
         /* process DSNH now */
         if ssid = 'DB2E' then /* avoid forever loop */
         do
              ssid = 'DB2H'
              signal start_pgm
         end
         else
         do
              if ssid = 'DB2H' then
              do
                   ssid = 'DB2I'
                   signal start_pgm
              end
              else
              do
                   /* je suis la parce que ssid = 'DB2I'*/
                   say 'Tous les DB2 de ZPR1 sont traités'
              end
         end
   end
"FREE DD(INP)"
if lpar = 'SUD2' then
do
  "EXECIO 0 DISKW OUFs2 (FINIS"
  "FREE DD(OUFs2)"
end
EXIT rcalloc

/*---------------------------------------*/
/* End of program body- Routines section */
/*---------------------------------------*/

/* MAP SELF-DEFINING SECT IFCID 001 LG = 112 */
DSNDQWS0:
  /*  OFFSET TO THE PRODUCT SECTION */
  QWS00PSO = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 4
  QWS00PSL = C2D(SUBSTR(INPUT_REC,OFFSET,2))
  OFFSET = OFFSET + 2
  QWS00PSN = C2D(SUBSTR(INPUT_REC,OFFSET,2))
  OFFSET = OFFSET + 2
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQWSA CPU TIME */
  QWS00R1O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 4
  QWS00R1L =  C2D(SUBSTR(INPUT_REC,OFFSET,2))
  OFFSET = OFFSET + 2
  QWS00R1N =  C2D(SUBSTR(INPUT_REC,OFFSET,2))
  OFFSET = OFFSET + 2
  save_offset = offset
  /* controle de coherence */
  if  QWS00R1N  > 4 then
      do
           say 'QWS00R1N is not equal to 4, abnormal end ' QWS00R1N
           exit 8
      end
  /* Load offset to DSNDQWSA section - decode db2 stc cpu section */
  OFFSET= QWS00R1O - 4 + 1
  /* init DIST pas toujours pr§sent */
  DISTTcb      = 0
  DISTSrb      = 0
  DISTpSRB     = 0
  DISTpSRB_Ziip= 0
  i=0
  do until i= QWS00R1N
         i = i+ 1
         call DSNDQWSA
  end

  /*restore offset */
  offset = save_offset

  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQWSB STATS COUNTERS*/
  /*  INSTRUMENTATION STATISTICS DATA ABOUT OUTPUT DESTINATION */
  QWS00R2O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQWSC */
  /*  IFCIDS RECORDED TO STATISTICS */
  QWS00R3O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQ3ST */
  /*  Subsytem services fields */
  /*  SIGNON, IDEN, COMMITS, ABORTS ...*/
  QWS00R4O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  save_offset = offset
  offset = QWS00R4O - 4 + 1
  call DSNDQ3ST
  offset = save_offset
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQ9ST */
  QWS00R5O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQWSD */
  /*  CHECKPOINT INFO, IFI COUNT    ...*/
  QWS00R6O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  save_offset = offset
  offset = QWS00R6O - 4 + 1
  call DSNDQWSD
  offset = save_offset
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQVLS */
  /*  LATCH COUNTS                  ...*/
  QWS00R7O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQVAS */
  /*  ASMC STATS NBRE DE SUSPENSIONS ..*/
  QWS00R8O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQSST */
  /*  STORAGE MANAGER */
  QWS00R9O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  save_offset = offset
  offset = QWS00R9O - 4 + 1
  call DSNDQSST
  offset = save_offset
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQLST */
  /*  DDF STATS BY LOCATION */
  QWS00RAO = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQJST */
  /*  LOG MANAGER           */
  QWS00RAO = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  save_offset = offset
  offset = QWS00RAO - 4 + 1
  call DSNDQJST
  offset = save_offset
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQDST */
  /*  DBAT STATS            */
  QWS00RCO = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  save_offset = offset
  offset = QWS00RCO - 4 + 1
  call DSNDQDST
  offset = save_offset
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQWOS */
  /*  ZOS STATS             */
  QWS00RCO = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  /* LG = 112 = 14 SECTIONS * 8 */

  Return


QW0225:
numeric digits 15
       offset_save=offset /* sauvergarde offset debut data section*/
       /* offset= offset of self definition section*/
       /* offset= offset + 8 : bypass pointer to Product  Section*/
       /* offset_d = offset de la data section */
       offset=offset+4+2+2 /*pointer to data section 1*/
       /*take the contents pointed by the offset */
       offset_d= C2D(SUBSTR(INPUT_REC,OFFSET,4))

       /* -------------- */
       /* data section 1 */
       /* -------------- */
       /* Data section 1 = 2 parts, DBM1 and DIST */

       /* offset to dbm1 */
       offset_d=offset_d -4+1
       offset=offset+4

    /* say 'offs sect1'  offset_d */
       /* len of data section 1 : it will be repeated :*/
       /* One for DBM1 and one for DIST */
       len=      C2D(SUBSTR(INPUT_REC,OFFSET,2))
       offset=offset+2
       rep=      C2D(SUBSTR(INPUT_REC,OFFSET,2))
       offset=offset+2
    /* say 'len' len
       say 'rep' rep */

       /* offset to DIST */
       offset_d2=offset_d+len

    /* say 'offs sect2'  offset_d2 */

       QW0225AN =(SUBSTR(INPUT_REC,OFFSET_d,4))
       if  QW0225AN <> 'DBM1' then
       do
           say 'W0225 - Mapping error'
           exit 8
       end
    /***********************************/
    /* Processing DBM1 storage section */
    /***********************************/
       if  QW0225AN =  'DBM1' & vsm ='Y'  then
       do
           offset_d=offset_d+4
           /* extended region size */
           QW0225RG = C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
           offset_d=offset_d+4+4+4
           QW0225EL = C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
           offset_d=offset_d+4
           QW0225EH = C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
           offset_d=offset_d+4 +4+4
           /* storage reserved fo must complete */
           /* before V10 depends on CTHREAD and MaxDBAT zparm*/
           QW0225CR = C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
           offset_d=offset_d+4
           /* storage reserved for open/close datasets */
           /* depends on DSMax value */
           QW0225MV = C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
           offset_d=offset_d+4
           QW0225SO = C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
           offset_d=offset_d+4
           QW0225GS = C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
           offset_d=offset_d+4+4
           QW0225VR = C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
           offset_d=offset_d+4
           QW0225FX = C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
           offset_d=offset_d+4
           QW0225GM = C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
           offset_d=offset_d+4
           /* 31 bit storage available */
           QW0225AV = C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
           offset_d=offset_d+4+4+8+8+8+8
           QW0225RL_dbm1 = C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
           /* 225RL = Real stor. frame used by the Address Space*/
           /*    this includes bufferpools storage qw0225bb */
           offset_d=offset_d+8
           QW0225AX_dbm1 = C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
           offset_d=offset_d+8
           /* QW0225HVPagesInReal 64 bits private Real */
           QW0225HVPagesInReal =  C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
           offset_d=offset_d+8
           /* QW0225HVAuxSlots    64 bits private Aux */
           QW0225HVAuxSlots =  C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
           offset_d=offset_d+24
      /*   /* QW0225HWM           64 bits private Real*/
           QW0225HVGPagesInReal =  C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
           offset_d=offset_d+8
           /* QW0225HWM           64 bits private Aux */
           QW0225HVGAuxSlots=  C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
           offset_d=offset_d+8 */
           /* QW0225PagesInReal 64 bits private Real without BP */
           QW0225PriStg_Real=  C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
           offset_d=offset_d+8
           /* QW0225PagesInAux  64 bits private Aux  without BP */
           QW0225PriStg_Aux=  C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
           offset_d=offset_d+8
           TotalRealUsedBP = QW0225HVPagesInReal - QW0225PriStg_Real
           TotalAuxUsedBP = QW0225HVAuxSlots    - QW0225PriStg_Aux
       end  /* if  QW0225AN =  'DBM1' & vsm = 'Y' then */

       /* rep = 2 : there is 2 parts , DBM1 and DDF */
       if rep = 2 then
       do
          /* partie DIST */
          QW0225AN =(SUBSTR(INPUT_REC,OFFSET_d2,4))
          if  QW0225AN <> 'DIST'  then
          do
              say 'W0225 - Mapping error DIST not found'
              say 'input_rec' input_rec
              say 'offset'   offset_d2
              exit 8
          end
          if  QW0225AN =  'DIST' & vsm='Y' then
          do
              offset_d2=offset_d2+4
              offset_d2=offset_d2+4+4+4
              offset_d2=offset_d2+4
              offset_d2=offset_d2+4 +4+4
              offset_d2=offset_d2+4
              offset_d2=offset_d2+4
              offset_d2=offset_d2+4
              offset_d2=offset_d2+4+4
              offset_d2=offset_d2+4
              offset_d2=offset_d2+4
              offset_d2=offset_d2+4+4+4+8+8+8+8
              QW0225RL_dist = C2D(SUBSTR(INPUT_REC,offset_d2,8))
              offset_d2=offset_d2+8
              QW0225AX_dist = C2D(SUBSTR(INPUT_REC,offset_d2,8))
          end  /* if  QW0225AN =  'DIST' & vsm = 'Y' then */
       end
       else /*if rep = 2 then*/
       do
              QW0225RL_dist = 0
              QW0225AX_dist = 0
       end

       /*pointer to data section 2*/

       offset_d= C2D(SUBSTR(INPUT_REC,OFFSET,4))
       offset_d=offset_d -4+1


       QW0225AT =C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
       offset_d=offset_d+4 /*pointer on data section 2*/
       QW0225DB =C2D(SUBSTR(INPUT_REC,OFFSET_d,4))

       if (QW0225AT + qw0225DB) < MinThdSee then
          do
              MinThdSee = QW0225AT + qw0225DB
              MinThdSeeTime= run_fmt_time
              MinThdSeeDate= sm100dte
          end
       if (QW0225AT + qw0225DB) > MaxThdSee then
          do
              MaxThdSee = QW0225AT + qw0225DB
              MaxThdSeeTime= run_fmt_time
              MaxThdSeeDate= sm100dte
          end
       /* say 'threads allied=' QW0225AT
          say 'threads dbat=' QW0225DB      */

       /*pointer to data section 3 : Shared and Common Storage */
       offset=offset+8 /* go to next pointer*/
       if vsm = 'Y' then
       do
          /* load address of section 3*/
          offset_d= C2D(SUBSTR(INPUT_REC,OFFSET,4))
          offset_d=offset_d -4+1

          offset_d=offset_d +136
          QW0225SHRINREAL  =C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
          offset_d=offset_d + 32
          QW0225ShrStg_Real=C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
          offset_d=offset_d + 8
          QW0225ShrStg_Aux =C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
          offset_d=offset_d + 8
          QW0225ShrStkStg_Real=C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
          offset_d=offset_d + 8
          QW0225ShrStkStg_Aux =C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
          offset_d=offset_d + 8
          QW0225ComStg_Real=C2D(SUBSTR(INPUT_REC,OFFSET_d,8))
          offset_d=offset_d + 8
          QW0225ComStg_Aux =C2D(SUBSTR(INPUT_REC,OFFSET_d,8))

         /* formula from    Redbook V11 Monitoring */
         /* table 13-1 13-2                        */
         /* Calculation to be updated when V11 + Log Mgr control */
         /* in Real, Log. write buffers  */
          TotalRealUsedByDB2 = qw0225rl_dbm1+ qw0225rl_dist +,
                 QW0225ShrStg_Real + QW0225ShrStkStg_Real +,
                 QW0225ComStg_Real

      /*  TotalRealUsedByLPAR meaning not clear - value does not  */
      /*     corresponds with others z/OS monitoring tool         */
      /*  TotalRealUsedByLPAR= qw0225rl_dbm1+ qw0225rl_dist +,    */
      /*       QW0225ComStg_Real + -- in redbook but no where else*/
      /*                           QW0225SHRINREAL                */
          /* QW0225ComStg_Real Real in use 64 bit shared */
          /* QW0225SHRINREAL   Real in use 64 bit common */

      /*  if MaxRealLPAR  <  TotalRealUsedByLPAR then */
      /*       do                                     */
      /*           MaxRealLPAR = TotalRealUsedByLPAR  */
      /*           time_MaxRealLPAR = run_fmt_time    */
      /*       end                                    */

          offset_d=offset_d + 32
      /*  QW0225_WARN      =C2D(SUBSTR(INPUT_REC,OFFSET_d,4)) */
          offset_d=offset_d + 8
          QW0225_REALAVAIL =C2D(SUBSTR(INPUT_REC,OFFSET_d,4))

          if MinQW0225_REALAVAIL > QW0225_REALAVAIL then
               do
                   MinQW0225_REALAVAIL = QW0225_REALAVAIL
                   time_MinQW0225_REALAVAIL = run_fmt_time
                   date_MinQW0225_REALAVAIL = sm100dte
               end
       end

       /*-------------------------*/
       /*pointer to data section 4*/
       /*-------------------------*/
       offset=offset+8

       /*-------------------------------------------------*/
       /*pointer to data section 5 : Pool storage details */
       /*-------------------------------------------------*/
       offset=offset+8
       if  vsm = 'Y' then
       do
         offset_d= C2D(SUBSTR(INPUT_REC,OFFSET,4))
         offset_d= offset_d+4
       /* QW0225AS Total system agent storage 31 bits*/
         QW0225AS =C2D(SUBSTR(INPUT_REC,OFFSET_d,4))
       /* QW0225BB Total buffer manager storage blocks */

       /*-------------------------------*/
       /* Calculate Max threads allowed */
       /*-------------------------------*/

         /*Ici on a eu tous les infos on peut donc calculer le */
         /* nombre de threads Max theoriques*/
         /* Source : IBM formula  */
         /* (Redbook V11 subsystem monitoring Chap. Virtual Stor*/
         /* Min and Max is used in a very defensive way */
         /* The excel proposed with MEMU deoesn't use min Max */
         /* I also caculate this value (thdcomp2) */

         /*    Thread footprint calculation : */

         /* Basic Storage Cushion */
         BC = QW0225CR + QW0225MV + QW0225SO
         /* Non DB2 storage, retains Max value for final calculation*/
         ND = QW0225EH-QW0225GM-QW0225GS-QW0225FX-QW0225VR
         if ND > MaxND then MaxND=ND
         /* Max Allowable storage */
         AS = QW0225RG-BC-MaxND
         AS2= QW0225RG-BC-ND
         if AS < MinAS then MinAS=AS
         /* Max Allowable storage for thread use*/
         TS = MinAS-(QW0225AS + QW0225FX + QW0225GM+ QW0225EL)
         TS2= AS2-(QW0225AS + QW0225FX + QW0225GM+ QW0225EL)
         if TS < MinTS then MinTS=TS
         /* Average thread footprint */
         if (QW0225AT + qdstcnat) = 0 then
            /* if threads in system = 0 then 1 */
            TF =  QW0225VR- QW0225AS + QW0225GS
         else
            TF = (QW0225VR-QW0225AS+QW0225GS)/(QW0225AT+qdstcnat)

         if TF > MaxTF then MaxTF=TF
         /* Max threads supported    */
         ThdComp=MinTS/MaxTF
         ThdComp2=TS2/TF
         StorBefContract=qw0225AV-(qw0225cr+qw0225SO+qw0225MV)
         /* Storage contraction ?*/
         if qw0225AV <  qw0225cr then
                do
                    say ' Storage critical condition',
                        '@ ' run_fmt_time
                end
         else do
              if qw0225AV <  (qw0225cr+ qw0225SO+qw0225MV) then
                do
                    say ' Full system contraction should happen',
                        '@ ' run_fmt_time
                end
         end /* else */

         if ThdComp < MinThdComp then do
                                     MinThdComp =ThdComp
                                     MinThdCompTime=run_fmt_time
                                     MinThdCompDate=sm100dte
                                   end
         if ThdComp2 < MinThdComp2 then do
                                     MinThdComp2 =ThdComp2
                                     MinThdComp2Time=run_fmt_time
                                     MinThdComp2Date=sm100dte
                                   end
         if ThdComp > MaxThdComp then do
                                     MaxThdComp =ThdComp
                                     MaxThdCompTime =run_fmt_time
                                     MaxThdCompDate =sm100dte
                                   end
         if ThdComp2 > MaxThdComp2 then do
                                     MaxThdComp2 =ThdComp2
                                     MaxThdComp2Time =run_fmt_time
                                     MaxThdComp2Date =sm100dte
                                   end

         Real4K_dbm1=(QW0225RL_dbm1 *4096)/ 1048576    /*1MB*/
         Real4K_dist=(QW0225RL_dist *4096)/ 1048576    /*1MB*/

         If MinReal4K_dbm1 > Real4K_dbm1 then
                          do
                             MinReal4K_dbm1=Real4K_dbm1
                             time_MinReal4K_dbm1=run_fmt_time
                             Date_MinReal4K_dbm1=sm100dte
                          end
         If MaxReal4K_dbm1 < Real4K_dbm1 then
                          do
                             MaxReal4K_dbm1=Real4K_dbm1
                             time_MaxReal4K_dbm1=run_fmt_time
                             Date_MaxReal4K_dbm1=sm100dte
                          end
         If MinReal4K_dist > Real4K_dist then
                          do
                             MinReal4K_dist=Real4K_dist
                             time_MinReal4K_dist=run_fmt_time
                             Date_MinReal4K_dist=sm100dte
                          end
         If MaxReal4K_dist < Real4K_dist then
                          do
                             MaxReal4K_dist=Real4K_dist
                             time_MaxReal4K_dist=run_fmt_time
                             Date_MaxReal4K_dist=sm100dte
                          end
         /* calculation to be updated when V11 + Log Mgr control */
         /* in aux - check IBM excel provided with memu */
         TotalAuxlUsedByDB2 = qw0225ax_dbm1+ qw0225ax_dist +,
               QW0225ComStg_Aux  + QW0225ShrStg_Aux  +  ,
                                   QW0225ShrStkStg_Aux
         If MaxDB2AuxUse < TotalAuxlUsedByDB2 then
                          do
                             MaxDB2AuxUse=TotalAuxlUsedByDB2
                             timeMaxDB2AuxUse=run_fmt_time
                             DateMaxDB2AuxUse=sm100dte
                          end
       end /* if vsm ... */
return
/* MAP SELF-DEFINING SECT IFCID 002 LG = 12X8 = 96 */
DSNDQWS1:
  /*  OFFSET TO THE PRODUCT SECTION */
  QWS10PSO = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQXST */
  /*  RDS stats block  */
  QWS10R1O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  if  QWS10R1O > 0 then
  do
    save_offset = offset
    offset = QWS10R1O - 4 + 1
    call DSNDQXST
    offset = save_offset
  end
  else
  do
    call DSNDQXST0
  end
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQTST */
  /*  nbre de bind, nbre de plan allocated succ ... */
  QWS10R2O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  save_offset = offset
  offset = QWS10R2O - 4 + 1
  call DSNDQTST
  offset = save_offset
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQBST */
  /*  Buffer manager stats                          */
  QWS10R3O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 6
  QWS10r3N = C2D(SUBSTR(INPUT_REC,OFFSET,2))
  OFFSET = OFFSET + 2
  /* decode dsndqbst to have  buffer stats */
  Sum_QBSTGET = 0
  Sum_QBSTRIO = 0
  Sum_QBSTIMW = 0
  Sum_QBSTDSO = 0
  Sum_QBSTWIO = 0
  Sum_QBSTRPI = 0
  Sum_QBSTWPI = 0
  Sum_QBSTPIO = 0
  Sum_QBSTMAX = 0
  Sum_QBSTWFD = 0
  Sum_QBSTWFF = 0
  Sum_QBSTCIO = 0
  Sum_QBSTDIO = 0
  Sum_QBSTLIO = 0
  Sum_QBSTSIO = 0
  if  QWS10R3O > 0 then
  do
      saveoffset= offset
      offset=QWS10R3O - 4 + 1
      /*add code here if need figures by bufferpool ID */
      m=0
      do until m= QWS10r3N
         m = m+ 1
         call dsndqbst
         Sum_QBSTGET = Sum_QBSTGET + QBSTGET
         Sum_QBSTRIO = Sum_QBSTRIO + QBSTRIO
         Sum_QBSTIMW = Sum_QBSTIMW + QBSTIMW
         Sum_QBSTDSO = Sum_QBSTDSO + QBSTDSO
         Sum_QBSTWIO = Sum_QBSTWIO + QBSTWIO
         Sum_QBSTRPI = Sum_QBSTRPI + QBSTRPI
         Sum_QBSTWPI = Sum_QBSTWPI + QBSTWPI
         Sum_QBSTPIO = Sum_QBSTPIO + QBSTPIO
         Sum_QBSTMAX = Sum_QBSTMAX + QBSTMAX
         Sum_QBSTWFD = Sum_QBSTWFD + QBSTWFD
         Sum_QBSTWFF = Sum_QBSTWFF + QBSTWFF
         Sum_QBSTCIO = Sum_QBSTCIO + QBSTCIO
         Sum_QBSTDIO = Sum_QBSTDIO + QBSTDIO
         Sum_QBSTLIO = Sum_QBSTLIO + QBSTLIO
         Sum_QBSTSIO = Sum_QBSTSIO + QBSTSIO
      end
      offset=saveoffset
  end

  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQIST */
  /*  Data   manager stats                          */
  QWS10R4O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 8
  /* decode dsnDQIST to have to Data manager stats */
  saveoffset= offset
  offset=QWS10R4O - 4 + 1
  call dsndqist
  offset=saveoffset
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQTXA */
  /*  Lock   manager stats                          */
  OFFSET = OFFSET + 8
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQISE */
  OFFSET = OFFSET + 8
  /*  OFFSET TO THE DATA SECTION MAPPED BY DSNDQBGL */
  /*  GBP Stats                                     */
  QWS10R7O = C2D(SUBSTR(INPUT_REC,OFFSET,4))
  OFFSET = OFFSET + 6
  QWS10R7N = C2D(SUBSTR(INPUT_REC,OFFSET,2))
  OFFSET = OFFSET + 2
  if  QWS10R7O > 0 then
  do
       save_offset = offset
       offset = QWS10R7O - 4 + 1
       m=0
       do until m= QWS10r7N
           m = m+ 1
           call DSNDQBGL
       end /* do until */
       offset = save_offset
  end  /* QWS10R7O > 0  */
  /*  (...)                                         */
  /*  Others sections - Check Rex100                */
  return

dsndqist:
    numeric digits 15
    offset  =  offset +4
    /* Fields of these macro seems to be all cumulative */
    /* calculate difference between interval */
    /* check QIEYE */
      if  SUBSTR(INPUT_REC,OFFSET,4) <> 'QIST' then
        do
              say 'Mapping error QIST eye catcher not found'
              exit(8)
        end

    offset = offset + 4
    /* RID Term RDS Limit */
    QISTRLLM = C2D(SUBSTR(INPUT_REC,offset,4))
    offset = offset + 4
    /* RID Term DM  Limit */
    QISTRPDM = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 20
    /* not optimal column proc Invalid Sproc */
    QISTCOLS = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 40
    /* 32KB Wrkfile used instead of 4KB */
    QISTWFP1 = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* 4 KB Wrkfile used instead of 32 KB */
    QISTWFP2 = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 28
    /* hwm storage used by workfiles in KB */
    offset = offset + 8
    /* Current all workfile usage in KB : DGTT and Sort */
    offset = offset + 8
    /* Current 4K wrkfile storage usage in KB*/
    QISTW4K  = C2D(SUBSTR(INPUT_REC,OFFSET,8))
    if QISTW4K > Max_QISTW4K then
          Max_QISTW4K = QISTW4K
    offset = offset + 8
    /* Current 32K wrkfile storage usage in KB*/
    QISTW32K = C2D(SUBSTR(INPUT_REC,OFFSET,8))
    if QISTW32K > Max_QISTW32K then
          Max_QISTW32K = QISTW32K
    offset = offset + 8
    /* Nb DM in memory   wrkfiles active currently */
    offset = offset + 8
    /* Space DM in memory active currently in KB*/
    offset = offset + 24
    /* Nb SRT in memory   wrkfiles active currently */
    offset = offset + 8
    /* Space SRT in memory active currently in bytes */
    offset = offset + 32
    /* Current RID blocks overflowed (stored) in wrkfiles*/
    offset = offset + 8
    /* Current NON Sort related workfiles active */
    offset = offset + 16
    /* Physical  workfiles created */
    offset = offset + 24
    /* HWM wkfile storage used by an agent */
    QISTAMXU =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 8
    /* Current storage configured for wkfiles*/
    offset = offset + 8
    /* Current DGTT  configured for wkfile KB*/
    offset = offset + 8
    /* Current DGTT  used  KB*/
    offset = offset + 8
    /* HWM     DGTT  used  KB*/
    QISTDGTTMXU = C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 8
    /* Current others  configured for wkfile KB*/
    offset = offset + 8
    /* Current others used  KB*/
    offset = offset + 8
    /* HWM    others used KB*/
    QISTWFMXU = C2D(SUBSTR(INPUT_REC,OFFSET,8))
    return
/* MAP STANDARD HEADER PRODUCT SECTION */
DSNDQWHS:
  OFFSET = OFFSET + 2
  QWHSTYP = C2D(SUBSTR(INPUT_REC,OFFSET,1))
  OFFSET = OFFSET + 2
  /* QWHSIID DS XL2 IFCID */
  QWHSIID = C2D(SUBSTR(INPUT_REC,OFFSET,2))
  IFCID=QWHSIID
  OFFSET = OFFSET + 2
  QWHSNSDA =C2D(SUBSTR(INPUT_REC,OFFSET,1))
  OFFSET = OFFSET + 6
  /* QWHSSSID DS CL4 SUBSYSTEM NAME */
  QWHSSSID = SUBSTR(INPUT_REC,OFFSET,4)
  OFFSET = OFFSET + 64
  /* TOTAL LENGTH = 76 */
  RETURN

/* STATISTICS CPU TIME MAPPING MACRO LG = 52*4*/
DSNDQWSA:
    numeric digits 15
    QWSAPROC =(SUBSTR(INPUT_REC,OFFSET,4))
    OFFSET = OFFSET + 4
    /*CONVERT INTO HEX VALUE*/
    QWSAEJST = C2X(SUBSTR(INPUT_REC,OFFSET,8))
    /*ELIMINATE 1.5 BYTES */
    QWSAEJST = X2D(SUBSTR(QWSAEJST,1,13))
    QWSAEJST = QWSAEJST/1000000
    OFFSET = OFFSET + 8

    QWSASRBT = C2X(SUBSTR(INPUT_REC,OFFSET,8))
    QWSASRBT = X2D(SUBSTR(QWSASRBT,1,13))
    QWSASRBT = QWSASRBT/1000000
    OFFSET = OFFSET + 16

    QWSAPSRB = C2X(SUBSTR(INPUT_REC,OFFSET,8))
    QWSAPSRB = X2D(SUBSTR(QWSAPSRB,1,13))
    QWSAPSRB = QWSAPSRB/1000000
    OFFSET = OFFSET + 8

    QWSAPSRB_Ziip = C2X(SUBSTR(INPUT_REC,OFFSET,8))
    QWSAPSRB_Ziip = X2D(SUBSTR(QWSAPSRB_Ziip,1,13))
    QWSAPSRB_Ziip = QWSAPSRB_Ziip/1000000
    OFFSET = OFFSET + 16

    Select
         When qwsaproc  = 'MSTR' Then do
                    MstrTcb      =QWSAEJST
                    MstrSrb      =QWSAsrbt
                    MstrpSRB     =QWSApsrb
                    MstrpSRB_Ziip=QWSApsrb_Ziip
                 end
         When qwsaproc  = 'DBM1' Then do
                    DBM1Tcb      =QWSAEJST
                    DBM1Srb      =QWSAsrbt
                    DBM1pSRB     =QWSApsrb
                    DBM1pSRB_Ziip=QWSApsrb_Ziip
                 end
         When qwsaproc  = 'DIST' Then do
                    DISTTcb      =QWSAEJST
                    DISTSrb      =QWSAsrbt
                    DISTpSRB     =QWSApsrb
                    DISTpSRB_Ziip=QWSApsrb_Ziip
                 end
         When qwsaproc  = 'IRLM' Then do
                    IRLMTcb      =QWSAEJST
                    IRLMSrb      =QWSAsrbt
                    IRLMpSRB     =QWSApsrb
                    IRLMpSRB_Ziip=QWSApsrb_Ziip
                 end
         Otherwise      do
                          say 'qwsaproc NOT correct' qwsaproc
                          exit 8
                        end
    end   /* select */
RETURN

DSNDQISE:
    /* EDMPOOL STATS */
    numeric digits 15
    /* Fields from IFCID002  : all cumulative */
    /* calculate difference between interval */

    /*# OF REQ FOR CT SECTIONS*/
    offset = offset + 8
    QISECTG = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF LOAD CT SECT FROM DASD*/
    offset = offset + 4
    QISECTL = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF REQUESTS FOR DBD*/
    offset = offset + 20
    QISEDBDG = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF LOAD DBD FROM DASD*/
    offset = offset + 4
    QISEDBDL = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF REQ FOR PT SECTIONS*/
    offset = offset + 4
    QISEKTG  = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF LOAD PT SECT FROM DASD*/
    offset = offset + 4
    QISEKTL = C2D(SUBSTR(INPUT_REC,offset,4))
    offset = offset + 12
    /*# OF Inserts  FOR DYN CACHE*/
    QISEDSI  = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF REQUESTS FOR DYN CACHE*/
    offset = offset +  4
    QISEDSG  = C2D(SUBSTR(INPUT_REC,offset,4))
    /*NUMBER OF PAGES IN DBD POOL*/
    offset = offset + 12
    QISEDPGE = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF FREE PG IN DBD FREE CHAIN*/
    offset = offset + 4
    QISEDFRE = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF FAIL DUE TO DBD POOL FULL*/
    offset = offset - 8
    QISEDFAL = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF PGS IN STMT POOL*/
    offset = offset + 20
    QISECPGE = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF FREE PG IN STMT FREE CHAIN*/
    offset = offset + 4
    QISECFRE = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF FAIL DUE TO STMT POOL FULL*/
    offset = offset - 8
    QISECFAL = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF PAGES IN SKEL EDM POOL*/
    offset = offset + 24
    QISEKPGE = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF FREE PG IN SKEL EDM POOL FREE CHAIN */
    offset = offset + 4
    QISEKFRE = C2D(SUBSTR(INPUT_REC,offset,4))
    /*# OF FAIL DUE TO STMT SKEL POOL FULL*/
    offset = offset - 8
    QISEKFAL = C2D(SUBSTR(INPUT_REC,offset,4))

return
DSNDQSST:
    offset= offset+4
    /* eye catcher */
    eyec     = SUBSTR(INPUT_REC,OFFSET,4)
    if ( eyec     <> 'QSST' ) then
                  do
                      say 'DSNDQSST eye catcher not met, error'
                      exit(8)
                  end
    offset= offset+4*14
    /* full storage contraction*/
    QSSTCONT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    QSSTCRIT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    QSSTABND = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
 return

DSNDQTST:
    /* Service Controler Stats */
    offset= offset+4
    /* eye catcher */
    eyec     = SUBSTR(INPUT_REC,OFFSET,4)
    if ( eyec     <> 'QTST' ) then
                  do
                      say 'DSNDQTST eye catcher not met, error'
                      exit(8)
                  end
    offset= offset+4*18
    /* Datasets opened */
    QTDSOPN  =  C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4*12
    /* DS closed by drain DSMax reached */
    QTDSDRN  =  C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* RWRO Convert */
    QTPCCT   =  C2D(SUBSTR(INPUT_REC,OFFSET,4))

 return
DSNDQ3ST:
    /* DB2 Subsystem services fields */
    offset= offset+4
    /* Signon, meaningful only with CICS or IMS */
    /* Nbr of signon for new user of an EXISTING thread*/
    /* If Signon > CrtThread then there is Thread reuse */
    Q3STSIGN = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* Create thread (does not include DBAT) */
    Q3STCTHD = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* Terminate     */
    Q3STTERM = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 8
    /* Commit1 */
    Q3STPREP = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* Commit2 */
    Q3STCOMM = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* Aborts */
    Q3STABRT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4*9
    /* HWM   IDBACK*/
    Q3STHWIB = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* HWM   IDFORE*/
    Q3STHWIF = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* HWM   CTHREAD*/
    Q3STHWCT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
 return

DSNDQJST:
    offset=offset+4
    /* eye catcher */
    eyec     = SUBSTR(INPUT_REC,OFFSET,4)
    if ( eyec     <> 'QJST' ) then
                  do
                      say 'DSNDQJST eye catcher not met, error'
                      exit(8)
                  end
    offset=offset+40
    /* active log output CI created */
    QJSTBFFL = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    return
DSNDQDST:
    if QWS00RCO = 0 then
    /* No DDF information */
      do
          say 'There is no DDF information in this trace'
          say ' '
          QDSTQDBT =0
          QDSTQCRT =0
          QDSTQCIT =0
          QDSTQMIT =0
          QDSTCNAT =0
          QDSTHWAT =0
          QDSTHWDT =0
          QDSTCIN2 =0
          QDSTMIN2 =0
          return
      end
    /* dbat queued */
    QDSTQDBT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 20 /* 4x 5 */
    /* dbat rejected condbat reached */
    QDSTQCRT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* current inact 1 */
    QDSTQCIT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* Max     inact 1 */
    QDSTQMIT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* curr pooled dbat : active and disconnect */
    QDSTCNAT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* Max  pooled dbat : active and disconnect */
    QDSTHWAT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* Max  dbat        : Max active + inact    */
    QDSTHWDT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 8
    /* cur inact 2        */
    QDSTCIN2 = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4
    /* Max inact 2        */
    QDSTMIN2 = C2D(SUBSTR(INPUT_REC,OFFSET,4))
    return


GET_FMT_TIME:
  Old_Hour = Hour
  RUN_HH = SM100TME % 360000
  RUN_HH = RIGHT(RUN_HH,2,'0')
  RUN_MIN = SM100TME % 6000 - RUN_HH*60
  RUN_MIN = RIGHT(RUN_MIN,2,'0')
  RUN_SEC = SM100TME % 100 - RUN_HH *3600 - RUN_MIN*60
  RUN_SEC = RIGHT(RUN_SEC,2,'0')
  RUN_FMT_TIME = RUN_HH!!':'!!RUN_MIN!!':'!!RUN_SEC
  Hour = left(run_fmt_time,2)
  /* Detect if we change hour */
  if Old_Hour <> Hour then Change_Hour=1
                      else Change_Hour=0
  RETURN


write_header:
  say 'CSV file ' oufl     ' will be produced'
  queue "Lpar,ssid,date,dow,Hour,MstrTCB,MstrSRB,MstrPSRB,"!!,
         "MstrPSRB_Ziip,Dbm1TCB,DBm1SRB,DBm1PSRB,Dbm1PSRB_Ziip,"!!,
                       "IrlmTCB,IrlmSRB,IrlmPSRB,IrlmPSRB_Ziip,"!!,
                       "DistTCB,DistSRB,DistPSRB,DistPSRB_Ziip,"!!,
         "CrtThd,Sign,Term,Comm1,Comm2,Abort,MaxIDBACK,"!!,
         "MaxIDFOR,CThread,"!!,
         "Chkpt,"!!,
         "MaxDSCur,DSClose,DSOpen,"!!,
         "ROSwitch,"!!,
                       "Getpage,Syncio,SyncWr,AsyncWr,"!!,
                       "PageInR,PageInW,"!!,
                       "SPrefIO,CastIO,DynPrfIO,LstPrfIO,BpSio,"!!,
         "MaxInac1,MaxActDbat,MaxAllDbat,"!!,
         "MaxDbat,"!!,
         "MaxAldThds,ThdMaxComp,ThdMaxComp2,"!!,
         "MaxRealUsedDB2,MaxAuxUsedDB2,MinRealAvail,"!!,
         "MaxExtRegion,Min31Avail,"!!,
         "NotOptColProc,32KbUsed4Prf,4KbUsed32Prf,"!!,
    ,/* Logging */
         "ActLogCI," !!,
    ,/* Workfile usage  */
         "Max4KwfMB,Max32KWfMB,MaxWfUseThdMB," !!,
         "MaxDGTTMB,MaxOthMB"
     /*  Zones below correspond to the ibm provided excel columns */
     /*  "Z,BE,CV,CX,CZ,CU,CW,CY,CQ,Y,BD"  */

  "EXECIO" queued() "DISKW OUFL"
  return


write_report:
    /* summarize or Max min to report only by hour */
   /* pas de rupture pour le 1er record lu */
   if rupture = 0
   then do
       rupture=1
       call init_summary
   end
   /* We change hour, start write */

   if   Change_Hour
   then do
       call write_summary
       call init_summary
   end
   else do
   /* if same hour, continue the sum */
       sum_MstrTcb      = sum_MstrTcb + dif_MstrTcb
       sum_MstrSrb      = sum_MstrSrb + dif_MstrSrb
       sum_MstrpSRB     = sum_MstrpSRB + dif_MstrpSRB
       sum_MstrpSRB_Ziip = sum_MstrpSRB_Ziip + dif_MstrpSRB_Ziip
       sum_dbm1Tcb      = sum_dbm1Tcb + dif_dbm1Tcb
       sum_dbm1Srb      = sum_dbm1Srb + dif_dbm1Srb
       sum_dbm1pSRB     = sum_dbm1pSRB + dif_dbm1pSRB
       sum_dbm1pSRB_Ziip = sum_dbm1pSRB_Ziip + dif_dbm1pSRB_Ziip
       sum_IrlmTcb      = sum_IrlmTcb + dif_IrlmTcb
       sum_IrlmSrb      = sum_IrlmSrb + dif_IrlmSrb
       sum_IrlmpSRB     = sum_IrlmpSRB + dif_IrlmpSRB
       sum_IrlmpSRB_Ziip = sum_IrlmpSRB_Ziip + dif_IrlmpSRB_Ziip
       sum_DistTcb   = sum_DistTcb + dif_DistTcb
       sum_DistSrb   = sum_DistSrb + dif_DistSrb
       sum_DistpSRB  = sum_DistpSRB+ dif_DistpSRB
       sum_DistpSRB_Ziip = sum_DistpSRB_Ziip+ dif_DistpSRB_Ziip
       sum_Q3STCTHD  = sum_Q3STCTHD + dif_Q3STCTHD /* cr threads*/
       sum_Q3STSIGN  = sum_Q3STSIGN + dif_Q3STSIGN /* Signon  */
       sum_Q3STTERM  = sum_Q3STTERM + dif_Q3STTERM /* Terminate*/
       sum_Q3STPREP  = sum_Q3STPREP + dif_Q3STPREP /* commit ph1*/
       sum_Q3STCOMM  = sum_Q3STCOMM + dif_Q3STCOMM /* Commit Ph 2*/
       sum_Q3STABRT  = sum_Q3STABRT + dif_Q3STABRT /* Aborts */
       if  Q3STHWIB > Max_Q3STHWIB  then     /* Max IDBACK */
           Max_Q3STHWIB = Q3STHWIB
       if  Q3STHWIF > Max_Q3STHWIF  then     /* Max IDFORE */
           Max_Q3STHWIF = Q3STHWIF
       if  Q3STHWCT > Max_Q3STHWCT  then     /* Max IDFORE */
           Max_Q3STHWCT = Q3STHWCT
       if  QTDSOPN  > Max_QTDSOPN   then     /* Max DS Opened*/
           Max_QTDSOPN  = QTDSOPN
       Sum_QXSTFND = Sum_QXSTFND + dif_QXSTFND   /* Full prepare*/
       Sum_QXSTNFND= Sum_QXSTNFND+ dif_QXSTNFND
       Sum_QXSTIPRP= Sum_QXSTIPRP+ dif_QXSTIPRP
       Sum_QXSTNPRP= Sum_QXSTNPRP+ dif_QXSTNPRP
       Sum_QWSDCKPT= Sum_QWSDCKPT+ dif_QWSDCKPT  /* Checkpoints */
       Sum_QTDSDRN = Sum_QTDSDRN + dif_QTDSDRN   /* Drain Close */
       Sum_QTPCCT  = Sum_QTPCCT  + dif_QTPCCT    /* RWRO Switch */
       Sum2_QBSTDSO = Sum2_QBSTDSO + dif_QBSTDSO   /* Open DS*/
       sum2_QBSTGET = sum2_QBSTGET + dif_QBSTGET /* gp */
       sum2_QBSTRIO = sum2_QBSTRIO + dif_QBSTRIO /* sync read */
       sum2_QBSTIMW = sum2_QBSTIMW + dif_QBSTIMW /* Immed. write */
       sum2_QBSTWIO = sum2_QBSTWIO + dif_QBSTWIO /* Async Write */
       sum2_QBSTRPI = sum2_QBSTRPI + dif_QBSTRPI /* Page IN Read*/
       sum2_QBSTWPI = sum2_QBSTWPI + dif_QBSTWPI /* Page In Writ*/
       sum2_QBSTPIO = sum2_QBSTPIO + dif_QBSTPIO /* Seq Pref. IO */
       sum2_QBSTMAX = sum2_QBSTMAX + dif_QBSTMAX /* Wrkfil no created*/
       sum2_QBSTWFD = sum2_QBSTWFD + dif_QBSTWFD /* Wrkfil rejected*/
       sum2_QBSTWFF = sum2_QBSTWFF + dif_QBSTWFF /* merge pass degrad*/
       sum2_QBSTCIO = sum2_QBSTCIO + dif_QBSTCIO /* Castout IO */
       sum2_QBSTDIO = sum2_QBSTDIO + dif_QBSTDIO /* Dyn Pr IO */
       sum2_QBSTLIO = sum2_QBSTLIO + dif_QBSTLIO /* Lst Pr IO */
       sum2_QBSTSIO = sum2_QBSTSIO + dif_QBSTSIO /* SIO */
       if  QDSTQMIT > Max_QDSTQMIT  then     /* Max inact type1*/
           Max_QDSTQMIT = QDSTQMIT
       if  QDSTHWAT > Max_QDSTHWAT  then     /* Max act dbat */
           Max_QDSTHWAT = QDSTHWAT
       if  QDSTHWDT > Max_QDSTHWDT  then     /* Max act&inact dbat*/
           Max_QDSTHWDT = QDSTHWDT
       if  QDSTMIN2 > Max_QDSTMIN2  then     /* Max  dbat*/
           Max_QDSTMIN2 = QDSTMIN2
       if  QW0225AT > Max_QW0225AT  then     /* Max allied threads*/
           Max_QW0225AT = QW0225AT
       if  ThdComp  < min_ThdComp   then     /* Max thread computed*/
           min_Thdcomp  = Thdcomp
       if  ThdComp2 < min_ThdComp2  then  /* Max thread computed*/
           min_Thdcomp2 = Thdcomp2
       if  TotalRealUsedByDB2 > Max_TotalRealUsedByDB2 then
           Max_TotalRealUsedByDB2 = TotalRealUsedByDB2
       if  TotalAuxlUsedByDB2 > Max_TotalAuxlUsedByDB2 then
           Max_TotalAuxlUsedByDB2 = TotalAuxlUsedByDB2
       if  QW0225_REALAVAIL   < min_QW0225_REALAVAIL then
           min_QW0225_REALAVAIL = QW0225_REALAVAIL
       if  QW0225RG    > Max_QW0225RG then
           Max_QW0225RG         = QW0225RG /* Region Size extended */
       if  QW0225AV    < Min_QW0225AV then /* 31 bits available */
          Min_QW0225AV         = QW0225AV
       sum_QISTCOLS= Sum_QISTCOLS+ dif_QISTCOLS /* Cols not optimized*/
       sum_QISTWFP1= Sum_QISTWFP1+ dif_QISTWFP1 /* 32KbUsed4Pref.*/
       sum_QISTWFP2= Sum_QISTWFP2+ dif_QISTWFP2 /* 4KbUsed32Prf*/
       sum_QJSTBFFL= Sum_QJSTBFFL+ dif_QJSTBFFL /* Log created*/
   end
   return
write_summary:
    /* write only if some records have been read between writes*/
    if RFlush= 0 ! ( RFlush=1 & recw<reci)  then nop
                      else return
    /* output counter */
    reco= reco+ 1
    recw= reci  /* we save when we write */
    /* Display some warnings */
    Call Check_counters
    /*rows in excel format */
    queue sm100sid !! ',' !! sm100ssi !! ','  ,
    !! '"' !! sm100dte !! '"' !! ','   ,
    !! dayoweek     !! ','   ,
    !! Old_Hour     !! ','   ,
    !! sum_MstrTcb      !! ','   ,
    !! sum_MstrSrb      !! ','   ,
    !! sum_MstrpSRB     !! ','   ,
    !! sum_MstrpSRB_Ziip !! ','   ,
    !! sum_dbm1Tcb      !! ','   ,
    !! sum_dbm1Srb      !! ','   ,
    !! sum_dbm1pSRB     !! ','   ,
    !! sum_dbm1pSRB_Ziip !! ','   ,
    !! sum_IrlmTcb      !! ','   ,
    !! sum_IrlmSrb      !! ','   ,
    !! sum_IrlmpSRB     !! ','   ,
    !! sum_IrlmpSRB_Ziip !! ','  ,
    !! sum_DistTcb      !! ','   ,
    !! sum_DistSrb      !! ','   ,
    !! sum_DistpSRB     !! ','     ,
    !! sum_DistpSRB_Ziip !! ','    ,
    !! sum_Q3STCTHD  !! ','        ,     /* Create Thd */
    !! sum_Q3STSIGN  !! ','        ,     /* Signon  */
    !! sum_Q3STTERM  !! ','        ,     /* Terminate*/
    !! sum_Q3STPREP  !! ','        ,     /* Commit phase 1 */
    !! sum_Q3STCOMM  !! ','        ,     /* Commit Ph 2*/
    !! sum_Q3STABRT  !! ','        ,     /* Aborts */
    !! Max_Q3STHWIB  !! ','        ,     /* Max IDBACK */
    !! Max_Q3STHWIF  !! ','        ,     /* Max IDFORE */
    !! Max_Q3STHWCT  !! ','        ,     /* Max CTHREAD */
    !! sum_QWSDCKPT  !! ','        ,     /* Checkpoints */
    !! Max_QTDSOPN   !! ','        ,     /* DS Opened   */
    !! sum_QTDSDRN   !! ','        ,     /* Drain Close */
    !! sum2_QBSTDSO  !! ','        ,     /* OPEN DS     */
    !! sum_QTPCCT    !! ','        ,     /* RWRO switch */
    !! sum2_QBSTGET   !! ','        ,
    !! sum2_QBSTRIO   !! ','        ,
    !! sum2_QBSTIMW   !! ','        ,
    !! sum2_QBSTWIO   !! ','        ,
    !! sum2_QBSTRPI   !! ','        , /*page in read */
    !! sum2_QBSTWPI   !! ','        ,
    !! sum2_QBSTPIO   !! ','        ,
    !! sum2_QBSTCIO   !! ','        ,
    !! sum2_QBSTDIO   !! ','        ,
    !! sum2_QBSTLIO   !! ','        ,
    !! sum2_QBSTSIO   !! ','        ,
    !! Max_QDSTQMIT      !! ','        ,     /* Max . inact type 1*/
    !! Max_QDSTHWAT      !! ','        ,     /* Max active dbat*/
    !! Max_QDSTHWDT      !! ','        ,     /* Max act & inact dbat */
    !! Max_QDSTMIN2      !! ','        ,     /* act dbat */
    !! Max_QW0225AT      !! ','        ,     /*  allied threads*/
    !! format(min_ThdComp ,4,0)   !! ',' ,
    !! format(min_ThdComp2,4,0)   !! ',' ,
    !! f2mb(Max_TotalRealUsedByDB2)     !! ',' ,
    !! f2mb(Max_TotalAuxlUsedByDB2)     !! ',' ,
    !! f2mb(min_QW0225_REALAVAIL)       !! ',' ,
    !! b2mb(Max_QW0225RG)               !! ',' ,
    !! b2mb(min_QW0225AV)               !! ',' , /* 31 bits avail*/
    !!         sum_QISTCOLS         !! ',' ,
    !!         sum_QISTWFP1         !! ',' ,
    !!         sum_QISTWFP2         !! ',' ,
    !!     sum_QJSTBFFL             !! ',' ,  /*Log created*/
    !!  trunc(Max_QISTW4K/1024)  !! ',' , /* Max MB 4K */
    !!  trunc(Max_QISTW32K/1024) !! ',' ,
    !!  trunc(QISTAMXU/1024)     !! ',' , /*Max MB wk used thread*/
    !!  trunc(QISTDGTTMXU/1024)  !! ',' , /* Max MB DGTT */
    !!  trunc(QISTWFMXU/1024)    !! ','   /* Max MB Other*/
   "EXECIO" queued() "DISKW OUFL"
return


/* SMF HEADER */
DSNDQWST:
   OFFSET = OFFSET + 1
   /* SM100RTY DS XL1 RECORD TYPE X'64' OR 100 */
   SM100RTY = C2D(SUBSTR(INPUT_REC,OFFSET,1))
   /* stop processing if not 100 */
   if sm100rty <> 100 then return
   OFFSET = OFFSET + 1
   /* SM100TME DS XL4 TIME SMF MOVED RECORD */
   SM100TME = C2D(SUBSTR(INPUT_REC,OFFSET,4))
   CALL GET_FMT_TIME
   OFFSET = OFFSET + 4
   field    = C2X(SUBSTR(INPUT_REC,OFFSET,4))
     parse value field with 1 . 2 c 3 yy 5 ddd 8 .
     if (c = 0) then
       yyyy = '19'!!yy
     else
       yyyy = '20'!!yy
   sm100dte    = yyyy!!'.'!!ddd
   /* get day of week : easier to select days */
   test_date = yyyy ddd
   sm100dte=DAT_MVS2SD(test_date)
   dayoweek = DAT_S2DOW(sm100dte)
   /* save date of smf records processed */
   if reco = 0 then save_date=sm100dte
   else do
     if save_date <> sm100dte & displ = 0 then do
        displ=1
        say 'There is 2 different dates in this SMF extract'
        say '             '  save_date sm100dte
        say ' '
     end
   end
   OFFSET = OFFSET + 4
   sm100sid = SUBSTR(INPUT_REC,OFFSET,4)
   OFFSET = OFFSET + 4
   /* SM100SSI DS CL4 SUBSYSTEM ID */
   sm100ssi = SUBSTR(INPUT_REC,OFFSET,4)
   OFFSET = OFFSET + 10
   /* TOTAL LENGTH = 28 */
RETURN


dsndqbst:
    numeric digits 15
    QBSTPID =  C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 8
    QBSTGET =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 8
    QBSTRIO =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 8
    offset = offset + 8*5
    QBSTWIO =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 16
    QBSTRPI =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 8
    QBSTWPI =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 8
    /* Open Dataset */
    QBSTDSO =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 8
    QBSTIMW =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 16
    /* Pages read seq Prefetch */
    QBSTSPP =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 56
    /* OF SEQ PREFETCH (ASYNCHRONOUS) READ*/
    QBSTPIO =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 16
    /* nb wkfile not created due to buffers resource */
    QBSTMAX =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 48
    /* nb of workfiles denied during sort/merge */
    QBSTWFD =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 8
    /* nb of time sort not optimized due to BP shortage*/
    QBSTWFF =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 40
    /* nb of cast out IO */
    QBSTCIO =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 8
    QBSTVPL =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 24
    /* save BP0 size - after 17:00 because i had time to modify */
    if lpar = 'SUD2' & Old_Hour > '17' then
    do
         if bp0_vpsize  = 0 then
         do
             if QBSTPID = 0 then do
                                 bp0_vpsize = QBSTVPL
                                 say  ssid 'BP0VPSIZE=' bp0_vpsize
                            end
         end
    end
    QBSTDIO =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 8
    QBSTLIO =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 16
    QBSTSIO =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    /*    say 'Buffid =' QBSTPID,     */
    /*        'QBSTGET=' QBSTGET,     */
    /*        'QBSTRIO=' QBSTRIO,     */
    /*        'QBSTWIO=' QBSTWIO,     */
    /*        'QBSTIMW=' QBSTIMW,     */
    /*    say 'QBSTPIO=' QBSTPIO,     */
    /*        'QBSTCIO=' QBSTCIO,     */
    /*        'QBSTDIO=' QBSTDIO,     */
    /*        'QBSTLIO=' QBSTLIO,     */
    /*        'QBSTSIO=' QBSTSIO      */
    offset = offset + 144 /* 8*18 */

    /*****************************/
    /* Processing the data read  */
    /*****************************/

    /* test if BufferID QBSTPIDis already recorded */
    i=1
    do while i <= nbBP
       if QBSTPID = BPList.i then leave
       i=i+1
    end
    if i >  nbBP then /* this BP is not recorded yet */
    do
        nbBP=nbBP+1
        BPList.nbBP=QBSTPID
        ListPrefLow.QBSTPID = 0
        /* First entry is  created with read value because */
        /* records are cumulative (from yesterday value for example*/
        Old_QBSTSPP.QBSTPID=QBSTSPP
        Old_QBSTPIO.QBSTPID=QBSTPIO
    end

    /* Processing counters to report */
    Dif_QBSTSPP.QBSTPID = QBSTSPP  - Old_QBSTSPP.QBSTPID
    Dif_QBSTPIO.QBSTPID = QBSTPIO  - Old_QBSTPIO.QBSTPID
    Old_QBSTSPP.QBSTPID=QBSTSPP
    Old_QBSTPIO.QBSTPID=QBSTPIO
    /*******************************/
    /* Calculate prefetch quantity */
    /*******************************/
    /*say  Dif_QBSTSPP.QBSTPID  Dif_QBSTPIO.QBSTPID*/
    if  Dif_QBSTSPP.QBSTPID > 0 & Dif_QBSTPIO.QBSTPID > 0 then
    do
      PrefQty = trunc(Dif_QBSTSPP.QBSTPID/Dif_QBSTPIO.QBSTPID)
      if PrefQty <= 4 then do
         /*  temR=1
             rec.1= 'Prefetch Qty too low for BP ' QBSTPID,
                    sm100sid'/'sm100ssi '@'RUN_FMT_TIME PrefQty
                  call logW */
             ListPrefLow.QBSTPID = ListPrefLow.QBSTPID+1
        end
    end

    return
dsndqbgl:
    numeric digits 15
    /* Group BPID */
    QBGLGN  =  C2D(SUBSTR(INPUT_REC,OFFSET,4))
    offset = offset + 4+1+3
    offset = offset + 8*17
    /* Write requests failed no storage */
    QBGLWF  =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    offset = offset + 8*13
    /* Write requests failed no storage secondary GBP */
    QBGL2F  =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    /* Write Around */
    offset = offset + 8*17
    QBGLWA  =  C2D(SUBSTR(INPUT_REC,OFFSET,8))
    /* go to end of macro QBGL */
    offset = offset + 8 + 24

    /*****************************/
    /* Processing the data read  */
    /*****************************/

    /* test if BufferID QBGLGN is already recorded */
    i=1
    do while i <= nbGBP
       if QBGLGN = GBPList.i then leave
       i=i+1
    end
    if i >  nbGBP then /* this GBP is not recorded yet */
    do
        nbGBP=nbGBP+1
        GBPList.nbGBP=QBGLGN
        /* First entry is  created with read value because */
        /* records are cumulative (from yesterday value for example*/
        Old_QBGL2F.QBGLGN =QBGL2F
        Old_QBGLWF.QBGLGN =QBGLWF
        Old_QBGLWA.QBGLGN =QBGLWA
        SumHr_QBGLWF.QBGLGN = 0
        SumHr_QBGL2F.QBGLGN = 0
        SumHr_QBGLWA.QBGLGN = 0
    end

    /* Processing counters to report */
    Dif_QBGLWF.QBGLGN = QBGLWF - Old_QBGLWF.QBGLGN
    Dif_QBGL2F.QBGLGN = QBGL2F - Old_QBGL2F.QBGLGN
    Dif_QBGLWA.QBGLGN = QBGLWA - Old_QBGLWA.QBGLGN
    Old_QBGLWF.QBGLGN = QBGLWF
    Old_QBGL2F.QBGLGN = QBGL2F
    Old_QBGLWA.QBGLGN = QBGLWA
    if Dif_QBGLWA.QBGLGN > 0  then
      SumHr_QBGLWA.QBGLGN=SumHr_QBGLWA.QBGLGN+Dif_QBGLWA.QBGLGN
    if Dif_QBGL2F.QBGLGN > 0  then
      SumHr_QBGL2F.QBGLGN=SumHr_QBGL2F.QBGLGN+Dif_QBGL2F.QBGLGN
    if Dif_QBGLWF.QBGLGN > 0  then
      SumHr_QBGLWF.QBGLGN=SumHr_QBGLWF.QBGLGN+Dif_QBGLWF.QBGLGN

    return

ifcid_diff:
       /* Cumulative values, report only the difference */
       /* When diff is negative, this means that the value have been*/
       /* reset (Seen at DB2 restart , but probably also if they    */
       /* reach their Max)                                          */
              Dif_MstrTcb =       MstrTcb       - Old_MstrTcb
              Dif_MstrSrb =       MstrSrb       - Old_MstrSrb
              Dif_MstrpSRB=       MstrpSRB      - Old_MstrpSRB
              Dif_MstrpSRB_Ziip = MstrpSRB_Ziip - Old_MstrpSRB_Ziip
              Dif_dbm1Tcb =       dbm1Tcb       - Old_dbm1Tcb
              Dif_dbm1srb =       dbm1srb       - Old_dbm1srb
              Dif_dbm1pSRB=       dbm1pSRB      - Old_dbm1pSRB
              Dif_dbm1pSRB_Ziip = dbm1pSRB_Ziip - Old_dbm1pSRB_Ziip
              Dif_irlmTcb =       irlmTcb       - Old_irlmTcb
              Dif_irlmsrb =       irlmsrb       - Old_irlmsrb
              Dif_irlmpSRB=       irlmpSRB      - Old_irlmpSRB
              Dif_irlmpSRB_Ziip = irlmpSRB_Ziip - Old_irlmpSRB_Ziip
              Dif_distTcb =       distTcb       - Old_distTcb
              Dif_distsrb =       distsrb       - Old_distsrb
              Dif_distpSRB=       distpSRB      - Old_distpSRB
              Dif_distpSRB_Ziip = distpSRB_Ziip - Old_distpSRB_Ziip

        if    Dif_MstrTcb < 0 then
        do
              say '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
              say 'Cumulative fields reset, possible DB2 RECYCLE'
              say '      at' sm100dte run_fmt_time
              say '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
              say ''

              Dif_MstrTcb =       MstrTcb
              Dif_MstrSrb =       MstrSrb
              Dif_MstrpSRB=       MstrpSRB
              Dif_MstrpSRB_Ziip = MstrpSRB_Ziip
              Dif_dbm1Tcb =       dbm1Tcb
              Dif_dbm1srb =       dbm1srb
              Dif_dbm1pSRB=       dbm1pSRB
              Dif_dbm1pSRB_Ziip = dbm1pSRB_Ziip
              Dif_irlmTcb =       irlmTcb
              Dif_irlmsrb =       irlmsrb
              Dif_irlmpSRB=       irlmpSRB
              Dif_irlmpSRB_Ziip = irlmpSRB_Ziip
              Dif_distTcb =       distTcb
              Dif_distsrb =       distsrb
              Dif_distpSRB=       distpSRB
              Dif_distpSRB_Ziip = distpSRB_Ziip
        end
              Old_Mstrtcb =       Mstrtcb
              Old_MstrSrb =       MstrSrb
              Old_MstrpSRB=       MstrpSRB
              Old_MstrpSRB_Ziip = MstrpSRB_Ziip
              Old_dbm1Tcb =       dbm1Tcb
              Old_dbm1srb =       dbm1srb
              Old_dbm1pSRB=       dbm1pSRB
              Old_dbm1pSRB_Ziip = dbm1pSRB_Ziip
              Old_irlmTcb =       irlmTcb
              Old_irlmsrb =       irlmsrb
              Old_irlmpSRB=       irlmpSRB
              Old_irlmpSRB_Ziip = irlmpSRB_Ziip
              Old_distTcb =       distTcb
              Old_distsrb =       distsrb
              Old_distpSRB=       distpSRB
              Old_distpSRB_Ziip = distpSRB_Ziip

       /*********************************/
       /* Subsystem services stats Q3ST */
       /*********************************/
              Dif_Q3STSIGN =     Q3STSIGN-Old_Q3STSIGN
              Dif_Q3STTERM =     Q3STTERM-Old_Q3STTERM
              Dif_Q3STCTHD =     Q3STCTHD-Old_Q3STCTHD
              Dif_Q3STPREP =     Q3STPREP-Old_Q3STPREP
              Dif_Q3STCOMM =     Q3STCOMM-Old_Q3STCOMM
              Dif_Q3STABRT =     Q3STABRT-Old_Q3STABRT

          if  Dif_Q3STSIGN < 0 then
          do
              Dif_Q3STSIGN = Q3STSIGN
              Dif_Q3STTERM = Q3STTERM
              Dif_Q3STCTHD = Q3STCTHD
              Dif_Q3STPREP = Q3STPREP
              Dif_Q3STCOMM = Q3STCOMM
              Dif_Q3STABRT = Q3STABRT
          end

          Old_Q3STSIGN = Q3STSIGN
          Old_Q3STTERM = Q3STTERM
          Old_Q3STCTHD = Q3STCTHD
          Old_Q3STPREP = Q3STPREP
          Old_Q3STCOMM = Q3STCOMM
          Old_Q3STABRT = Q3STABRT

       /***************************/
       /* buffer pool stats       */
       /***************************/

              Dif_QBSTGET = Sum_QBSTGET-Old_QBSTGET
              Dif_QBSTRIO = Sum_QBSTRIO-Old_QBSTRIO
              Dif_QBSTDSO = Sum_QBSTDSO-Old_QBSTDSO
              Dif_QBSTIMW = Sum_QBSTIMW-Old_QBSTIMW
              Dif_QBSTWIO = Sum_QBSTWIO-Old_QBSTWIO
              Dif_QBSTRPI = Sum_QBSTRPI-Old_QBSTRPI
              Dif_QBSTWPI = Sum_QBSTWPI-Old_QBSTWPI
              Dif_QBSTPIO = Sum_QBSTPIO-Old_QBSTPIO
              Dif_QBSTMAX = Sum_QBSTMAX-Old_QBSTMAX
              Dif_QBSTWFD = Sum_QBSTWFD-Old_QBSTWFD
              Dif_QBSTWFF = Sum_QBSTWFF-Old_QBSTWFF
              Dif_QBSTCIO = Sum_QBSTCIO-Old_QBSTCIO
              Dif_QBSTDIO = Sum_QBSTDIO-Old_QBSTDIO
              Dif_QBSTlIO = Sum_QBSTlIO-Old_QBSTlIO
              Dif_QBSTsIO = Sum_QBSTsIO-Old_QBSTsIO

          if  Dif_QBSTGET < 0 then
          do
              Dif_QBSTGET = Sum_QBSTGET
              Dif_QBSTRIO = Sum_QBSTRIO
              Dif_QBSTDSO = Sum_QBSTDSO
              Dif_QBSTIMW = Sum_QBSTIMW
              Dif_QBSTWIO = Sum_QBSTWIO
              Dif_QBSTRPI = Sum_QBSTRPI
              Dif_QBSTWPI = Sum_QBSTWPI
              Dif_QBSTPIO = Sum_QBSTPIO
              Dif_QBSTMAX = Sum_QBSTMAX
              Dif_QBSTWFD = Sum_QBSTWFD
              Dif_QBSTWFF = Sum_QBSTWFF
              Dif_QBSTCIO = Sum_QBSTCIO
              Dif_QBSTDIO = Sum_QBSTDIO
              Dif_QBSTlIO = Sum_QBSTlIO
              Dif_QBSTsIO = Sum_QBSTsIO
          end
              Old_QBSTGET = Sum_QBSTGET
              Old_QBSTRIO = Sum_QBSTRIO
              Old_QBSTIMW = Sum_QBSTIMW
              Old_QBSTDSO = Sum_QBSTDSO
              Old_QBSTWIO = Sum_QBSTWIO
              Old_QBSTRPI = Sum_QBSTRPI
              Old_QBSTWPI = Sum_QBSTWPI
              Old_QBSTPIO = Sum_QBSTPIO
              Old_QBSTMAX = Sum_QBSTMAX
              Old_QBSTWFD = Sum_QBSTWFD
              Old_QBSTWFF = Sum_QBSTWFF
              Old_QBSTCIO = Sum_QBSTCIO
              Old_QBSTDIO = Sum_QBSTDIO
              Old_QBSTlIO = Sum_QBSTlIO
              Old_QBSTsIO = Sum_QBSTsIO

      /****************************************/
      /* dsndqjst Log  Manager stats IFCID 001*/
      /****************************************/
      Dif_QJSTBFFL = QJSTBFFL - Old_QJSTBFFL
      if  Dif_QJSTBFFL < 0 then
              Dif_QJSTBFFL = QJSTBFFL
      Old_QJSTBFFL = QJSTBFFL

      /****************************************/
      /* dsndqist Data Manager stats IFCID 002 */
      /****************************************/
              Dif_QTDSDRN  = QTDSDRN  - Old_QTDSDRN
              Dif_QTPCCT   = QTPCCT   - Old_QTPCCT
              Dif_QWSDCKPT = QWSDCKPT - Old_QWSDCKPT
              Dif_QXSTFND  = QXSTFND  - Old_QXSTFND
              Dif_QXSTNFND = QXSTNFND - Old_QXSTNFND
              Dif_QXSTIPRP = QXSTIPRP - Old_QXSTIPRP
              Dif_QXSTNPRP = QXSTNPRP - Old_QXSTNPRP

              Dif_QISTRPDM = QISTRPDM - Old_QISTRPDM
              Dif_QISTCOLS = QISTCOLS - Old_QISTCOLS
              Dif_QISTWFP1 = QISTWFP1 - Old_QISTWFP1
              Dif_QISTWFP2 = QISTWFP2 - Old_QISTWFP2

      if  Dif_QISTRLLM < 0 then
      do
              Dif_QTDSDRN  = QTDSDRN
              Dif_QTPCCT   = QTPCCT
              Dif_QWSDCKPT = QWSDCKPT
              Dif_QXSTFND  = QXSTFND
              Dif_QXSTNFND = QXSTNFND
              Dif_QXSTIPRP = QXSTIPRP
              Dif_QXSTNPRP = QXSTNPRP
              Dif_QISTRLLM = QISTRLLM
              Dif_QISTRPDM = QISTRPDM
              Dif_QISTCOLS = QISTCOLS
              Dif_QISTWFP1 = QISTWFP1
              Dif_QISTWFP2 = QISTWFP2
      end

              Old_QTDSDRN  = QTDSDRN
              Old_QTPCCT   = QTPCCT
              Old_QWSDCKPT = QWSDCKPT
              Old_QXSTFND  = QXSTFND
              Old_QXSTNFND = QXSTNFND
              Old_QXSTIPRP = QXSTIPRP
              Old_QXSTNPRP = QXSTNPRP
              Old_QISTRLLM = QISTRLLM
              Old_QISTRPDM = QISTRPDM
              Old_QISTCOLS = QISTCOLS
              Old_QISTWFP1 = QISTWFP1
              Old_QISTWFP2 = QISTWFP2

      return
DisplayVStor:
  if vsm='Y' & reco > 0 & lpar <> 'SUD2' then
  do
    rec.1= ' '; call LOGW ; rec.1= ' ' ; call LOGW
    rec.1= 'Threads observed Max : ' MaxThdSee 'at' MaxThdSeeDate,
                                                 MaxThdSeeTime
    call LOGW
    rec.1= '                 Min : ' MinThdSee 'at' MinThdSeeDate,
                                                 MinThdSeeTime
    call LOGW
    rec.1= ' '; call LOGW ; rec.1= ' ' ; call LOGW
    rec.1= 'Max Threads allowed projected with this period is : '
    call LOGW
    rec.1= '    ' floor(MinThdComp) 'at' MinThdCompDate MinThdCompTime,
        '/' floor(MaxThdComp) 'at' MaxThdCompDate MaxThdCompTime
    call LOGW
    rec.1= '    Formula without Min/Max applied : '
    call LOGW
    rec.1= '    ' floor(MinThdComp2) 'at' MinThdComp2Date MinThdComp2Time,
        '/' floor(MaxThdComp2) 'at' MaxThdComp2Date MaxThdComp2Time
    call LOGW
    rec.1= ' '
    call LOGW
    rec.1= 'DBM1, Max Real Storage is : ' format(MaxReal4K_dbm1,5,2),
        'MB at ' Date_MaxReal4K_dbm1 time_MaxReal4K_dbm1
    call LOGW
    rec.1= '                   Min is : ' ,
                             format(MinReal4K_dbm1,5,2) 'MB at ',
           Date_MinReal4K_dbm1 time_MinReal4K_dbm1
    call LOGW
    rec.1= 'DIST, Max Real Storage is : ' format(MaxReal4K_dist,5,2),
        'MB at ' Date_MaxReal4K_dist time_MaxReal4K_dist
    rec.1= '                   Min is : ' ,
                          format(MinReal4K_dist,5,2) 'MB at ',
         Date_MinReal4K_dist time_MinReal4K_dist
    call LOGW
    rec.1= ' '
    call LOGW
 /* rec.1= 'Max Real Storage used by LPAR :' MaxRealLPAR ' Frames --', */
 /*            f2mb(MaxRealLPAR)  ' in MB'                          */
 /* rec.1= '       at ' time_MaxRealLPAR                            */
    temp=MinQW0225_REALAVAIL*4096 / 1048576      /* in MB*/
    rec.1= 'Min Real Storage available for LPAR : ' MinQW0225_REALAVAIL,
                'Frames --' f2mb(MinQW0225_REALAVAIL) ' MB'
    call LOGW
    rec.1= '       at ' Date_MinQW0225_REALAVAIL time_MinQW0225_REALAVAIL
    call LOGW
    rec.1= ' '
    call LOGW
    rec.1= 'Max Aux Storage used by DB2  :' MaxDB2AuxUse ' Frames --',
           f2mb(MaxDB2AuxUse)        ' MB'
    call LOGW
    rec.1= '       at ' DateMaxDB2AuxUse timeMaxDB2AuxUse
    call LOGW
  end
return
init_var:
  if vsm='Y' then
      do
           MaxND=0
           MinAS=999999999999999
           MinTS=999999999999999
           MaxTF=0
           MaxThdSee =0
           MaxThdComp=0
           MaxThdComp2=0
           MinThdSee =999999999999999
           MinThdComp=999999999999999
           MinThdComp2=999999999999999
           MaxReal4K_dbm1=0
           MinReal4K_dbm1=999999999999999
           MaxReal4K_dist=0
           MinReal4K_dist=999999999999999
           MinQW0225_REALAVAIL=999999999999999
        /* MaxRealLPAR = 0 */
           MaxDB2AuxUse = -1
      end
  /* init counters */
  Old_QBSTGET = 0
  Old_QBSTRIO = 0
  Old_QTDSDRN = 0
  Old_QTPCCT  = 0
  Old_QWSDCKPT= 0
  Old_QXSTFND = 0
  Old_QXSTNFND= 0
  Old_QXSTIPRP= 0
  Old_QXSTNPRP= 0
  Old_QBSTDSO = 0
  Old_QBSTIMW = 0
  Old_QBSTWIO = 0
  Old_QBSTRPI = 0
  Old_QBSTWPI = 0
  Old_QBSTPIO = 0
  Old_QBSTMAX = 0
  Old_QBSTWFD = 0
  Old_QBSTWFF = 0
  Old_QBSTCIO = 0
  Old_QBSTDIO = 0
  Old_QBSTLIO = 0
  Old_QBSTSIO = 0

  Old_QJSTBFFL  = 0

  Old_QISTRLLM  = 0
  Old_QISTRPDM  = 0
  Old_QISTCOLS  = 0
  Old_QISTWFP1  = 0
  Old_QISTWFP2  = 0

  Old_Q3STSIGN = 0
  Old_Q3STTERM = 0
  Old_Q3STCTHD = 0
  Old_Q3STPREP = 0
  Old_Q3STCOMM = 0
  Old_Q3STABRT = 0


  Old_MstrTcb =       0
  Old_MstrSrb =       0
  Old_MstrpSRB=       0
  Old_MstrpSRB_Ziip = 0
  Old_dbm1Tcb =       0
  Old_dbm1srb =       0
  Old_dbm1pSRB=       0
  Old_dbm1pSRB_Ziip = 0
  Old_irlmTcb =       0
  Old_irlmsrb =       0
  Old_irlmpSRB=       0
  Old_irlmpSRB_Ziip = 0
  Old_distTcb =       0
  Old_distsrb =       0
  Old_distpSRB=       0
  Old_distpSRB_Ziip = 0


  /* compteurs input/output */
  reco= 0
  reci= 0
  recs= 0

  min_time ='26:00:00'
  Max_time ='ZZ:00:00'
  min_date ='20990101'
  Max_date ='19700101'
  return

FLOOR: procedure
parse arg F
return TRUNC(F) - (F < 0) * (F <> TRUNC(F))

CEIL: procedure
parse arg C
return TRUNC(C) + (C > 0) * (C <> TRUNC(C))
/* convert 4K frames to MB */
f2mb:
 arg num
 num = format(num*4/1024,,2)
 return num
/* convert bytes to MB */
b2mb:
 arg num
 num = format(num/1048576,,0)
 return num
/*========================================== */
/* Set SMF data set name , depending on lpar */
/*========================================== */
SetSmfDs:
  oufl = 'systmp.wsyngud.smfexta'
  Select
       When lpar  = 'SUD2' then
            do
                ssid='DBAP'
            end
       When lpar  = 'XX10' then
            do
                ssid='DB2B'
            end
       When lpar  = 'LIM'   then
            do
                ssid='DBP1'
            end
       When lpar  = 'CTR'   then
            do
                ssid='DB2I'
            end
       When lpar  = 'LIM2' then
            do
                ssid='DBP2'
            end /* end Lpar XX10 Sofinco */
       When lpar  = 'LIM3' then
            do
                ssid='DBP3'
            end /* end Lpar XX10 Sofinco */
       When lpar  = 'LIM4' then
            do
                ssid='DBP8'
            end /* end Lpar XX10 Sofinco */
       When lpar  = 'MVSA' then
            do
                ssid='DB2P'
            end /* end Lpar CRPP  */
       When lpar  = 'IPO4' then
            do
                ssid='DSN2'
            end /* end Lpar  Prod CACIB */
       When lpar  = 'ZPR1' then
            do
                ssid='DB2E'
            end /* end Lpar  Prod CASA  */
       When lpar  = 'PROD' then
            do
                clnt='CAAGIS'
            end /* end Lpar  Prod CAAG  */
       Otherwise
            do
               say 'Lpar not processed - End of program'
               exit(0)
            end
  end   /* End select */
  return
init_summary:
       sum_MstrTcb      = dif_MstrTcb
       sum_MstrSrb      = dif_MstrSrb
       sum_MstrpSRB     = dif_MstrpSRB
       sum_MstrpSRB_Ziip =  dif_MstrpSRB_Ziip
       sum_dbm1Tcb      = dif_dbm1Tcb
       sum_dbm1Srb      =  dif_dbm1Srb
       sum_dbm1pSRB     =  dif_dbm1pSRB
       sum_dbm1pSRB_Ziip = dif_dbm1pSRB_Ziip
       sum_IrlmTcb      =  dif_IrlmTcb
       sum_IrlmSrb      =  dif_IrlmSrb
       sum_IrlmpSRB     =  dif_IrlmpSRB
       sum_IrlmpSRB_Ziip =  dif_IrlmpSRB_Ziip
       sum_DistTcb   =  dif_DistTcb
       sum_DistSrb   =  dif_DistSrb
       sum_DistpSRB  =  dif_DistpSRB
       sum_DistpSRB_Ziip =  dif_DistpSRB_Ziip
       sum_Q3STCTHD  =  dif_Q3STCTHD /* cr threads*/
       sum_Q3STSIGN  =  dif_Q3STSIGN /* Signon  */
       sum_Q3STTERM  =  dif_Q3STTERM /* Terminate*/
       sum_Q3STPREP  =  dif_Q3STPREP /* commit ph1*/
       sum_Q3STCOMM  =  dif_Q3STCOMM /* Commit Ph 2*/
       sum_Q3STABRT  =  dif_Q3STABRT /* Aborts */
       Max_Q3STHWIB = Q3STHWIB
       Max_Q3STHWIF = Q3STHWIF
       Max_Q3STHWCT = Q3STHWCT
       Max_QTDSOPN  = QTDSOPN
       SUm_QWSDCKPT=  dif_QWSDCKPT  /* Checkpoints */
       SUm_QXSTFND =  dif_QXSTFND   /* Prepare     */
       SUm_QXSTNFND=  dif_QXSTNFND
       SUm_QXSTIPRP=  dif_QXSTIPRP
       SUm_QXSTNPRP=  dif_QXSTNPRP
       Sum_QTDSDRN =  dif_QTDSDRN   /* Drain Close */
       Sum_QTPCCT  =  dif_QTPCCT    /* RWRO switch */
       SUm2_QBSTDSO =  dif_QBSTDSO   /* Open DS*/
       sum2_QBSTGET = dif_QBSTGET /* gp */
       sum2_QBSTRIO = dif_QBSTRIO /* sync read */
       sum2_QBSTIMW = dif_QBSTIMW /* Immed. write */
       sum2_QBSTWIO = dif_QBSTWIO /* Async Write */
       sum2_QBSTRPI = dif_QBSTRPI /* Async Write */
       sum2_QBSTWPI = dif_QBSTWPI /* Async Write */
       sum2_QBSTPIO = dif_QBSTPIO /* Seq Pref. IO */
       sum2_QBSTMAX = dif_QBSTMAX
       sum2_QBSTWFD = dif_QBSTWFD
       sum2_QBSTWFF = dif_QBSTWFF
       sum2_QBSTCIO = dif_QBSTCIO /* Castout IO */
       sum2_QBSTDIO = dif_QBSTDIO /* Dyn Pr IO */
       sum2_QBSTLIO = dif_QBSTLIO /* Lst Pr IO */
       sum2_QBSTSIO = dif_QBSTSIO /* SIO */
       Max_QDSTQMIT = QDSTQMIT
       Max_QDSTHWAT = QDSTHWAT
       Max_QDSTHWDT = QDSTHWDT
       Max_QDSTMIN2 = QDSTMIN2
       Max_QW0225AT = QW0225AT
       min_Thdcomp  = Thdcomp
       min_Thdcomp2 = Thdcomp2
       Max_TotalRealUsedByDB2 = TotalRealUsedByDB2
       Max_TotalAuxlUsedByDB2 = TotalAuxlUsedByDB2
       min_QW0225_REALAVAIL = QW0225_REALAVAIL
       Max_QW0225RG         = QW0225RG /* Region Size extended */
       Min_QW0225AV         = QW0225AV
       sum_QISTCOLS=  dif_QISTCOLS /* Cols not optimized*/
       sum_QISTWFP1=  dif_QISTWFP1 /* 32KbUsed4Pref.*/
       sum_QISTWFP2=  dif_QISTWFP2 /* 4KbUsed32Prf*/
       sum_QJSTBFFL=  dif_QJSTBFFL /* Log created*/
  return
DSNDQWSD:
    /* Nbr of checkpoints cumulative value */
    QWSDCKPT = C2D(SUBSTR(INPUT_REC,OFFSET,4))
 return

Check_counters:
    /* Workfiles */
    if sum2_QBSTMAX > 0 then do
           temR=1
           rec.1= 'Workfile Not Created NoBuf QBSTMAX',
             sm100sid'/'sm100ssi '@'Old_Hour Sum2_QBSTMAX
           call logW
    end
    if sum2_QBSTWFD > 0 then do
           temR=1
           rec.1= 'Workfile Rejected NoBuf QBSTWFD',
             sm100sid'/'sm100ssi '@'Old_Hour Sum2_QBSTWFD
           call logW
    end
    if sum2_QBSTWFF > 0 then do
           temR=1
           rec.1= 'Merge Pass degraded Low Buf QBSTWFF',
             sm100sid'/'sm100ssi '@'Old_Hour Sum2_QBSTWFF
           call logW
    end
    /* Only for SUD2 */
    if lpar = 'SUD2'   then
    do
        SumBP_SUD2_all = sum2_QBSTGET + SumBP_SUD2_all
        /* record Max getpage */
        if  sum2_QBSTGET > Max_SUD2_gp then do
                Max_SUD2_gp = sum2_QBSTGET
                Max_SUD2_gp_hour = Old_Hour
            end
        /* record activity between 9-18 */
        if (Old_Hour > '08' & Old_Hour < '19') then
             do
               SumBP_SUD2 = sum2_QBSTGET + SumBP_SUD2
               if sum2_QBSTGET < 1000000 then,
                      SUD2_BpInact = SUD2_BpInact + 1
             end
        return
    end
    /* Global Dynamic Stmt cache hit ratio > 90% */
 /* Hit = Sum_QXSTFND / (Sum_QXSTFND+Sum_QXSTNFND + 0.01)
    if Hit < 0.90 then
             do
               rec.1= 'Warning : Global Dyn. Cache Hit < 90%',
                  format(Hit,3,2) ' @' run_fmt_time
               call logw
               retcode=4
             end
    /* Local  Dynamic Stmt cache hit ratio > 70% */
    /* Source Optimizing DB2 System Performance using db2 statistics*/
    Hit = Sum_QXSTNPRP/ (Sum_QXSTNPRP + Sum_QXSTIPRP + 0.01)
    if Hit = 0   then do
           if tsaylocal=0 then do
             rec.1= 'Warning : Local Dyn. Cache probably not used'
             call LOgw
             tsayLocal = 1
           end
    end
    else if Hit < 0.70 then
             do
               rec.1= 'Warning : Local Dyn. Cache Hit < 70%',
                  format(Hit,3,2) ' @' run_fmt_time
               call logw
               retcode=4
             end
    */
    if (sum_dbm1Tcb*3) > sum_dbm1Srb & sum_dbm1Tcb > 100 then do
     rec.1= 'DBM1 TCB time too high vs DBM1 SRB ',
            'Hour/DBM1TCB/DBM1SRB ' Old_Hour sum_dbm1TCB sum_dbm1SRB
     call LOGW
    end

    if sum_QWSDCKPT > 13             then  do
     rec.1= 'Checkpoint frequency too high, Max should be 1/ 5mn',
            'Hour/Checkpoints '     Old_Hour sum_QWSDCKPT
     call LOGW
    end

    if sum_QTDSDRN  > 1 & sum_dbm1Tcb > 100 then do
     rec.1= 'DSMax reached ',
            'Hour/DrainClose '     Old_Hour sum_QTDSDRN
     call LOGW
    end

    if sum_QTPCCT   > 900 sum_dbm1Tcb > 100 then do
     rec.1= 'RWRO Switch too high (15/mn is ok)',
            'Hour/ROSwitch   '     Old_Hour sum_QTPCCT
     call LOGW
    end

    if (sum2_QBSTRPI + sum2_QBSTWPI) >  100 then do
     rec.1=   'Page In for RW observed ',
        'Hour/PageIn R/PageInWrite' Old_Hour sum2_QBSTRPI sum2_QBSTWPI
     call LOGW
    end

    /* Bypassed columns - Invalid Select Procedure */
    if (sum_QISTCOLS )               >  500 then do
     temR=1
     rec.1= 'Not optimized SProc observed',
        'Hour/Number              '  Old_Hour sum_QISTCOLS
     call LOGW
    end

    if (Max_QDSTMIN2+Max_QW0225AT)   >  min_ThdComp ! ,
       (Max_QDSTMIN2+Max_QW0225AT)   >  min_ThdComp2  then do
     rec.1= 'DBAT + AlliedThreads > Theoric Minimum Thread Number',
        'Hour/DBAT/Allied/min_ThdComp/min_ThdComp2 '
     call LOGW
     rec.1= Old_Hour Max_QDSTMIN2 Max_QW0225AT min_ThdComp min_ThdComp2
     call LOGW
    end
    /* GBP counters */
      h=1
      do while h <= nbGBP
         i = GBPList.h
         h=h+1
         if SumHr_QBGLWA.i> 0    then
             do
                temR=1
                rec.1= 'GBP' i 'Write Around happened',
                  sm100sid'/'sm100ssi '@'Old_Hour SumHr_QBGLWA.i
                call logW
             end
         if SumHr_QBGL2F.i> 0    then
             do
                temR=1
                rec.1= 'GBP' i 'Write SecGBP NoStorage',
                  sm100sid'/'sm100ssi '@'Old_Hour SumHr_QBGL2F.i
                call logW
             end
         if SumHr_QBGLWF.i > 0    then
             do
                temR=1
                rec.1= 'GBP' i 'Write GBP NoStorage',
                  sm100sid'/'sm100ssi '@'Old_Hour SumHr_QBGLWF.i
                call logW
             end

          SumHr_QBGLWF.i=0
          SumHr_QBGL2F.i=0
          SumHr_QBGLWA.i=0
      end  /* End do */

    return
LOGW:
     say rec.1
     if temR=0 then return /* No file report if not set */
     "EXECIO 1 DISKW OUFw  (STEM rec. "
     temR=0 /* No file report is the default */
     return
/* for SUD2 */
LOGW2:
     say rec.1
     "EXECIO 1 DISKW OUFs2 (STEM rec. "
    return
/* Report dataset on output */
CrOutput:
    ope = 1
    /* caagis ssid forced to some value */
    if clnt = 'CAAGIS' then
    do
          if sm100ssi = 'DBPR' ! sm100ssi = 'DBAP'  then
          do
              lpar='SUDM'
              ssid='DBPR'
          end
          if sm100ssi = 'DB2I' ! sm100ssi = 'DB2V'  then
          do
              lpar='SUDB'
              ssid='DB2I'
          end
    end
    oufL = "'" !! hlq !! '.reportS.' !! lpar !! '.' !! ssid !! "'"
      X=outtrap(tmp.)
      "DELETE" oufL "PURGE"
      X=outtrap(off)
    say 'Allocate' oufL
    /* if with header */
       OPT2 = 'H'
    if OPT2 = 'H' then
      "ALLOC FI(OUFL) DA("oufL") NEW CATALOG REUSE" ,
      "LRECL(900) RECFM(V B) TRACKS SPACE(15,15)"
    else
      "ALLOC FI(OUFL) DA("oufL") NEW CATALOG REUSE" ,
      "LRECL(500) RECFM(V B) TRACKS SPACE(15,15)"
    rcalloc = rc
    if rcalloc <> 0 then Do
         say "**********************************************"
         say "   Error allocating report file" rcalloc
         say "   Abnormal end  "
         say "**********************************************"
         Exit 8
    end
/* WRITE report header */
      OPT2 = 'H'
   if OPT2 = 'H' then
    CALL write_header
/* Report warning messages  */
oufw = "'" !! hlq !! '.reportsw.' !! lpar !!'.' !! ssid !! "'"
X=OUTTRAP(TMP.)
"DELETE" oufw "PURGE"
X=OUTTRAP(OFF)
"ALLOC FI(OUFw) DA("oufw") NEW CATALOG REUSE" ,
"LRECL(80) RECFM(F B) TRACKS SPACE(5,5) RELEASE"
rcalloc = rc
if rcalloc <> 0 then Do
     say "**********************************************"
     say "   Error allocating report warnings file" rcalloc
     say "   Abnormal end  "
     say "**********************************************"
     Exit 8
end

/* Only SUD2 report BP usage Generate ALTER BP command */
if lpar = 'SUD2' & temX=0 then
do
  temX=1
  oufs2= "'" !! hlq !! '.reportsw.alrt2' !! "'"
  say 'Output to' oufs2
  X=OUTTRAP(TMP.)
  "DELETE" oufs2 "PURGE"
  x=OUTTRAP(OFF)
  "ALLOC FI(OUFs2) DA("oufs2") NEW CATALOG REUSE" ,
  "LRECL(80) RECFM(F B) TRACKS SPACE(2,2) RELEASE"
  rcalloc = rc
  if rcalloc <> 0 then Do
    say "**********************************************"
    say "   Error allocating report warnings bp file" rcalloc
    say "   Abnormal end  "
    say "**********************************************"
    Exit 8
  end
end /* SUD2*/
rec.1= ' '
call logw
rec.1= '*** Processing for Subsys ***' ssid lpar
call logw
return
DSNDQXST:
    /*************************************************/
    /*  RDS STATISTICS BLOCK  DSNDQXST               */
    /*************************************************/
    /* Fields from IFCID002 : cumulative */
    /* calculate difference between interval */
    offset=offset+4
    /* eye catcher */
    eyec     = SUBSTR(INPUT_REC,OFFSET,4)
    if ( eyec     <> 'QXST' ) then
                  do
                      say 'offset=' offset
                      eyec = SUBSTR(INPUT_REC,1,100)
                      say 'eyec' eyec
                      say 'DSNDQXST eye catcher not met, error'
                      exit(8)
                  end
    offset  =  offset + 4
    /* Selects     */
    QXSELECT = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
    /* Inserts     */
    QXINSRT  = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
    /* Update      */
    QXUPDTE  = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
    /* Delete      */
    QXDELET  = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8 * 20
    /* Fetch       */
    QXFETCH  = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8 * 14
    /*---*/
    /*#RID List failed No storage */
    QXNSMIAP = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
    /*# Failed Limit exceeded */
    QXMRMIAP = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8*31
    /*# Short Prepare */
    QXSTFND  = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
    /*# Full  Prepare */
    QXSTNFND  = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
    /*# Implicit Prepare = FULL prepare */
    QXSTIPRP  = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
    /*# Avoided  Prepare */
    QXSTNPRP  = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
    /*# Stmt discarded - MaxKEEPD */
    QXSTDEXP  = C2D(SUBSTR(INPUT_REC,offset,8))
    /* (...) */
    offset  =  offset + 8*61
    /*# RID list Overflowed to Workfile No Storage */
    QXWFRIDS = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
    /*# RID list overflowed to wKk Limit Exceeded   */
    QXWFRIDT = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
    /*# RID list append for a hybrid join was interrupt No Storage*/
    QXHJINCS = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
    /*# RID list append for a hybrid join Limit exceeded*/
    QXHJINCT = C2D(SUBSTR(INPUT_REC,offset,8))
    offset  =  offset + 8
return
DSNDQXST0:
 /* say '!!! Record' reci 'no DSNDQXST data' */
    QXSELECT = 0
    QXINSRT  = 0
    QXUPDTE  = 0
    QXDELET  = 0
    QXFETCH  = 0
    QXNSMIAP = 0
    QXSTFND  = 0
    QXSTNFND = 0
    QXSTIPRP = 0
    QXSTNPRP = 0
    QXSTDEXP = 0
    QXWFRIDS = 0
    QXWFRIDT = 0
    QXHJINCS = 0
    QXHJINCT = 0
    QXMRMIAP = 0
return
/*-----------------------------------------*/
/* Specific for lpar SUD2 : Check BP usage */
/*-----------------------------------------*/
SUD2_report_bp_usage:
  /* report usage activity */
  rec.1= ' '
  call LOGW
  rec.1 = 'BP Usage report :'
  call LOGW
  /* compute average usage */
  SUD2avg_bp_all  = SumBP_SUD2 % 24
  rec.1 = ,
         'SUD2: ' ssid 'has BP inact - avg gp/h :' SUD2avg_bp_all
  call LOGW
  rec.1 = ,
         '              Max gp/h observed :' Max_SUD2_gp ' at ',
                                             Max_SUD2_gp_hour
  call LOGW
  rec.1 = ,
         '              avg gp/h office hours:' SUD2avg_bp
  call LOGW
  rec.1='  SUD2 avg getpage for 00:00-2359   :' SUD2avg_bp_all
  call logW
  SUD2avg_bp = SumBP_SUD2 % 10
  rec.1='  SUD2_BpInact hours from 9:00-18:00:' SUD2_BpInact
  call logW
  rec.1='  SUD2avg getpage during 9:00-18:00 :' SUD2avg_bp
  call logW
  /********************/
  /*  SET VPSIZE PART */
  /********************/

  /* important activity observed all day */
  if su2avg_bp_all > 2000000 &  bp0_vpsize < 55000 then
  do
        rec.1 ='BP probably small vs. observed activity, recommend :'
        call LOGW2
        rec.1 ='DSN SYSTEM('ssid')'
        call LOGW2
        rec.1 ='-ALTER BPOOL(BP0) VPSIZE(300000)'
        call LOGW2
        rec.1 ='-ALTER BPOOL(BP1) VPSIZE(100000)'
        call LOGW2
        return
  end

  /* Max gp/hour high at somes time => higher a little */
  if Max_SUD2_gp > 5000000 & bp0_vpsize < 55000 then
     do
        rec.1 ='DSN SYSTEM('ssid')'
        call LOGW2
        rec.1 ='-ALTER BPOOL(BP0) VPSIZE(100000)'
        call LOGW2
        return
     end
  /* Not enough activity */
  if Max_SUD2_gp < 5000000 & bp0_vpsize > 55000 then
     do
          rec.1 ='DSN SYSTEM('ssid')'
          call LOGW2
          rec.1 ='-ALTER BPOOL(BP0) VPSIZE(50000)'
          call LOGW2
          return
     end
return
/*---------------------------------------*/
/* Date functions from Chuck Meyer paper */
/*---------------------------------------*/
/* yyyymmdd => weekday */
DAT_S2DOW: Procedure
Parse Arg 1 yyyy +4 mm +2 dd +2 .
f = yyyy + (mm-14)%12
w = ((13*(mm+10-(mm+10)%13*12)-1)%5+dd+77 ,
+ 5 * (f - f%100*100)%4 + f%400 - f%100*2) //7
Return WORD('Sun Mon Tue Wed Thur Fri Sat',w+1)
/*---------------------*/
/* Is this leap year ? */
/*---------------------*/
LY?: Procedure
Parse Arg 1 y +4
Return ((y//4)=0)
/*---------------------*/
/* yyyyddd => yyyymmdd */
/*---------------------*/
DAT_MVS2SD: Procedure
Parse Value REVERSE(arg(1)) With 1 j +3 y
Parse Value REVERSE(j y) With y j
If LENGTH(y) = 2 Then y = YY2YYYY(y)
months = '31' (28 + LY?(y)) ,
'31 30 31 30 31 31 30 31 30 31'
Do m = 1 To 12 While j > WORD(months,m)
j = j - WORD(months,m)
End
Return RIGHT(y,4,0) !! RIGHT(m,2,0) !! RIGHT(j,2,0)
/********************************************/
/* Display list of BP with low Prefetch Qty */
/********************************************/
DisplayPref:
    temR=1
    rec.1= 'Lpar:' sm100sid  'SSID:' sm100ssi
    call logW
    temR=1
    rec.1= 'List of Bufferpols with a low Prefetch Quantity'
    call logW
    i=1
    do while i <= nbBP
       temR=1
       j=BPList.i
       rec.1= j ListPrefLow.j
       if  ListPrefLow.j > 0 then
                        call logW
       i=i+1
    end

Thursday, April 6, 2017

Rexx to decode IFCID 369 (Aggregate accounting statistics)

03/05/2021

Refresh this Rexx because i just used it to evaluate the impact of Asynchronous Duplexed Locking.
Very useful IFCID , should be better known. 
All the accounting figures grouped by Connection Type. 



6/10/2017
Update : Ziip figures and correction of bugs - validated figures with BMC Mainview Performance Reporter (V11 tested).
The first period recorded should be deleted (similar problem with all accumulated data: meaningful only if there is a figures for the start and the end period)

06/04/2017

There is a problem with this IFCID because all the presentations and even DB2 manuals or SDSNMACS and SDSNIVPD contents let think that this IFCID can be output to SMF. Which is wrong (maybe a bug ?) , because if you do -START TRACE(STAT) CLASS(9) DEST(SMF) , you will never find IFCID 369 in your SMF records ...
In fact, the only way to get it is with the READS commands.
Below is the code to do this. Just submit this Rexx, it will start the trace , read the contents of the OPx buffer every x minutes and then report the data in a report dataset.
Why IFCID369 is interesting ? You can have the same information by doing sums on your accounting report (Check my REX101 program)
IFCID369 is interesting on my site because there is too much accounting data that it has been decided that the accounting records from CICS are only kept from 9:00 to 10:00. This means that the only way to have some hints on the CPU on another period that is not 09:00 to 10:00 is to go to SMF30 and look at your  CICS STC  consumption. With IFCID369, i can have a lot of  accounting data, not all (the most interesting figure, the number of getpage, is not there !!! in fact everything reported by DSNDQWAC) on all period, in an aggregated version.


Have fun !

Duc

Follow this link on Github to get the Rexx 


Tuesday, December 6, 2016

An utility (Excel) to deal with dates from my execs

SMF data often gives dates in format of YYYY.nnn ,  (For example 2016.307 , corresponding to 02/11/2016), I am in general a bit lazy to transform this in my rexx ...
I use this Excel in my daily work to switch between "normal date" format and this YYYY.nnn format (there is a name for this, but no place in my litle brain to remember)

Here is the link to my Excel to do this :

 https://www.evernote.com/shard/s381/sh/cc820363-7867-4292-bba1-30f45b541ed7/a63aa3cdea70a145badf6b39d254896f

Saturday, October 15, 2016

There is no Guru

Don't believe in gurus ,  find your own truth.
And this is true , even with DB2.

I don't go to IDUG conferences anymore, because there is no "research"  presentations,  all of subjects are just an extract of of the manuals. Read them and the redbooks, you will save your money.

I dealt with DB2 performance for some time, for several customers, the technical presentations helped me a lot, but when we dig in, sometimes we need more things in depth, and the presentation contents is not enough specific. Most of the time, contents are copied from one to another ...
So every time i write to the authors,  i realised that a lot of them have never tested things that they claim ... if they reply to you.

In preference, guys from DB2 development team always reply, they love technology as you and i , and they love to spread their knowledge to the others.

The professional speakers are to take with care. Lot of them don't spend enough time in "the real world" and just relay something they have heard ...I've had some bad surprise in my career applying updates on blind faith because the presenter said it.