MainframeSupports
tip week 32/2013:

MVS has a component called SMF. SMF is basically a system similar to the MVS log, but a lot less accessible. Almost all products running under MVS write records to SMF. These records may contain any kind of information typically about the performance of the product, but it can also be about access to the system. Records having the same record layout are written to SMF using the same SMF-record type. The most commonly used SMF-record types and their layout are available at the Pacsys web-site.

One of the reasons that SMF-records are hard to access is that they are written as spanned records. Their record length may be up to 32756 bytes long. This format is no problem for products like DFSORT and especially SAS. It is mostly systems programmers who uses the contents of SMF-records and many of them uses SAS with the sole purpose of reading SMF-records. DFSORT does not function very well with SMF-records because it can only process information in fixed positions, but many SMF-record types has a layout where variable positions are used. Fortunately both COBOL and PLI can read spanned records and can also handle variable positions.

The first part of all SMF-records no matter which type has the same layout. Here you find information like the record type, the date, the time, the MVS-system and the subsystem. Use the Pacsys link for precise position and contents. In the rest of the SMF-record the format is free. To give you a good foundation for reading SMF-records I have written a PLI program which reads SMF type 101 records. This type of records are written by DB2 in almost infinite amounts. Type 101 records are typical for SMF-record types with variable positions. To locate the information you need to use a variety of offsets and this program shows you how to use two of them:

smf101: PROC(parm) OPTIONS(MAIN) ORDER;

DCL parm            CHAR(100) VAR;
DCL sysprint        FILE PRINT;
DCL accFile         FILE RECORD SEQUENTIAL;
DCL accFile_data    CHAR(114);
DCL smfFile         FILE RECORD SEQUENTIAL;
DCL smfFile_data    CHAR(32767) VAR;
DCL smfFile_eof     CHAR(1);
DCL maxRecords      FIXED BIN(31);
DCL smfDateChar     CHAR(4);
DCL smfTime         FIXED BIN(31);
DCL smfTimeChar     CHAR(4) BASED(addr(smfTime));
DCL timeFrst        FIXED BIN(31);
DCL timeLast        FIXED BIN(31);
DCL ifcid           FIXED BIN(15);
DCL ifcidPic        PIC'999';
DCL ifcidChar       CHAR(2) BASED(addr(ifcid));
DCL ssid            CHAR(4);
DCL corrname        CHAR(12);
DCL planname        CHAR(8);
DCL recordNo        FIXED BIN(31);
DCL productOfsChar  CHAR(2);
DCL productOfs      FIXED BIN(15) BASED(addr(productOfsChar));
DCL corrdataOfsChar CHAR(2);
DCL corrdataOfs     FIXED BIN(15) BASED(addr(corrdataOfsChar));
DCL putCount        FIXED BIN(31);

ON ENDFILE(smfFile) smfFile_eof = 'Y';

maxRecords = 100;
timeFrst = 10 * 360000;
timeLast = 14 * 360000;
recordNo = 0;
putCount = 0;
smfFile_eof = 'N';
OPEN FILE(smfFile);
READ FILE(smfFile) INTO(smfFile_data);
DO WHILE(smfFile_eof = 'N' & recordNo < maxRecords);
  recordNo = recordNo + 1;
  smfTimeChar = substr(smfFile_data, 3, 4);
  IF smfTime >= timeFrst & smfTime < timeLast
   & substr(smfFile_data, 2, 1) = '65'X
  THEN DO;
    smfDateChar = substr(smfFile_data, 7, 4);
    productOfsChar = substr(smfFile_data, 27, 2);
    productOfs = productOfs - 3;
    ifcidChar = substr(smfFile_data, productOfs + 4, 2);
    ssid = substr(smfFile_data, productOfs + 12, 4);
    corrdataOfsChar = substr(smfFile_data, productOfs, 2);
    corrdataOfs = productOfs + corrdataOfs;
    corrname = substr(smfFile_data, corrdataOfs + 12, 12);
    planname = substr(smfFile_data, corrdataOfs + 32, 8);
    ifcidPic = ifcid;
    CALL writeRec;
  END;
  READ FILE(smfFile) INTO(smfFile_data);
END;
CLOSE FILE(smfFile);
PUT SKIP LIST('Records read . : ' !! recordNo);
PUT SKIP LIST('Records written: ' !! putCount);

writeRec: PROC;

  IF putcount = 0
  THEN DO;
    accFile_data = 'IFC DATE SSID PLAN CORRELATION';
    WRITE FILE(accFile) FROM(accFile_data);
  END;
  accFile_data = ifcidPic !! ' ' !! smfDateChar !! ' ' !! ssid !! ' '
               !! planname !! ' ' !! corrname
               ;
  WRITE FILE(accFile) FROM(accFile_data);
  putcount = putcount + 1;

END writeRec;

END smf101;

The loop reading through the file containing SMF-records (smfFile) has an IF that limits the processing of records to type 101 ('65'X) written between 10am and 2pm. Within this IF I locate the offset to a socalled product section where the internal DB2-record type (ifcid) is located (among other information). In the product section there is yet another offset which points to a correlation section where information about the connection to DB2 is located, like the DB2 plan name and the correlation name.

Files containing SMF-records can be huge and are typically stored on tape. I/O within PLI is not especially fast compared to for instance DFSORT. It may be a good idea to filter the SMF-records using DFSORT before you start processing using PLI. For instance is it possible to code the IF selecting records for processing in the above program in DFSORT, because both the SMF-record type and the time are located in fixed positions.

Previous tip in english        Forrige danske tip        Tip list