Black Hill Software

  • Home
  • Products
    • EasySMF
      • Release Notes and Latest Version
      • Online Manual
      • License Agreement
    • EasySMF:JE
      • EasySMF:JE Java Quickstart
      • Release Notes and Latest Version
      • Javadoc
      • EasySMF JSON Javadoc
      • License Agreement
    • 30 Day Trial
  • Purchase
    • How to Buy
    • Purchase a License
  • Support
    • EasySMF Support
    • Get the latest version of EasySMF
    • EasySMF:JE Support
    • Get the latest version of EasySMF:JE
  • News
  • Contact
    • Support
    • Sales

Java SMF Sample 3 : Performance Index

November 4, 2014 by Andrew

This sample illustrates the use of functions provided in the type 72 classes to calculate the WLM performance index and work with WLM Importances.

Calculation of the performance index can be complex, because it depends on the type of goal: velocity, average response time or percentile response time. Methods are provided in the ServiceReportClassPeriodDataSection class so you don’t have to do it yourself. The performance index can be calculated from single or multiple sections with the same goal. Methods are also provided to calculate velocity.

Processing

The sample program reads the SMF data and builds a list of service class intervals which have a performance index greater than 2. The list is sorted and grouped by system, time and importance, then listed by performance index and service class name.

Type 72 records can have multiple Service/Report Class Period Data sections. This is handled with nested for… loops. To get the sections we are interested in:

  1. Read the record.
  2. Check the type and subtype.
  3. Create the type 72 record.
  4. Skip report classes – we will only report service classes. workloadManagerControlSection().r723mrcl() tells us whether this record relates to a report class.
  5. Loop through the list of sections.
for (SmfRecord record : reader) 
{
    if (record.recordType() == 72 && record.subType() == 3) 
    {
        Smf72Record r72 = new Smf72Record(record);
        if (!r72.workloadManagerControlSection().r723mrcl())
        {
            for (ServiceReportClassPeriodDataSection section : 
                r72.serviceReportClassPeriodDataSections()) 
            {
                // process section...
            }
        }
    }
};

The ServiceClassPeriod class is used to hold information about the entries to be included in the report. The time value comes from the time the SMF record was written. SMF records from a single interval may not have exactly the same time, so we add 30 seconds and truncate the value to a minute value. This ensures that all entries have the same times and the grouping by time works correctly (assuming that all records are written within 30 seconds of the minute boundary).

private static class ServiceClassPeriod
{
    public ServiceClassPeriod(Smf72Record record,
            ServiceReportClassPeriodDataSection section)
    {
        system = record.system();
        // round to nearest minute
        time = record.smfDateTime().plusSeconds(30)
                .truncatedTo(ChronoUnit.MINUTES);
        name = record.workloadManagerControlSection().r723mcnm();
        period = section.r723cper();
        importance = section.importance();
        perfIndex = section.performanceIndex();
    }

    String system;
    LocalDateTime time;
    String name;
    int period;
    Importance importance;
    double perfIndex;
}

For each section we check the performance index, and add it to the list if the performance index is greater than 2.

For velocity goals we also check the amount of activity. Sometimes velocity goals show a high performance index simply because they are doing very little work and have very few using samples. In this case, if the using + delay sample count for a velocity goal is less than 5% of the number of times WLM ran its sampling, we ignore it as a low activity class. These numbers are very arbitrary – you might choose to change them, or not use them at all.

// if performance index > 2 and:
if (section.performanceIndex() > 2 &&
    // either not a velocity goal or
    //  using + delay is > 5% of total samples 
    (!section.r723cvel() || 
     section.r723ctot() + section.r723ctou()  
         > r72.workloadManagerControlSection().r723mtvNum() / 20)
    )
{
   highPI.add(new ServiceClassPeriod(r72, section));
}

We then sort the entries by the various criteria that we want to group by, then write group headers and detail lines.

The ServiceReportClassPeriodDataSection class returns the importance as an Importance enum. When comparing Importance enums Importance.SYSTEM is greater than Importance.DISCRETIONARY, which means that Importances 1-5 sort opposite to their numeric order i.e. Importance.I1 is greater than Importance.I5.

Importance.toString() returns the importance name for reporting, e.g. “1”, “Discretionary”.

Output

The output looks like the following:

SYSA

   1/10/14 12:45 AM
      Importance: 1
         TSO      Period 1 4.0
      Importance: 4
         DB2T     Period 1 2.6

   1/10/14 1:00 AM
      Importance: 4
         DB2T     Period 1 4.6</pre>

The Complete Program

import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import com.blackhillsoftware.smf.Importance;
import com.blackhillsoftware.smf.SmfRecord;
import com.blackhillsoftware.smf.SmfRecordReader;
import com.blackhillsoftware.smf.smf72.Smf72Record;
import com.blackhillsoftware.smf.smf72.subtype3.ServiceReportClassPeriodDataSection;

