org.miloss.fgsms.tests.ManualLoadTests.java Source code

Java tutorial

Introduction

Here is the source code for org.miloss.fgsms.tests.ManualLoadTests.java

Source

/**
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 * <p>
 * If it is not possible or desirable to put the notice in a particular file,
 * then You may include the notice in a location (such as a LICENSE file in a
 * relevant directory) where a recipient would be likely to look for such a
 * notice.
 * <p>
 * 
 */
/*  ---------------------------------------------------------------------------
 *  U.S. Government, Department of the Army
 *  Army Materiel Command
 *  Research Development Engineering Command
 *  Communications Electronics Research Development and Engineering Center
 *  ---------------------------------------------------------------------------
 */
package org.miloss.fgsms.tests;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.UUID;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.ws.BindingProvider;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.miloss.fgsms.agentcore.ConfigLoader;
import org.miloss.fgsms.agentcore.ConfigurationException;
import org.miloss.fgsms.agentcore.MessageProcessor;
import org.miloss.fgsms.common.IpAddressUtility;
import org.miloss.fgsms.common.Utility;
import org.miloss.fgsms.services.interfaces.common.PolicyType;
import org.miloss.fgsms.services.interfaces.common.SecurityWrapper;
import org.miloss.fgsms.services.interfaces.datacollector.AddDataRequestMsg;
import org.miloss.fgsms.services.interfaces.datacollector.DataCollectorService;
import org.miloss.fgsms.services.interfaces.policyconfiguration.AccessDeniedException;
import org.miloss.fgsms.services.interfaces.policyconfiguration.DeleteServicePolicyRequestMsg;
import org.miloss.fgsms.services.interfaces.policyconfiguration.PCS;
import org.miloss.fgsms.services.interfaces.policyconfiguration.ServiceUnavailableException;
import org.miloss.fgsms.services.interfaces.policyconfiguration.SetServicePolicyRequestMsg;
import org.miloss.fgsms.services.interfaces.policyconfiguration.TransactionalWebServicePolicy;

/**
 * The general idea here is to add tons of records to stress out the user
 * interface, hopefully not causing excessive delays.
 *
 * Although this class has existed for some time, it was never really given any
 * attention until post public release, jan 2017, when it was expanded to
 * primarily benchmark FGSMS Agent Core's {@link MessageProcessor} which handles
 * the majority of web service transaction logs. Performance of the
 * {@link MessageProcessor} has always been a struggle between memory usage and
 * thread management. This class exercises it under varying conditions and
 * tracks it's ability to transmit data. As a side effect, it also stresses the
 * FGSMS {@link DataCollectorService}, certain UI elements, the statistics
 * aggregator and more.
 *
 * @author AO
 * @since 7.0.0
 * @see MessageProcessor
 */
public class ManualLoadTests {
    private static boolean moreOutput = false;

    /**
     * main entry point
     *
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {

        System.out.println("Must run this as a user with global admin rights");
        // create Options object
        Options options = new Options();
        options.addOption("makePolicy", true, "Create N service policies");
        options.addOption("deletePolicy", true, "Delete N service policies");
        options.addOption("makePerformanceData", true, "Creates N service policies and X performance records each");
        options.addOption("records", true, "X performance records");
        options.addOption("pcs", true, "PCS Url override");
        options.addOption("username", true, "username override");
        options.addOption("password", true, "password override");
        options.addOption("highOutput", false, "prints additional information std out");

        CommandLineParser parser = new DefaultParser();
        CommandLine line = parser.parse(options, args);
        ManualLoadTests obj = new ManualLoadTests();

        obj.init(line.getOptionValue("pcs"), line.getOptionValue("username"), line.getOptionValue("password"),
                line.hasOption("highOutput"));
        try {
            if (line.hasOption("makePolicy")) {
                obj.createServicePolicies(Integer.parseInt(line.getOptionValue("makePolicy")));
            } else if (line.hasOption("makePerformanceData")) {
                obj.outputSystemProperties();

                obj.createPerfData(Integer.parseInt(line.getOptionValue("makePerformanceData")),
                        Integer.parseInt(line.getOptionValue("records")), "Run 1");
                //run it again but with smaller numbers to make sure the threads don't die
                obj.createPerfData(Integer.parseInt(line.getOptionValue("makePerformanceData")),
                        Integer.parseInt(line.getOptionValue("records")), "Run 2");
                obj.close();
            } else if (line.hasOption("deletePolicy")) {
                obj.killPolicies(Integer.parseInt(line.getOptionValue("deletePolicy")));
            } else {
                // automatically generate the help statement
                HelpFormatter formatter = new HelpFormatter();
                formatter.printHelp("fgsms.ManualLoadTests.jar", options);
            }
        } catch (OutOfMemoryError oom) {
            System.out.println(
                    "Out of memory! remaining items are aborted, will pause until the FGSMS agent queue is emptied");
        }
        while (MessageProcessor.getSingletonObject().outboundQueueSize() > 0) {
            Thread.sleep(1000);
            printQueueStats();
        }
    }

    private static void printQueueStats() {
        System.out.print("Outbound queue:" + MessageProcessor.getSingletonObject().outboundQueueSize());
        if (moreOutput) {
            System.out.print(" Current VM Memory : total = " + Runtime.getRuntime().totalMemory() + " free = "
                    + Runtime.getRuntime().freeMemory() + " " + percentFreeMemory());
        } else
            System.out.println();
    }

    private static double percentFreeMemory() {
        return (1d - ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory() + 0d)
                / Runtime.getRuntime().totalMemory())) * 100d;
    }

    BindingProvider bp;
    /**
     * agent config
     */
    ConfigLoader cfg = null;
    /**
     * endpoint to the PCS service, needed since
     */
    PCS pcsport = null;

