package org.keycloak.testsuite.performance; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; import org.keycloak.testsuite.performance.statistics.SimpleStatistics; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import static org.keycloak.testsuite.performance.PerformanceTest.LOG; import static org.keycloak.testsuite.util.IOUtil.PROJECT_BUILD_DIRECTORY; /** * * @author tkyjovsk */ public class PerformanceMeasurement { private final Date started; private final int load; private long durationMillis; private SimpleStatistics statistics; private SimpleStatistics timeoutStatistics; public static final DateFormat ISO8601_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXX"); // should be compatible with `date --iso-8601=seconds` public static final DateFormat RFC3339_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ"); // should be compatible with `date --rfc-3339=seconds` public PerformanceMeasurement(int load) { this.started = new Date(); this.load = load; } public SimpleStatistics getStatistics() { return this.statistics; } public SimpleStatistics getTimeoutStatistics() { return this.timeoutStatistics; } public void setStatistics(SimpleStatistics statistics, SimpleStatistics timeoutStatistics) { this.durationMillis = new Date().getTime() - started.getTime(); if (durationMillis < 0) { throw new IllegalStateException("Cannot set a negative duration."); } this.statistics = statistics; this.timeoutStatistics = timeoutStatistics; } private void checkStatisticsNotNull() { if (statistics == null || timeoutStatistics == null) { throw new IllegalStateException("Iteration doesn't have any statistics set."); } } public double getThroughput(String statistic) { checkStatisticsNotNull(); return (double) statistics.get(statistic).getCount() / durationMillis * 1000; } public double getTimeoutPercentage(String statistic) { checkStatisticsNotNull(); long timeouts = timeoutStatistics.containsKey(statistic) ? timeoutStatistics.get(statistic).getCount() : 0; return (double) timeouts / statistics.get(statistic).getCount(); } public static final Object[] HEADER = new String[]{ "Timestamp", "Load", "Duration", "Count", "Min", "Max", "Average", "Standard Deviation", "Timeout Percentage", "Throughput",}; public List toRecord(String statistic) { checkStatisticsNotNull(); List record = new ArrayList(); record.add(ISO8601_DATE_FORMAT.format(started)); record.add(load); record.add(durationMillis); record.add(statistics.get(statistic).getCount()); record.add(statistics.get(statistic).getMin()); record.add(statistics.get(statistic).getMax()); record.add(statistics.get(statistic).getAverage()); record.add(statistics.get(statistic).getStandardDeviation()); record.add(getTimeoutPercentage(statistic)); record.add(getThroughput(statistic)); return record; } public void printToCSV() { printToCSV(null); } public void printToCSV(String testName) { checkStatisticsNotNull(); for (String statistic : statistics.keySet()) { File csvFile = new File(PROJECT_BUILD_DIRECTORY + "/measurements" + (testName == null ? "" : "/" + testName), statistic + ".csv"); boolean csvFileCreated = false; if (!csvFile.exists()) { try { csvFile.getParentFile().mkdirs(); csvFileCreated = csvFile.createNewFile(); } catch (IOException ex) { throw new RuntimeException(ex); } } try (BufferedWriter writer = new BufferedWriter(new FileWriter(csvFile, true))) { CSVPrinter printer = new CSVPrinter(writer, CSVFormat.RFC4180); if (csvFileCreated) { printer.printRecord(HEADER); } printer.printRecord(toRecord(statistic)); printer.flush(); } catch (IOException ex) { throw new RuntimeException(ex); } } } public void printToLog() { LOG.info("Measurement results:"); LOG.info("Operation " + Arrays.toString(HEADER)); for (String statistic : statistics.keySet()) { LOG.info(statistic + " " + toRecord(statistic)); } } }