/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.testing.framework; import java.io.*; import java.util.*; import org.eclipse.persistence.internal.helper.Helper; /** * Stores times for runs of tests vs base-line and computes averges/stats on these. * The baseline is the first value in the lists, followed by each test's value. */ public class PerformanceComparisonTestResult extends TestResult { public List testCounts; public List testAverages; public List testMaxs; public List testMins; public List testStandardDeviations; /** * Percentage differences between the performance comparisons. */ public List percentageDifferences; /** Records the average test count. */ public double averageTestCount; /** * The % difference between the current test average time and the * last successful run of the test on the baseline version. * Used for regression tests. */ protected double percentageDifferenceLastRun; /** * The % difference between the current test average time and the * average of the last 3 successful runs of the test on the baseline version. * Used for regression tests. */ protected double percentageDifferenceAverage; /** * The TopLink version that this test is comparing against. * This version defaults to the last test run, but can be set through the * System property toplink.loadbuild.baseline-version to another version such * as the last release. * Used for regression tests. */ protected String baselineVersion; /** * The up to 3 results for the current version. */ public List currentVersionResults; /** * The up to 3 results for the baseline version compared to. */ public List baselineVersionResults; /** * The regression baseline % standard deviation. */ public double baselineStandardDeviation; /** * The regression current % standard deviation. */ public double currentStandardDeviation; public PerformanceComparisonTestResult() { this.testCounts = new ArrayList(); this.testAverages = new ArrayList(); this.testMaxs = new ArrayList(); this.testMins = new ArrayList(); this.testStandardDeviations = new ArrayList(); this.percentageDifferences = new ArrayList(); this.currentVersionResults = new ArrayList(); this.baselineVersionResults = new ArrayList(); } public PerformanceComparisonTestResult(TestCase testCase) { super(testCase); this.testCounts = new ArrayList(); this.testAverages = new ArrayList(); this.testMaxs = new ArrayList(); this.testMins = new ArrayList(); this.testStandardDeviations = new ArrayList(); this.percentageDifferences = new ArrayList(); this.currentVersionResults = new ArrayList(); this.baselineVersionResults = new ArrayList(); } public PerformanceComparisonTestResult(TestCase testCase, String result) { super(testCase, result); this.testCounts = new ArrayList(); this.testAverages = new ArrayList(); this.testMaxs = new ArrayList(); this.testMins = new ArrayList(); this.testStandardDeviations = new ArrayList(); this.percentageDifferences = new ArrayList(); this.currentVersionResults = new ArrayList(); this.baselineVersionResults = new ArrayList(); } /** * Return the average test count. */ public double getAverageTestCount() { return averageTestCount; } /** * Set the average test count. */ public void setAverageTestCount(double averageTestCount) { this.averageTestCount = averageTestCount; // Also set this as the test time as this is what is stored in the db. this.testTime = (long)averageTestCount; } /** * Return the % difference between the current test average time and the * last successful run of the test on the baseline version. */ public double getPercentageDifferenceLastRun() { return percentageDifferenceLastRun; } /** * Return the & difference between the current test average time and the * average of the last 3 successful runs of the test on the baseline version. */ public double getPercentageDifferenceAverage() { return percentageDifferenceAverage; } /** * Return the TopLink version that this test is comparing against. * This version defaults to the last test run, but can be set through the * System property toplink.loadbuild.baseline-version to another version such * as the last release. */ public String getBaselineVersion() { return baselineVersion; } /** * Compute the test result averages and stand dev. */ public void computeResults() { for (int testIndex = 0; testIndex < getTestCounts().size(); testIndex++) { List times = (List)getTestCounts().get(testIndex); double testAverage = PerformanceComparisonTestResult.averageResults(times); double testStandardDeviation = PerformanceComparisonTestResult.standardDeviationResults(times); // Set the test average count as the test time. this.setAverageTestCount((long)testAverage); this.testAverages.add(new Double(testAverage)); this.testMins.add(PerformanceComparisonTestResult.minResults(times)); this.testMaxs.add(PerformanceComparisonTestResult.maxResults(times)); this.testStandardDeviations.add(new Double(testStandardDeviation)); if (testIndex > 0) { double testBaseLineAverage = ((Number)this.testAverages.get(0)).doubleValue(); // Difference double percentageDifference = PerformanceComparisonTestResult.percentageDifference(testAverage, testBaseLineAverage); this.percentageDifferences.add(new Double(percentageDifference)); } } } /** * Return the list of lists of test counts. */ public List getTestCounts() { return testCounts; } /** * Return the regression results from the current version run. */ public List getCurrentVersionResults() { return currentVersionResults; } /** * Return the regression results from the baseline runs. */ public List getBaselineVersionResults() { return baselineVersionResults; } /** * Add the test count for the test index. */ public void addTestCount(long time, int test) { if (getTestCounts().size() <= test) { getTestCounts().add(new ArrayList()); } ((List)getTestCounts().get(test)).add(new Long(time)); } /** * Always log the result for analysis. */ public boolean shouldLogResult() { return true; } /** * logs the result of the test on the print stream. */ public void logResult(Writer log) { String indentationString = getTestCase().getIndentationString(); try { if (hasError() || hasFatalError() || hasProblem()) { log.write(indentationString + "##FAILURE##" + Helper.cr()); } if (!getTestCounts().isEmpty()) { log.write(indentationString + "RUNS: " + ((List)getTestCounts().get(0)).size() + Helper.cr()); } for (int index = 0; index < getTestCounts().size(); index++) { PerformanceComparisonTest test = (PerformanceComparisonTest)this.testCase; log.write(Helper.cr()); if (index == 0) { log.write(indentationString + "BASE_LINE TEST" + Helper.cr()); } else { test = (PerformanceComparisonTest)test.getTests().get(index - 1); } log.write(indentationString + "TEST: " + test.getName() + Helper.cr()); log.write(indentationString + "TEST RUN TIME: " + (test.getTestRunTime() / 1000) + " seconds" + Helper.cr()); log.write(indentationString + "MEAN TEST COUNT: " + this.testAverages.get(index) + Helper.cr()); log.write(indentationString + "MAX TEST COUNT: " + this.testMaxs.get(index) + Helper.cr()); log.write(indentationString + "MIN TEST COUNT: " + this.testMins.get(index) + Helper.cr()); log.write(indentationString + "TEST % STANDARD DEVIATION: " + this.testStandardDeviations.get(index) + Helper.cr()); if (index > 0) { log.write(indentationString + "% DIFFERENCE: " + this.percentageDifferences.get(index - 1) + Helper.cr()); log.write(indentationString + "% DIFFERENCE ALLOWABLE: " + test.getAllowableDecrease() + Helper.cr()); } } if (getTestCase() instanceof PerformanceRegressionTest) { log.write(indentationString + "BASELINE VERSION: " + getBaselineVersion() + Helper.cr()); log.write(indentationString + "BASELINE VERSION RESULTS: " + getBaselineVersionResults() + Helper.cr()); log.write(indentationString + "BASELINE VERSION % STANDARD DEVIATION: " + this.baselineStandardDeviation + Helper.cr()); log.write(indentationString + "CURRENT VERSION RESULTS: " + this.getCurrentVersionResults() + Helper.cr()); log.write(indentationString + "CURRENT VERSION % STANDARD DEVIATION: " + this.currentStandardDeviation + Helper.cr()); log.write(indentationString + "% DIFFERENCE (last run): " + getPercentageDifferenceLastRun() + Helper.cr()); log.write(indentationString + "% DIFFERENCE (average): " + getPercentageDifferenceAverage() + Helper.cr()); } log.write(Helper.cr() + indentationString + "RESULT: " + getOutcome() + Helper.cr()); } catch (IOException exception) { // Ignore. } catch (ArrayIndexOutOfBoundsException exception) { // Ignore. } try { if (getException() != null) { getException().setIndentationString(indentationString); log.write(getException() + org.eclipse.persistence.internal.helper.Helper.cr()); } log.flush(); } catch (IOException exception) { } LoadBuildSystem.loadBuild.addResult(this); } /** * Compute the max of the results. */ public static Number maxResults(List times) { Number testMax = new Double(0); for (int index = 0; index < times.size(); index++) { Number time = (Number)times.get(index); if (time.doubleValue() > testMax.doubleValue()) { testMax = time; } } return testMax; } /** * Compute the min of the results. */ public static Number minResults(List times) { Number testMin = new Double(0); for (int index = 0; index < times.size(); index++) { Number time = (Number)times.get(index); if ((testMin.doubleValue() == 0) || (time.doubleValue() < testMin.doubleValue())) { testMin = time; } } return testMin; } /** * Filter max and min from results. */ public static List filterMaxMinResults(List times) { List filteredTimes = new ArrayList(times); if (filteredTimes.size() > 3) { filteredTimes.remove(maxResults(times)); filteredTimes.remove(minResults(times)); } return filteredTimes; } /** * Compute the average of the results rejecting the min and max. */ public static double averageResults(List allTimes) { // Compute the average reject the min and max to improve consistency. List times = filterMaxMinResults(allTimes); double testAverage = 0; for (int index = 0; index < times.size(); index++) { double time = ((Number)times.get(index)).doubleValue(); testAverage = testAverage + time; } testAverage = testAverage / times.size(); return testAverage; } /** * Compute the standard deviation of the results rejecting the min and max. */ public static double standardDeviationResults(List allTimes) { // Compute the average reject the min and max to improve consistency. double testAverage = averageResults(allTimes); // Compute the standard deviation reject the min and max to improve consistency. List times = filterMaxMinResults(allTimes); double testStandardDeviation = 0; for (int index = 0; index < times.size(); index++) { double time = ((Number)times.get(index)).doubleValue(); testStandardDeviation = testStandardDeviation + Math.pow(time - testAverage, 2); } testStandardDeviation = testStandardDeviation / times.size(); testStandardDeviation = Math.sqrt(testStandardDeviation); // As percent of average testStandardDeviation = (testStandardDeviation / testAverage) * 100; return testStandardDeviation; } /** * Compute the percentage difference between the values. */ public static double percentageDifference(double result, double baseline) { // Difference double percentageDifference = ((result - baseline) / baseline) * 100; // If negative calculate from the inverse spective to get a more meaningful result. if (percentageDifference < 0) { percentageDifference = -1 * ((baseline - result) / result) * 100; } return percentageDifference; } }