    /**
     * the url prefix that will be associated with all this stuff we will
     * generate
     */
    String baseurl = IpAddressUtility.modifyURL("http://localhost:9999/LoadTestServiceX", false);
    BufferedWriter outputReport;

    public ManualLoadTests() throws ConfigurationException {
        if (cfg == null) {
            cfg = new ConfigLoader();
        }
        if (pcsport == null) {
            pcsport = cfg.getPcsport();
        }
        bp = (BindingProvider) pcsport;
        //initialize the output files
        File siteDir = new File("../../src/site/markdown/");
        if (siteDir.exists() && siteDir.isDirectory()) {
            //got it
            siteDir = new File(siteDir, "MessageProcessor-Java-Benchmark.md");
            open(siteDir);
            outputReportHeader();
            return;
        }
        siteDir = new File("../src/site/markdown");
        if (siteDir.exists() && siteDir.isDirectory()) {
            siteDir = new File(siteDir, "MessageProcessor-Java-Benchmark.md");
            open(siteDir);
            //got it
            outputReportHeader();
            return;
        }
        siteDir = new File("Benchmark.md");
        //give up and just use the current working directory
        open(siteDir);
        outputReportHeader();

    }

    public void outputSystemProperties() throws Exception {
        if (outputReport != null) {

            outputReport.write("## Test System Information: \n\n");
            outputReport.write("| Field | Value | \n");
            outputReport.write("| --- | --- | \n");
            outputReport.write("| CPU Cores | " + Runtime.getRuntime().availableProcessors() + " | \n");
            outputReport.write("| Max memory | " + Runtime.getRuntime().maxMemory() + " | \n");
            outputReport.write("| java.runtime.version | " + System.getProperty("java.runtime.version") + " | \n");
            outputReport.write("| os.name | " + System.getProperty("os.name") + " | \n");

            outputReport.write("\n");
        }
    }

    public float createPerfData(final int policyCount, final int iterations, final String header) throws Exception {

        if (outputReport != null) {

            outputReport.write("## " + header + "\n\n");
            outputReport.write("Input parameters: \n\n");
            outputReport.write("| Field | Value | \n");
            outputReport.write("| --- | --- | \n");
            outputReport.write("| Create X policies  | " + policyCount + " |\n");
            outputReport.write("| Create X transactions per policy | " + iterations + " | \n");
            outputReport.write("| DTG | " + Utility.formatDateTime(new Date()) + " |\n");
            outputReport.write("\n");
        }

        //assuming baseurl[0-n]
        long start = System.currentTimeMillis();
        createServicePolicies((policyCount));
        printQueueStats();
        if (outputReport != null) {
            outputReport.write("### Results \n\n");
            outputReport.write("| Test | Results | \n");
            outputReport.write("| --- | --- | \n");
            outputReport.write("| Policies created | " + (policyCount) + "|\n");
            outputReport.write("| Policy creation time | " + (System.currentTimeMillis() - start) + "ms |\n");
        }
        start = System.currentTimeMillis();
        for (int i = 0; i < policyCount; i++) {
            final int urlcount = i;
            System.out.println("Creating " + baseurl + urlcount);
            for (int k = 0; k < iterations; k++) {
                makeTransaction(baseurl + urlcount, k);
            }
            //TODO throttling based on JVM memory?
            printQueueStats();
        }
        if (outputReport != null) {
            outputReport.write("| Performances Records created | " + (iterations * policyCount) + "|\n");
            outputReport.write("| Policy creation time | " + (System.currentTimeMillis() - start) + "ms |\n");
        }

        long delta = System.currentTimeMillis() - start;
        System.out.println("Message generation complete in " + (delta));
        System.out.println(iterations + " " + policyCount + " " + delta);
        try {
            System.out.println("Message generation complete in " + (((iterations * policyCount)) / (delta / 1000))
                    + " msg/sec");
        } catch (Exception ex) {
        }
        while (MessageProcessor.getSingletonObject().outboundQueueSize() > 0) {
            Thread.sleep(1000);

            printQueueStats();
            //total to send - what's left = total sent
            try {
                System.out.println("Current rate " + ((((iterations * policyCount))
                        - MessageProcessor.getSingletonObject().outboundQueueSize())
                        / ((System.currentTimeMillis() - start) / 1000f)) + " msg/sec");
            } catch (Exception ex) {
            }
        }
        delta = System.currentTimeMillis() - start;
        System.out.println();

        double bottom = delta / 1000d;
        if (outputReport != null) {
            outputReport.write("| Data transmission time | " + delta + " ms | \n");
            if (bottom != 0d) {
                outputReport.write(
                        "| Data transmission rate | " + (((iterations * policyCount)) / bottom) + " msg/sec\n\n");
            } else {
                outputReport.write("| Data transmission rate | NaN\n\n");
            }
        }
        if (bottom != 0d) {
            return (float) (((iterations * policyCount)) / bottom);
        } else {
            return -1;
        }
    }

