/******************************************************************************* * Copyright (c) 2000, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-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.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.StringTokenizer; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.swt.widgets.Display; import org.eclipse.test.internal.performance.results.db.ConfigResults; import org.eclipse.test.internal.performance.results.db.DB_Results; import org.eclipse.test.internal.performance.results.db.PerformanceResults; import org.eclipse.test.internal.performance.results.db.ScenarioResults; import org.eclipse.test.internal.performance.results.utils.Util; import org.osgi.framework.Bundle; /** * Main class to generate performance results of all scenarios matching a given pattern * in one HTML page per component. * * @see #printUsage() method to see a detailed parameters usage */ public class GenerateResults { /** * Prefix of baseline builds displayed in data graphs. * This field is set using <b>-baseline.prefix</b> argument. * <p> * Example: * <pre>-baseline.prefix 3.2_200606291905</pre> * * @see #currentBuildPrefixes */ String baselinePrefix = null; /** * Root directory where all files are generated. * This field is set using <b>-output</b> argument. * <p> * Example: * <pre>-output /releng/results/I20070615-1200/performance</pre> */ File outputDir; /** * Root directory where all data are locally stored to speed-up generation. * This field is set using <b>-dataDir</b> argument. * <p> * Example: * <pre>-dataDir /tmp</pre> */ File dataDir; /** * Arrays of 2 strings which contains config information: name and description. * This field is set using <b>-config</b> and/or <b>-config.properties</b> arguments. * <p> * Example: * <pre> * -config eclipseperflnx3_R3.3,eclipseperfwin2_R3.3,eclipseperflnx2_R3.3,eclipseperfwin1_R3.3,eclipseperflnx1_R3.3 * -config.properties * "eclipseperfwin1_R3.3,Win XP Sun 1.4.2_08 (2 GHz 512 MB); * eclipseperflnx1_R3.3,RHEL 3.0 Sun 1.4.2_08 (2 GHz 512 MB); * eclipseperfwin2_R3.3,Win XP Sun 1.4.2_08 (3 GHz 2 GB); * eclipseperflnx2_R3.3,RHEL 3.0 Sun 1.4.2_08 (3 GHz 2 GB); * eclipseperflnx3_R3.3,RHEL 4.0 Sun 1.4.2_08 (3 GHz 2.5 GB)" * </pre> * Note that: * <ul> * <li>if only <b>-config</b> is set, then configuration name is used for description </li> * <li>if only <b>-config.properties</b> is set, then all configurations defined with this argument are generated * <li>if both arguments are defined, then only configurations defined by <b>-config</b> argument are generated, * <b>-config.properties</b> argument is only used to set the configuration description.</li> * </ul> */ String[][] configDescriptors; /** * Scenario pattern used to generate performance results. * This field is set using <b>-scenarioPattern</b> argument. * <p> * Note that this pattern uses SQL conventions, not RegEx ones, * which means that '%' is used to match several consecutive characters * and '_' to match a single character. * <p> * Example: * <pre>-scenario.pattern org.eclipse.%.test</pre> */ String scenarioPattern; /** * A list of prefixes for builds displayed in data graphs. * This field is set using <b>-currentPrefix</b> argument. * <p> * Example: * <pre>-current.prefix N, I</pre> * * @see #baselinePrefix */ List currentBuildPrefixes; /** * A list of prefixes of builds to highlight in displayed data graphs. * This field is set using <b>-highlight</b> and/or <b>-highlight.latest</b> arguments. * <p> * Example: * <pre>-higlight 3_2</pre> */ List pointsOfInterest; /** * Tells whether only fingerprints has to be generated. * This field is set to <code>true</code> if <b>-fingerprints</b> argument is specified. * <p> * Default is <code>false</code> which means that scenario data * will also be generated. * * @see #genData * @see #genAll */ boolean genFingerPrints = false; /** * Tells whether only fingerprints has to be generated. * This field is set to <code>true</code> if <b>-data</b> argument is specified. * <p> * Default is <code>false</code> which means that fingerprints * will also be generated. * * @see #genFingerPrints * @see #genAll */ boolean genData = false; /** * Tells whether only fingerprints has to be generated. * This field is set to <code>false</code> * if <b>-fingerprints</b> or <b>-data</b> argument is specified. * <p> * Default is <code>true</code> which means that scenario data * will also be generated. * * @see #genData * @see #genFingerPrints */ boolean genAll = true; /** * Tells whether information should be displayed in the console while generating. * This field is set to <code>true</code> if <b>-print</b> argument is specified. * <p> * Default is <code>false</code> which means that nothing is print during the generation. */ PrintStream printStream = null; /** * Tells what should be the failure percentage threshold. * <p> * Default is 10%. */ int failure_threshold = 10; // PerformanceTestPlugin.getDBLocation().startsWith("net://"); PerformanceResults performanceResults; public GenerateResults() { } public GenerateResults(PerformanceResults results, String current, String baseline, boolean fingerprints, File data, File output) { this.dataDir = data; this.outputDir = output; this.genFingerPrints = fingerprints; this.genAll = !fingerprints; this.performanceResults = results; this.printStream = System.out; setDefaults(current, baseline); } /* * Parse the command arguments and create corresponding performance * results object. */ private void parse(String[] args) { StringBuffer buffer = new StringBuffer("Parameters used to generate performance results ("); buffer.append(new SimpleDateFormat().format(new Date(System.currentTimeMillis()))); buffer.append("):\n"); int i = 0; int argsLength = args.length; if (argsLength == 0) { printUsage(); } String currentBuildId = null; String baseline = null; String jvm = null; this.configDescriptors = null; while (i < argsLength) { String arg = args[i]; if (!arg.startsWith("-")) { i++; continue; } if (argsLength == i + 1 && i != argsLength - 1) { System.out.println("Missing value for last parameter"); printUsage(); } if (arg.equals("-baseline")) { baseline = args[i + 1]; if (baseline.startsWith("-")) { System.out.println("Missing value for "+arg+" parameter"); printUsage(); } buffer.append(" -baseline = "+baseline+'\n'); i++; continue; } if (arg.equals("-baseline.prefix")) { this.baselinePrefix = args[i + 1]; if (this.baselinePrefix.startsWith("-")) { System.out.println("Missing value for "+arg+" parameter"); printUsage(); } buffer.append(" ").append(arg).append(" = ").append(this.baselinePrefix).append('\n'); i++; continue; } if (arg.equals("-current.prefix")) { String idPrefixList = args[i + 1]; if (idPrefixList.startsWith("-")) { System.out.println("Missing value for "+arg+" parameter"); printUsage(); } buffer.append(" ").append(arg).append(" = "); String[] ids = idPrefixList.split(","); this.currentBuildPrefixes = new ArrayList(); for (int j = 0; j < ids.length; j++) { this.currentBuildPrefixes.add(ids[j]); buffer.append(ids[j]); } buffer.append('\n'); i++; continue; } if (arg.equals("-highlight") || arg.equals("-highlight.latest")) { if (args[i + 1].startsWith("-")) { System.out.println("Missing value for "+arg+" parameter"); printUsage(); } buffer.append(" ").append(arg).append(" = "); String[] ids = args[i + 1].split(","); this.pointsOfInterest = new ArrayList(); for (int j = 0; j < ids.length; j++) { this.pointsOfInterest.add(ids[j]); buffer.append(ids[j]); } buffer.append('\n'); i++; continue; } if (arg.equals("-current")) { currentBuildId = args[i + 1]; if (currentBuildId.startsWith("-")) { System.out.println("Missing value for "+arg+" parameter"); printUsage(); } buffer.append(" ").append(arg).append(" = ").append(currentBuildId).append('\n'); i++; continue; } if (arg.equals("-jvm")) { jvm = args[i + 1]; if (jvm.startsWith("-")) { System.out.println("Missing value for "+arg+" parameter"); printUsage(); } buffer.append(" ").append(arg).append(" = ").append(jvm).append('\n'); i++; continue; } if (arg.equals("-output")) { String dir = args[++i]; if (dir.startsWith("-")) { System.out.println("Missing value for "+arg+" parameter"); printUsage(); } this.outputDir = new File(dir); if (!this.outputDir.exists() && !this.outputDir.mkdirs()) { System.err.println("Cannot create directory "+dir+" to write results in!"); System.exit(2); } buffer.append(" ").append(arg).append(" = ").append(dir).append('\n'); continue; } if (arg.equals("-dataDir")) { String dir = args[++i]; if (dir.startsWith("-")) { System.out.println("Missing value for "+arg+" parameter"); printUsage(); } this.dataDir = new File(dir); if (!this.dataDir.exists() && !this.dataDir.mkdirs()) { System.err.println("Cannot create directory "+dir+" to save data locally!"); System.exit(2); } buffer.append(" ").append(arg).append(" = ").append(dir).append('\n'); continue; } if (arg.equals("-config")) { String configs = args[i + 1]; if (configs.startsWith("-")) { System.out.println("Missing value for "+arg+" parameter"); printUsage(); } String[] names = configs.split(","); int length = names.length; buffer.append(" ").append(arg).append(" = "); for (int j=0; j<length; j++) { if (j>0) buffer.append(','); buffer.append(names[j]); } if (this.configDescriptors == null) { this.configDescriptors = new String[length][2]; for (int j=0; j<length; j++) { this.configDescriptors[j][0] = names[j]; this.configDescriptors[j][1] = names[j]; } } else { int confLength = this.configDescriptors[0].length; int newLength = confLength; mainLoop: for (int j=0; j<confLength; j++) { for (int k=0; k<length; k++) { if (this.configDescriptors[j][0].equals(names[k])) { continue mainLoop; } } this.configDescriptors[j][0] = null; this.configDescriptors[j][1] = null; newLength--; } if (newLength < confLength) { String[][] newDescriptors = new String[newLength][2]; for (int j=0, c=0; j<newLength; j++) { if (this.configDescriptors[c] != null) { newDescriptors[j][0] = this.configDescriptors[c][0]; newDescriptors[j][1] = this.configDescriptors[c][1]; } else { c++; } } this.configDescriptors = newDescriptors; } } buffer.append('\n'); i++; continue; } if (arg.equals("-config.properties")) { String configProperties = args[i + 1]; if (configProperties.startsWith("-")) { System.out.println("Missing value for "+arg+" parameter"); printUsage(); } if (this.configDescriptors == null) { System.out.println("Missing -config parameter"); printUsage(); } int length = this.configDescriptors.length; StringTokenizer tokenizer = new StringTokenizer(configProperties, ";"); buffer.append('\t').append(arg).append(" = '").append(configProperties).append("' splitted in ").append(length).append(" configs:"); while (tokenizer.hasMoreTokens()) { String labelDescriptor = tokenizer.nextToken(); String[] elements = labelDescriptor.trim().split(","); for (int j=0; j<length; j++) { if (elements[0].equals(this.configDescriptors[j][0])) { this.configDescriptors[j][1] = elements[1]; buffer.append("\n\t\t+ "); buffer.append(elements[0]); buffer.append(" -> "); buffer.append(elements[1]); } } } buffer.append('\n'); i++; continue; } if (arg.equals("-scenario.filter") || arg.equals("-scenario.pattern")) { this.scenarioPattern= args[i + 1]; if (this.scenarioPattern.startsWith("-")) { System.out.println("Missing value for "+arg+" parameter"); printUsage(); } buffer.append(" ").append(arg).append(" = ").append(this.scenarioPattern).append('\n'); i++; continue; } if (arg.equals("-fingerprints")) { this.genFingerPrints = true; this.genAll = false; buffer.append(" ").append(arg).append('\n'); i++; continue; } if (arg.equals("-data")) { this.genData = true; this.genAll = false; buffer.append(" ").append(arg).append('\n'); i++; continue; } if (arg.equals("-print")) { this.printStream = System.out; // default is to print to console buffer.append(" ").append(arg); i++; String printFile = i==argsLength ? null : args[i]; if (printFile==null ||printFile.startsWith("-")) { buffer.append(" (to the console)").append('\n'); } else { try { this.printStream = new PrintStream(new BufferedOutputStream(new FileOutputStream(printFile))); } catch (FileNotFoundException fnfe) { // use the console if the output file cannot be created } buffer.append(" (to file: ").append(printFile).append(")\n"); } continue; } if (arg.equals("-failure.threshold")) { String value = args[i + 1]; try { this.failure_threshold = Integer.parseInt(value); if (this.failure_threshold < 0) { System.out.println("Value for "+arg+" parameter must be positive."); printUsage(); } } catch (NumberFormatException nfe) { System.out.println("Invalid value for "+arg+" parameter"); printUsage(); } buffer.append(" ").append(arg).append(" = ").append(value).append('\n'); i++; continue; } i++; } if (this.printStream != null) { this.printStream.print(buffer.toString()); } // Stop if some mandatory parameters are missing if (this.outputDir == null || this.configDescriptors == null || jvm == null) { printUsage(); } // Set performance results setPerformanceResults(currentBuildId, baseline); } /* * Print component PHP file */ private void printComponent(/*PerformanceResults performanceResults, */String component) throws FileNotFoundException { if (this.printStream != null) this.printStream.print("."); File outputFile = new File(this.outputDir, component + ".php"); PrintStream stream = new PrintStream(new BufferedOutputStream(new FileOutputStream(outputFile))); // Print header boolean isGlobal = component.startsWith("global"); if (isGlobal) { File globalFile = new File(this.outputDir, "global.php"); PrintStream gStream = new PrintStream(new BufferedOutputStream(new FileOutputStream(globalFile))); gStream.print(Utils.HTML_OPEN); gStream.print("</head>\n"); gStream.print("<body>\n"); gStream.print("<?php\n"); gStream.print(" include(\"global_fp.php\");\n"); gStream.print("?>\n"); gStream.print("<table border=0 cellpadding=2 cellspacing=5 width=\"100%\">\n"); gStream.print("<tbody><tr> <td colspan=3 align=\"left\" bgcolor=\"#0080c0\" valign=\"top\"><b><font color=\"#ffffff\" face=\"Arial,Helvetica\">\n"); gStream.print("Detailed performance data grouped by scenario prefix</font></b></td></tr></tbody></table>\n"); gStream.print("<a href=\"org.eclipse.php.core.php?\">org.eclipse.php.core*</a><br>\n"); gStream.print("</body>\n"); gStream.print(Utils.HTML_CLOSE); gStream.close(); } else { stream.print(Utils.HTML_OPEN); } stream.print("<link href=\""+Utils.TOOLTIP_STYLE+"\" rel=\"stylesheet\" type=\"text/css\">\n"); stream.print("<script src=\""+Utils.TOOLTIP_SCRIPT+"\"></script>\n"); stream.print("<script src=\""+Utils.FINGERPRINT_SCRIPT+"\"></script>\n"); stream.print(Utils.HTML_DEFAULT_CSS); // Print title stream.print("<body>"); printComponentTitle(/*performanceResults, */component, isGlobal, stream); // print the html representation of fingerprint for each config Display display = Display.getDefault(); if (this.genFingerPrints || this.genAll) { final FingerPrint fingerprint = new FingerPrint(component, stream, this.outputDir); display.syncExec( new Runnable() { public void run(){ try { fingerprint.print(GenerateResults.this.performanceResults); } catch (Exception ex) { ex.printStackTrace(); } } } ); } // FingerPrint fingerprint = new FingerPrint(component, stream, this.outputDir); // fingerprint.print(performanceResults); // print scenario status table if (!isGlobal) { // print the component scenario status table beneath the fingerprint final ScenarioStatusTable sst = new ScenarioStatusTable(component, stream); display.syncExec( new Runnable() { public void run(){ try { sst.print(GenerateResults.this.performanceResults); } catch (Exception ex) { ex.printStackTrace(); } } } ); // ScenarioStatusTable sst = new ScenarioStatusTable(component, stream); // sst.print(performanceResults); } stream.print(Utils.HTML_CLOSE); stream.close(); } private void printComponentTitle(/*PerformanceResults performanceResults, */String component, boolean isGlobal, PrintStream stream) { String baselineName = this.performanceResults.getBaselineName(); String currentName = this.performanceResults.getName(); // Print title line stream.print("<h3>Performance of "); if (!isGlobal) { stream.print(component); stream.print(": "); } stream.print(currentName); stream.print(" relative to "); int index = baselineName.indexOf('_'); if (index > 0) { stream.print(baselineName.substring(0, index)); stream.print(" ("); index = baselineName.lastIndexOf('_'); stream.print(baselineName.substring(index+1, baselineName.length())); stream.print(')'); } else { stream.print(baselineName); } stream.print("</h3>\n"); // Print reference to global results if (!isGlobal) { stream.print("<?php\n"); stream.print(" $type=$_SERVER['QUERY_STRING'];\n"); stream.print(" if ($type==\"\") {\n"); stream.print(" $type=\"fp_type=0\";\n"); stream.print(" }\n"); stream.print(" $href=\"<a href=\\\"performance.php?\";\n"); stream.print(" $href=$href . $type . \"\\\">Back to global results</a><br><br>\";\n"); stream.print(" echo $href;\n"); stream.print("?>\n"); } } /* * Print summary of coefficient of variation for each scenario of the given pattern * both for baseline and current builds. */ private void printSummary(/*PerformanceResults performanceResults*/) { long start = System.currentTimeMillis(); if (this.printStream != null) this.printStream.print("Print scenarios variations summary..."); File outputFile = new File(this.outputDir, "cvsummary.html"); PrintStream stream = null; try { stream = new PrintStream(new BufferedOutputStream(new FileOutputStream(outputFile))); printSummaryPresentation(stream); // List scenarioNames = DB_Results.getScenarios(); // int size = scenarioNames.size(); String[] components = this.performanceResults.getComponents(); int componentsLength = components.length; printSummaryColumnsTitle(stream/*, performanceResults*/); String[] configs = this.performanceResults.getConfigNames(true/*sorted*/); int configsLength = configs.length; for (int i=0; i<componentsLength; i++) { String componentName = components[i]; List scenarioNames = this.performanceResults.getComponentScenarios(componentName); int size = scenarioNames.size(); for (int s=0; s<size; s++) { String scenarioName = ((ScenarioResults) scenarioNames.get(s)).getName(); if (scenarioName == null) continue; ScenarioResults scenarioResults = this.performanceResults.getScenarioResults(scenarioName); if (scenarioResults != null) { stream.print("<tr>\n"); for (int j=0; j<2; j++) { for (int c=0; c<configsLength; c++) { printSummaryScenarioLine(j, configs[c], scenarioResults, stream); } } stream.print("<td>"); stream.print(scenarioName); stream.print("</td></tr>\n"); } } } } catch (Exception e) { e.printStackTrace(); } finally { stream.print("</table></body></html>\n"); stream.flush(); stream.close(); } if (this.printStream != null) this.printStream.println("done in "+(System.currentTimeMillis()-start)+"ms"); } /* * Print summary presentation (eg. file start and text presenting the purpose of this file contents).. */ private void printSummaryPresentation(PrintStream stream) { stream.print(Utils.HTML_OPEN); stream.print(Utils.HTML_DEFAULT_CSS); stream.print("<title>Summary of Elapsed Process Variation Coefficients</title></head>\n"); stream.print("<body><h3>Summary of Elapsed Process Variation Coefficients</h3>\n"); stream.print("<p> This table provides a bird's eye view of variability in elapsed process times\n"); stream.print("for baseline and current build stream performance scenarios."); stream.print(" This summary is provided to facilitate the identification of scenarios that should be examined due to high variability."); stream.print("The variability for each scenario is expressed as a <a href=\"http://en.wikipedia.org/wiki/Coefficient_of_variation\">coefficient\n"); stream.print("of variation</a> (CV). The CV is calculated by dividing the <b>standard deviation\n"); stream.print("of the elapse process time over builds</b> by the <b>average elapsed process\n"); stream.print("time over builds</b> and multiplying by 100.\n"); stream.print("</p><p>High CV values may be indicative of any of the following:<br></p>\n"); stream.print("<ol><li> an unstable performance test. </li>\n"); stream.print("<ul><li>may be evidenced by an erratic elapsed process line graph.<br><br></li></ul>\n"); stream.print("<li>performance regressions or improvements at some time in the course of builds.</li>\n"); stream.print("<ul><li>may be evidenced by plateaus in elapsed process line graphs.<br><br></li></ul>\n"); stream.print("<li>unstable testing hardware.\n"); stream.print("<ul><li>consistent higher CV values for one test configuration as compared to others across"); stream.print(" scenarios may be related to hardward problems.</li></ul></li></ol>\n"); stream.print("<p> Scenarios are listed in alphabetical order in the far right column. A scenario's\n"); stream.print("variation coefficients (CVs) are in columns to the left for baseline and current\n"); stream.print("build streams for each test configuration. Scenarios with CVs > 10% are highlighted\n"); stream.print("in yellow (10%<CV><CV<20%) and orange(CV>20%). </p>\n"); stream.print("<p> Each CV value links to the scenario's detailed results to allow viewers to\n"); stream.print("investigate the variability.</p>\n"); } /* * Print columns titles of the summary table. */ private void printSummaryColumnsTitle(PrintStream stream/*, PerformanceResults performanceResults*/) { String[] configBoxes = this.performanceResults.getConfigBoxes(true/*sorted*/); int length = configBoxes.length; stream.print("<table border=\"1\"><tr><td colspan=\""); stream.print(length); stream.print("\"><b>Baseline CVs</b></td><td colspan=\""); stream.print(length); stream.print("\"><b>Current Build Stream CVs</b></td><td rowspan=\"2\"><b>Scenario Name</b></td></tr>\n"); stream.print("<tr>"); for (int n=0; n<2; n++) { for (int c=0; c<length; c++) { stream.print("<td>"); stream.print(configBoxes[c]); stream.print("</td>"); } } stream.print("</tr>\n"); } /* * Print a scenario line in the summary table. */ private void printSummaryScenarioLine(int i, String config, ScenarioResults scenarioResults, PrintStream stream) { ConfigResults configResults = scenarioResults.getConfigResults(config); if (configResults == null || !configResults.isValid()) { stream.print("<td>n/a</td>"); return; } String url = config + "/" + scenarioResults.getFileName()+".html"; double[] stats = null; if (i==0) { // baseline results List baselinePrefixes = new ArrayList(); if (this.baselinePrefix == null) { baselinePrefixes.add(DB_Results.getDbBaselinePrefix()); } else { baselinePrefixes.add(this.baselinePrefix); } stats = configResults.getStatistics(baselinePrefixes); } else { stats = configResults.getStatistics(this.currentBuildPrefixes); } double variation = stats[3]; if (variation > 10 && variation < 20) { stream.print("<td bgcolor=\"yellow\">"); } else if (variation >= 20) { stream.print("<td bgcolor=\"FF9900\">"); } else { stream.print("<td>"); } stream.print("<a href=\""); stream.print(url); stream.print("\"/>"); stream.print(variation); stream.print("%</a></td>"); } /* * Print usage in case one of the argument of the line was incorrect. * Note that calling this method ends the program run due to final System.exit() */ private void printUsage() { System.out.println( "Usage:\n\n" + "-baseline\n" + " Build id against which to compare results.\n" + " Same as value specified for the \"build\" key in the eclipse.perf.config system property.\n\n" + "[-baseline.prefix]\n" + " Optional. Build id prefix used in baseline test builds and reruns. Used to plot baseline historical data.\n" + " A common prefix used for the value of the \"build\" key in the eclipse.perf.config system property when rerunning baseline tests.\n\n" + "-current\n" + " build id for which to generate results. Compared to build id specified in -baseline parameter above.\n" + " Same as value specified for the \"build\" key in the eclipse.perf.config system property. \n\n" + "[-current.prefix]\n" + " Optional. Comma separated list of build id prefixes used in current build stream.\n" + " Used to plot current build stream historical data. Defaults to \"N,I\".\n" + " Prefixes for values specified for the \"build\" key in the eclipse.perf.config system property. \n\n" + "-jvm\n" + " Value specified in \"jvm\" key in eclipse.perf.config system property for current build.\n\n" + "-config\n" + " Comma separated list of config names for which to generate results.\n" + " Same as values specified in \"config\" key in eclipse.perf.config system property.\n\n" + "-output\n" + " Path to default output directory.\n\n" + "[-config.properties]\n" + " Optional. Used by scenario status table to provide the following:\n" + " alternate descriptions of config values to use in columns.\n" + " The value should be specified in the following format:\n" + " name1,description1;name2,description2;etc..\n\n" + "[-highlight]\n" + " Optional. Comma-separated list of build Id prefixes used to find most recent matching for each entry.\n" + " Result used to highlight points in line graphs.\n\n" + "[-scenario.pattern]\n" + " Optional. Scenario prefix pattern to query database. If not specified,\n" + " default of % used in query.\n\n" + "[-fingerprints]\n" + " Optional. Use to generate fingerprints only.\n\n" + "[-data]\n" + " Optional. Generates table of scenario reference and current data with line graphs.\n\n" + "[-print]\n" + " Optional. Display output in the console while generating.\n" + "[-nophp]\n" + " Optional. Generate files for non-php server.\n" + "[-failure.threshold]\n" + " Optional. Set the failure percentage threshold (default is 10%).\n" ); System.exit(1); } /** * Run the generation from a list of arguments. * Typically used to generate results from an application. */ public IStatus run(String[] args) { parse(args); return run((IProgressMonitor) null); } /** * Run the generation using a progress monitor. * Note that all necessary information to generate properly must be set before * calling this method * * @see #run(String[]) */ public IStatus run(final IProgressMonitor monitor) { long begin = System.currentTimeMillis(); int work = 1100; int dataWork = 1000 * this.performanceResults.getConfigBoxes(false).length; if (this.genAll || this.genData) { work += dataWork; } SubMonitor subMonitor = SubMonitor.convert(monitor, work); try { // Print whole scenarios summary if (this.printStream != null) this.printStream.println(); printSummary(/*performanceResults*/); // Copy images and scripts to output dir Bundle bundle = UiPlugin.getDefault().getBundle(); // URL images = bundle.getEntry("images"); // if (images != null) { // images = FileLocator.resolve(images); // Utils.copyImages(new File(images.getPath()), this.outputDir); // } /* New way to get images File content = FileLocator.getBundleFile(bundle); BundleFile bundleFile; if (content.isDirectory()) { bundleFile = new DirBundleFile(content); Utils.copyImages(bundleFile.getFile("images", true), this.outputDir); } else { bundleFile = new ZipBundleFile(content, null); Enumeration imageFiles = bundle.findEntries("images", "*.gif", false); while (imageFiles.hasMoreElements()) { URL url = (URL) imageFiles.nextElement(); Utils.copyFile(bundleFile.getFile("images"+File.separator+, true), this.outputDir); } } */ // Copy bundle files Utils.copyBundleFiles(bundle, "images", "*.gif", this.outputDir); // images Utils.copyBundleFiles(bundle, "scripts", "*.js", this.outputDir); // java scripts Utils.copyBundleFiles(bundle, "scripts", "*.css", this.outputDir); // styles Utils.copyBundleFiles(bundle, "doc", "*.html", this.outputDir); // doc Utils.copyBundleFiles(bundle, "doc/images", "*.png", this.outputDir); // images for doc /* URL doc = bundle.getEntry("doc"); if (doc != null) { doc = FileLocator.resolve(doc); File docDir = new File(doc.getPath()); FileFilter filter = new FileFilter() { public boolean accept(File pathname) { return !pathname.getName().equals("CVS"); } }; File[] docFiles = docDir.listFiles(filter); for (int i=0; i<docFiles.length; i++) { File file = docFiles[i]; if (file.isDirectory()) { File subdir = new File(this.outputDir, file.getName()); subdir.mkdir(); File[] subdirFiles = file.listFiles(filter); for (int j=0; j<subdirFiles.length; j++) { if (subdirFiles[i].isDirectory()) { // expect only one sub-directory } else { Util.copyFile(subdirFiles[j], new File(subdir, subdirFiles[j].getName())); } } } else { Util.copyFile(file, new File(this.outputDir, file.getName())); } } } */ // Print HTML pages and all linked files if (this.printStream != null) { this.printStream.println("Print performance results HTML pages:"); this.printStream.print(" - components main page"); } long start = System.currentTimeMillis(); subMonitor.setTaskName("Write fingerprints: 0%"); subMonitor.subTask("Global..."); printComponent(/*performanceResults, */"global_fp"); subMonitor.worked(100); if (subMonitor.isCanceled()) throw new OperationCanceledException(); String[] components = this.performanceResults.getComponents(); int length = components.length; int step = 1000 / length; int progress = 0; for (int i=0; i<length; i++) { int percentage = (int) ((progress / ((double) length)) * 100); subMonitor.setTaskName("Write fingerprints: "+percentage+"%"); subMonitor.subTask(components[i]+"..."); printComponent(/*performanceResults, */components[i]); subMonitor.worked(step); if (subMonitor.isCanceled()) throw new OperationCanceledException(); progress++; } if (this.printStream != null) { String duration = Util.timeString(System.currentTimeMillis()-start); this.printStream.println(" done in "+duration); } // Print the scenarios data if (this.genData || this.genAll) { start = System.currentTimeMillis(); if (this.printStream != null) this.printStream.println(" - all scenarios data:"); ScenarioData data = new ScenarioData(this.baselinePrefix, this.pointsOfInterest, this.currentBuildPrefixes, this.outputDir); try { data.print(this.performanceResults, this.printStream, subMonitor.newChild(dataWork)); } catch (Exception ex) { ex.printStackTrace(); } if (this.printStream != null) { String duration = Util.timeString(System.currentTimeMillis()-start); this.printStream.println(" => done in "+duration); } } if (this.printStream != null) { long time = System.currentTimeMillis(); this.printStream.println("End of generation: "+new SimpleDateFormat("H:mm:ss").format(new Date(time))); String duration = Util.timeString(System.currentTimeMillis()-begin); this.printStream.println("=> done in "+duration); } return new Status(IStatus.OK, UiPlugin.getDefault().toString(), "Everything is OK"); } catch (OperationCanceledException oce) { return new Status(IStatus.OK, UiPlugin.getDefault().toString(), "Generation was cancelled!"); } catch (Exception ex) { return new Status(IStatus.ERROR, UiPlugin.getDefault().toString(), "An unexpected exception occurred!", ex); } finally { if (this.printStream != null) { this.printStream.flush(); if (this.printStream != System.out) { this.printStream.close(); } } } } private void setDefaults(String buildName, String baseline) { if (buildName == null) { buildName = this.performanceResults.getName(); } // Set default output dir if not set if (this.outputDir.getPath().indexOf(buildName) == -1) { File dir = new File(this.outputDir, buildName); if (dir.exists() || dir.mkdir()) { this.outputDir = dir; if (this.printStream != null) { this.printStream.println(" + changed output dir to: "+dir.getPath()); } } } // Verify that build is known String[] builds = this.performanceResults.getAllBuildNames(); if (builds == null || builds.length == 0) { System.err.println("Cannot connect to database to generate results build '"+buildName+"'"); System.exit(1); } if (Arrays.binarySearch(builds, buildName, Util.BUILD_DATE_COMPARATOR) < 0) { throw new RuntimeException("No results in database for build '"+buildName+"'"); } if (this.printStream != null) { this.printStream.println(); this.printStream.flush(); } // Init baseline prefix if not set if (this.baselinePrefix == null) { int index = baseline.lastIndexOf('_'); if (index > 0) { this.baselinePrefix = baseline.substring(0, index); } else { this.baselinePrefix = DB_Results.getDbBaselinePrefix(); } } // Init current build prefixes if not set if (this.currentBuildPrefixes == null) { this.currentBuildPrefixes = new ArrayList(); if (buildName.charAt(0) == 'M') { this.currentBuildPrefixes.add("M"); } else { this.currentBuildPrefixes.add("N"); } this.currentBuildPrefixes.add("I"); } } private void setPerformanceResults(String buildName, String baselineName) { // Set performance results this.performanceResults = new PerformanceResults(buildName, baselineName, this.baselinePrefix, this.printStream); // Set defaults setDefaults(buildName, this.performanceResults.getBaselineName()); // Read performance results data this.performanceResults.readAll(buildName, this.configDescriptors, this.scenarioPattern, this.dataDir, this.failure_threshold, null); } /* (non-Javadoc) * @see org.eclipse.equinox.app.IApplication#stop() */ public void stop() { // Do nothing } }