public class PerformanceIndex
{
    public static void main(String[] args) throws IOException
    {
        ArrayList<ServiceClassPeriod> highPI = new ArrayList<ServiceClassPeriod>();
        try (SmfRecordReader reader = 
                args.length == 0 ?
                SmfRecordReader.fromDD("INPUT") :
                SmfRecordReader.fromStream(new FileInputStream(args[0])))
        {
            for (SmfRecord record : reader)
            {
                if (record.recordType() == 72 && record.subType() == 3)
                {
                    Smf72Record r72 = new Smf72Record(record);

                    // skip report classes
                    if (!r72.workloadManagerControlSection().r723mrcl())
                    {
                        for (ServiceReportClassPeriodDataSection section : r72
                                .serviceReportClassPeriodDataSections())
                        {
                            // if performance index > 2 and:
                            if (section.performanceIndex() > 2
                                &&
                                // either not a velocity goal or
                                (!section.r723cvel() ||
                                // using + delay is > 5% of total samples
                                section.r723ctot() + section.r723ctou() > 
                                   r72.workloadManagerControlSection().r723mtvNum() / 20))
                            {
                                highPI.add(new ServiceClassPeriod(r72, section));
                            }
                        }
                    }
                }
            }
        }
        writeReport(highPI);
    }

    private static void writeReport(ArrayList<ServiceClassPeriod> highPI)
    {
        // Use custom comparator for complex sort order
        Collections.sort(highPI, new ServiceClassPeriodComparator());

        DateTimeFormatter timef = DateTimeFormatter.ISO_LOCAL_TIME;
        DateTimeFormatter datef = DateTimeFormatter.ISO_LOCAL_DATE;

        LocalDateTime currentTime = null;
        String currentSystem = null;
        Importance currentImportance = null;

        for (ServiceClassPeriod scInfo : highPI)
        {

            // group by System
            if (!scInfo.system.equals(currentSystem))
            {
                System.out.format("%n%s%n", scInfo.system);
                currentSystem = scInfo.system;
                currentTime = null;
                currentImportance = null;
            }
            if (!scInfo.time.equals(currentTime))
            {
                System.out.format("%n   %s %s%n", scInfo.time.format(datef),
                        scInfo.time.format(timef));
                currentTime = scInfo.time;
                currentImportance = null;
            }
            // Then by importance
            if (scInfo.importance != currentImportance)
            {
                System.out.format("      Importance: %s%n", scInfo.importance);
                currentImportance = scInfo.importance;
            }
            // detail line
            System.out.format("         %-8s Period %s %3.1f%n", scInfo.name,
                    scInfo.period, scInfo.perfIndex);
        }
    }

    /**
     *
     * Class to keep information about a service class period
     *
     */
    private static class ServiceClassPeriod
    {
        public ServiceClassPeriod(Smf72Record record,
                ServiceReportClassPeriodDataSection section)
        {
            system = record.system();
            // round to nearest minute
            time = record.smfDateTime().plusSeconds(30)
                    .truncatedTo(ChronoUnit.MINUTES);
            name = record.workloadManagerControlSection().r723mcnm();
            period = section.r723cper();
            importance = section.importance();
            perfIndex = section.performanceIndex();
        }

        String system;
        LocalDateTime time;
        String name;
        int period;
        Importance importance;
        double perfIndex;
    }

    /**
     * 
     * Comparator to implement custom sort order for report
     */
    private static class ServiceClassPeriodComparator implements
            Comparator<ServiceClassPeriod>
    {
        // sort by system,
        // then by time,
        // then by importance
        // then by performance index descending
        // finally by name and period
        public int compare(ServiceClassPeriod s1, ServiceClassPeriod s2)
        {
            int result = s1.system.compareTo(s2.system);
            if (result != 0)
                return result;
            result = s1.time.compareTo(s2.time);
            if (result != 0)
                return result;
            result = s2.importance.compareTo(s1.importance);
            if (result != 0)
                return result;
            // reversed to sort descending
            result = Double.compare(s2.perfIndex, s1.perfIndex);
            if (result != 0)
                return result;
            result = s1.name.compareTo(s2.name);
            if (result != 0)
                return result;
            result = Integer.compare(s1.period, s2.period);
            return result;
        }
    }
}

Filed Under: Java, Java SMF

30 Day Trial

EasySMF and EasySMF:JE are available for a free 30 day trial. Download now and start using them immediately.
30 Day Trial

Information

EasySMF:JE Java API for SMF Quickstart

EasySMF:JE Sample 1 : SMF Records by type and subtype

Systems Programmer Friendly Java

Sending Email from z/OS using Java

Sign up for EasySMF News

Stay up to date. Enter your email address to receive updates about EasySMF.
unsubscribe from list

Black Hill Software

Suite 10b, 28 University Drive, Mt Helen, VIC 3350, Australia
PO Box 2214, Bakery Hill, VIC 3354, Australia
+61 3 5331 8201
+1 (310) 634 9882
info@blackhillsoftware.com

News

  • Finding UID 0 work on z/OS using SMF Data
  • Apache Log4j CVE-2021-44228 Information
  • Java vs C++ : Drag Racing on z/OS

Twitter

My Tweets

Copyright © 2023 · Enterprise Pro Theme on Genesis Framework · WordPress · Log in