    public void makeTransaction(String url, int currentIteration) {
        MessageProcessor.getSingletonObject();
        AddDataRequestMsg msg = new AddDataRequestMsg();
        msg.setAction("testAction");
        msg.setAgentType("manualLoadTest");
        msg.setClassification(new SecurityWrapper());
        msg.setRecordedat(new GregorianCalendar());
        msg.setSuccess(true);
        msg.setRequestSize(100);
        msg.setResponseSize(100);
        msg.setRequestURI(url);
        msg.setServiceHost(Utility.getHostName());
        msg.setTransactionID(UUID.randomUUID().toString());
        msg.setURI(url);
        msg.setXmlRequest("testmessage");
        msg.setXmlResponse("testmessage");
        msg.setResponseTime((int) ((Math.random() * 1000)));

        MessageProcessor.getSingletonObject().processPreppedMessage(msg);

    }

    public void createServicePolicies(int count) throws Exception {
        long totaltime = 0;
        printQueueStats();
        for (int i = 0; i < count; i++) {
            System.out.println("Creating " + baseurl + i);
            long now = System.currentTimeMillis();
            setPolicy(baseurl + i);
            totaltime += System.currentTimeMillis() - now;
        }
        printQueueStats();
        System.out.println("took a total of " + totaltime + "ms or about " + ((double) totaltime / (double) count)
                + " ms on average");

    }

    public void setPolicy(String url) throws ConfigurationException, ServiceUnavailableException,
            AccessDeniedException, DatatypeConfigurationException {
        System.out.println("Setting up policy");
        TransactionalWebServicePolicy pol = new TransactionalWebServicePolicy();
        pol.setAgentsEnabled(true);
        pol.setBuellerEnabled(false);
        pol.setDataTTL(DatatypeFactory.newInstance().newDuration(600000));
        pol.setHealthStatusEnabled(false);
        pol.setMachineName(Utility.getHostName());
        pol.setPolicyType(PolicyType.TRANSACTIONAL);
        pol.setURL(url);
        SetServicePolicyRequestMsg req = new SetServicePolicyRequestMsg();
        req.setClassification(new SecurityWrapper());
        req.setURL(pol.getURL());
        req.setPolicy(pol);
        pcsport.setServicePolicy(req);
    }

    public void killPolicies(int count) throws Exception {

        if (outputReport != null) {

            outputReport.write("### Removing policies and data\n\n");
            outputReport.write("Input parameters: \n\n");
            outputReport.write("| Field | Value | \n");
            outputReport.write("| --- | --- | \n");
            outputReport.write("| Create X policies  | " + count + " |\n");
            outputReport.write("| DTG | " + Utility.formatDateTime(new Date()) + " |\n");

        }
        long start = System.currentTimeMillis();
        DeleteServicePolicyRequestMsg req = new DeleteServicePolicyRequestMsg();
        req.setClassification(new SecurityWrapper());
        req.setDeletePerformanceData(true);
        for (int i = 0; i < count; i++) {
            System.out.println("deleting " + baseurl + i);
            req.setURL(baseurl + i);
            pcsport.deleteServicePolicy(req);
        }
        start = System.currentTimeMillis() - start;
        if (outputReport != null) {
            outputReport.write("| Deletion time | " + start + " ms | \n");
            outputReport.write("| Deletion rate | " + (count / (start / 1000f)) + " policy+data/sec\n");
            outputReport.write("\n");
        }
    }

    private void open(File siteDir) {
        try {
            outputReport = new BufferedWriter(new FileWriter(siteDir));
        } catch (Exception ex) {

            outputReport = null;
        }
    }

    public void close() {
        if (outputReport != null) {
            try {
                outputReport.write("\n");
                outputReport.flush();
                outputReport.close();
            } catch (Exception ex) {
            }
        }
        outputReport = null;

    }

    private void outputReportHeader() {
        if (outputReport != null) {
            try {
                outputReport.write("# FGSMS Java Benchmark Report\n\n");
                outputReport.write("This covers load testing agains the following components\n\n");
                outputReport.write(" - Java Agent Core MessageProcess\n");
                outputReport.write(" - Java Server - Data Collector Service\n\n");
            } catch (IOException ex) {

            }
        }
    }

    public void init(String url, String username, String password, boolean moreOutput) {
        this.moreOutput = moreOutput;
        if (url != null) {
            bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url);
        } else {
            bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, cfg.getPCS_URLS().get(0));
        }

        if (username != null) {
            bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, username);
        } else {
            bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, cfg.getUsername());
        }

        if (password != null) {
            bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);
        } else {
            bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, Utility.DE(cfg.getPassword()));
        }

    }
}