| /******************************************************************************* |
| * 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()]); |
| } |
| |
| } |