blob: 3688b26fd874ca888ed1dbf59ab3eedc83fc379a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.test.performance.ui;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import junit.framework.AssertionFailedError;
import org.eclipse.test.internal.performance.data.Dim;
import org.eclipse.test.internal.performance.db.Scenario;
import org.eclipse.test.internal.performance.db.TimeSeries;
import org.eclipse.test.performance.ui.Utils.ConfigDescriptor;
public class ScenarioResults {
private Scenario[] scenarios;
private String baseline;
private String baselinePrefix = null;
private String current;
private ArrayList pointsOfInterest;
private ArrayList buildIDStreamPatterns;
private Hashtable scenarioComments;
private Hashtable variabilityData;
private ConfigDescriptor configDescriptor;
/**
* Summary of results for a scenario for a given build compared to a
* reference.
*
* @param scenarios -
* the array of Scenario objects for which to generate results.
* @param reference -
* the reference build ID
* @param current -
* the current buildID
* @param configDescriptor -
* a ConfigDescriptor object.
* @param pointsOfInterest -
* an ArrayList of buildId's to highlight on line graphs.
*/
public ScenarioResults(Utils.ConfigDescriptor configDescriptor, Scenario[] scenarios, String baseline, String baselinePrefix, String current,
ArrayList pointsOfInterest, Hashtable scenarioComments, ArrayList buildIDPatterns, Hashtable variabilityTable) {
this.scenarios = scenarios;
this.baseline = baseline;
this.baselinePrefix = baselinePrefix;
this.pointsOfInterest = pointsOfInterest;
this.scenarioComments = scenarioComments;
this.configDescriptor=configDescriptor;
buildIDStreamPatterns=buildIDPatterns;
this.current = current;
variabilityData=variabilityTable;
printSummary();
printDetails();
}
private void printSummary() {
String outFile = null;
PrintStream ps = null;
for (int s = 0; s < scenarios.length; s++) {
ArrayList pointsOfInterest = new ArrayList();
Scenario t = scenarios[s];
// get latest points of interest matching
if (this.pointsOfInterest != null) {
Iterator iterator = this.pointsOfInterest.iterator();
while (iterator.hasNext()) {
String buildIdPattern = iterator.next().toString();
if (buildIdPattern.endsWith("*")) {
pointsOfInterest.addAll(getAllMatchingBuildIds(t, buildIdPattern.substring(0, buildIdPattern.length() - 1)));
} else {
String match = getMostRecentMatchingBuildID(t, buildIdPattern);
if (match != null)
pointsOfInterest.add(match);
}
}
}
int[] buildNameIndeces = { -1, -1 };
buildNameIndeces[0] = Utils.getBuildNameIndex(t.getTimeSeriesLabels(), current);
buildNameIndeces[1] = Utils.getBuildNameIndex(t.getTimeSeriesLabels(), baseline);
// don't produce result if none exists for current build
if (Utils.getBuildNameIndex(t.getTimeSeriesLabels(), current) == -1) {
continue;
}
String scenarioFileName = t.getScenarioName().replace('#', '.').replace(':', '_').replace('\\', '_');
outFile = configDescriptor.outputDir + "/" + scenarioFileName + ".html";
String rawDataFile=scenarioFileName+"_raw.html";
if (outFile != null) {
try {
new File(outFile).getParentFile().mkdirs();
ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(outFile)));
} catch (FileNotFoundException e) {
System.err.println("can't create output file" + outFile); //$NON-NLS-1$
}
}
if (ps == null)
ps = System.out;
ps.println(Utils.HTML_OPEN);
ps.println(Utils.HTML_DEFAULT_CSS);
ps.println("<title>" + t.getScenarioName() + "(" + configDescriptor.description + ")" + "</title></head>"); //$NON-NLS-1$
ps.println("<h4>Scenario: " + t.getScenarioName() + " (" + configDescriptor.description + ")</h4><br>"); //$NON-NLS-1$ //$NON-NLS-2$
if (scenarioComments.containsKey(t.getScenarioName())) {
ps.println("<b>Notes</b><br>\n");
ps.println("<table><tr><td>" + scenarioComments.get(t.getScenarioName()) + "</td></tr></table><br>\n");
}
ps.println("<b>Click measurement name to view line graph of measured values over builds.</b><br><br>\n");
ps.println("<table border=\"1\">"); //$NON-NLS-1$ //$NON-NLS-2$
Dim[] dimensions = filteredDimensions(t.getDimensions());
try {
ps.println("<tr><td>Build Id</td>"); //$NON-NLS-1$
for (int i = 0; i < dimensions.length; i++) {
Dim dim = dimensions[i];
String dimName = dim.getName();
ps.println("<td><a href=\"#" + configDescriptor.name + "_" + scenarioFileName + "_" + dimName + "\">" + dimName + "</a></td>");
}
ps.print("</tr>\n");
// store current and reference values for diff later
double[][] diffValues = new double[2][dimensions.length];
// to determine if diff is possible
boolean[] refValueExistance = new boolean[dimensions.length];
for (int j = 0; j < 2; j++) {
String referenceIndicator = (j == 1) ? "(reference)" : "";
String buildName = ((buildNameIndeces[j] == -1) ? "n/a" : t.getTimeSeriesLabels()[buildNameIndeces[j]]) + referenceIndicator;
ps.print("<tr><td>" + buildName + "</td>");
for (int i = 0; i < dimensions.length; i++) {
Dim dim = dimensions[i];
TimeSeries ts = t.getTimeSeries(dim);
if (j == 1 && buildNameIndeces[j] != -1)
refValueExistance[i] = true;
if (buildNameIndeces[j] != -1)
diffValues[j][i] = ts.getValue(buildNameIndeces[j]);
String displayValue = (buildNameIndeces[j] == -1) ? "n/a" : dim.getDisplayValue(ts.getValue(buildNameIndeces[j]));
String stddev = (buildNameIndeces[j] == -1) ? "0" : dim.getDisplayValue(ts.getStddev(buildNameIndeces[j]));
if (stddev.startsWith("0 ") || stddev.equals("0"))
ps.println("<td>" + displayValue + "</td>");
else
ps.println("<td>" + displayValue + " [" + stddev + "]" + "</td>");
}
ps.print("</tr>");
}
// get diffs and print results
ps.println(getDiffs(diffValues, dimensions, refValueExistance));
ps.println();
ps.println("</font></table>");
ps.println("*Delta values in red and green indicate degradation > 10% and improvement > 10%,respectively.<br><br>");
ps.println("<br><hr>\n\n");
// print text legend.
ps.println("Black and yellow points plot values measured in integration and last seven nightly builds.<br>\n" + "Magenta points plot the repeated baseline measurement over time.<br>\n"
+ "Boxed points represent previous releases, milestone builds, current reference and current build.<br><br>\n"
+ "Hover over any point for build id and value.\n");
//print link to raw data.
ps.println("<br><br><b>Click <a href=\""+rawDataFile+"\">here</a> to view raw data and stats.</b>" +
"<br>The raw data and stats include data for all current stream builds and all baseline test runs.<br>\n");
// print image maps of historical
for (int i = 0; i < dimensions.length; i++) {
Dim dim = dimensions[i];
String dimName = dim.getName();
TimeLineGraph lg = Utils.getLineGraph(t, dim.getName(), baseline, baselinePrefix, current, pointsOfInterest,buildIDStreamPatterns);
String lgImg = configDescriptor.outputDir + "/graphs/" + scenarioFileName + "_" + dimName + ".gif";
Utils.printLineGraphGif(lg, lgImg);
ps.println("<br><a name=\"" + configDescriptor.name + "_" + scenarioFileName + "_" + dimName + "\"></a>");
ps.println("<br><b>" + dimName + "</b><br>");
ps.println(Utils.getDimensionDescription(dimName) + "<br><br>\n");
ps.println(Utils.getImageMap(lg, "graphs/" + scenarioFileName + "_" + dimName + ".gif",scenarioFileName+"_raw.html"));
}
ps.println("<br><br></body>");
ps.println(Utils.HTML_CLOSE); //$NON-NLS-1$
if (ps != System.out)
ps.close();
} catch (AssertionFailedError e) {
e.printStackTrace();
continue;
}
}
}
private void printDetails() {
String outFile = null;
PrintStream ps = null;
for (int s = 0; s < scenarios.length; s++) {
Scenario t = scenarios[s];
// don't produce result if none exists for current build
if (Utils.getBuildNameIndex(t.getTimeSeriesLabels(), current) == -1) {
continue;
}
Dim[] dimensions = filteredDimensions(t.getDimensions());
RawDataTable currentResultsTable=new RawDataTable(t,dimensions,buildIDStreamPatterns,current);
//create table for baseline data
RawDataTable baselineResultsTable=new RawDataTable(t,dimensions,baselinePrefix,baseline);
//store cv for aggregate data
Hashtable data=(Hashtable)variabilityData.get(t.getScenarioName());
if (data==null){
data=new Hashtable();
variabilityData.put(t.getScenarioName(),data);
}
data.put("cConfig-"+configDescriptor.name,currentResultsTable.getCV());
data.put("bConfig-"+configDescriptor.name,baselineResultsTable.getCV());
String scenarioFileName = t.getScenarioName().replace('#', '.').replace(':', '_').replace('\\', '_');
outFile = configDescriptor.outputDir + "/" + scenarioFileName + "_raw.html";
if (outFile != null) {
try {
new File(outFile).getParentFile().mkdirs();
ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(outFile)));
} catch (FileNotFoundException e) {
System.err.println("can't create output file" + outFile); //$NON-NLS-1$
}
}
if (ps == null)
ps = System.out;
ps.println(Utils.HTML_OPEN);
ps.println(Utils.HTML_DEFAULT_CSS);
ps.println("<title>" + t.getScenarioName() + "(" + configDescriptor.description + ")" + " - Details</title></head>"); //$NON-NLS-1$
ps.println("<h4>Scenario: " + t.getScenarioName() + " (" + configDescriptor.description + ")</h4>"); //$NON-NLS-1$
ps.println("<a href=\""+scenarioFileName+".html\">VIEW GRAPH</a><br><br>"); //$NON-NLS-1$
ps.println("<table><td><b>Current Stream Test Runs</b></td><td><b>Baseline Test Runs</b></td></tr>\n");
ps.println("<tr valign=\"top\">" +
"<td>"+currentResultsTable.toHtmlString()+"</td>"
+"<td>"+baselineResultsTable.toHtmlString()+"</td></tr>");
ps.println("</table>");
ps.close();
}
}
private String getMostRecentMatchingBuildID(Scenario scenario, String buildIdPrefix) {
String[] buildIds = scenario.getTimeSeriesLabels();
for (int i = buildIds.length - 1; i > -1; i--) {
if (buildIds[i].startsWith(buildIdPrefix))
return buildIds[i];
}
return null;
}
private ArrayList getAllMatchingBuildIds(Scenario scenario, String buildIdPrefix) {
ArrayList result = new ArrayList();
String[] buildIds = scenario.getTimeSeriesLabels();
for (int i = buildIds.length - 1; i > -1; i--) {
if (buildIds[i].startsWith(buildIdPrefix) && !buildIds[i].equals(baseline))
result.add(buildIds[i]);
}
return result;
}
private String getDiffs(double[][] values, Dim[] dimensions, boolean[] refValueExistance) {
String diffRow = "<tr><td>*Delta</td>";
for (int j = 0; j < dimensions.length; j++) {
Dim dim = dimensions[j];
double diffValue = values[0][j] - values[1][j];
double diffPercentage = 0;
if (values[1][j] != 0)
diffPercentage = ((int) (((diffValue / Math.abs(values[1][j])) * 1000))) / 10.0;
String diffDisplayValue = dim.getDisplayValue(diffValue);
// green
String fontColor = "";
if ((diffPercentage < -10 && !dim.largerIsBetter()) || (diffPercentage > 10 && dim.largerIsBetter()))
fontColor = "#006600";
if ((diffPercentage < -10 && dim.largerIsBetter()) || (diffPercentage > 10 && !dim.largerIsBetter()))
fontColor = "#FF0000";
diffPercentage = Math.abs(diffPercentage);
String percentage = (diffPercentage == 0) ? "" : "<br>" + diffPercentage + " %";
if (diffPercentage > 10 || diffPercentage < -10) {
diffRow = diffRow.concat("<td><FONT COLOR=\"" + fontColor + "\"><b>" + diffDisplayValue + percentage + "</b></FONT></td>");
} else if (refValueExistance[j]) {
diffRow = diffRow.concat("<td>" + diffDisplayValue + percentage + "</td>");
} else {
diffRow = diffRow.concat("<td>n/a</td>");
}
}
diffRow = diffRow.concat("</tr>");
return diffRow;
}
private Dim[] filteredDimensions(Dim[] dimensions) {
ArrayList list = new ArrayList();
ArrayList filtered = new ArrayList();
list.add(0, "Elapsed Process");
list.add(1, "CPU Time");
list.add(2, "Invocation Count");
list.add(3, "Kernel time");
list.add(4, "Data Size");
list.add(5, "Library Size");
list.add(6, "GDI Objects");
list.add(7, "Text Size");
// list.add(8,"Used Java Heap");
// list.add(9,"Committed");
// list.add(10,"Page Faults");
// list.add(11,"Hard Page Faults");
// list.add(12,"Soft Page Faults");
for (int i = 0; i < dimensions.length; i++) {
String dimName = dimensions[i].getName();
if (list.contains(dimName))
list.set(list.indexOf(dimName), dimensions[i]);
}
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Object tmp = iterator.next();
try {
if ((Dim) tmp instanceof Dim)
filtered.add(tmp);
} catch (ClassCastException e) {
//silently ignore
}
}
return (Dim[]) filtered.toArray(new Dim[filtered.size()]);
}
}