1/*******************************************************************************
2 * Copyright (c) 2000, 2009 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *     IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.test.performance.ui;
12
13import java.io.PrintStream;
14import java.util.List;
15import java.util.StringTokenizer;
16
17import org.eclipse.test.internal.performance.results.db.BuildResults;
18import org.eclipse.test.internal.performance.results.db.ConfigResults;
19import org.eclipse.test.internal.performance.results.db.PerformanceResults;
20import org.eclipse.test.internal.performance.results.db.ScenarioResults;
21
22/**
23 * Class used to print a scenario status table.
24 */
25public class ScenarioStatusTable {
26
27	private String component;
28	private PrintStream stream;
29	private int jsIdCount;
30
31/**
32 * Creates an HTML table of red x/green check for a scenario for each
33 * configuration.
34 */
35public ScenarioStatusTable(String  name, PrintStream stream) {
36    this.component = name;
37    this.stream = stream;
38}
39
40/**
41 * Prints the HTML representation of scenario status table into the given stream.
42 */
43public void print(PerformanceResults performanceResults) {
44
45	String baselineName = performanceResults.getBaselineName();
46	List scenarios = performanceResults.getComponentScenarios(this.component);
47	int size = scenarios.size();
48
49	// Print titles
50	printTitle();
51	this.stream.print("<table border=\"1\">\n");
52	this.stream.print("<tr>\n");
53	this.stream.print("<td><h4>All ");
54	this.stream.print(computeSize(scenarios));
55	this.stream.print(" scenarios</h4></td>\n");
56	printColumnsTitle(size, performanceResults);
57
58	// Print one line per scenario results
59	this.jsIdCount = 0;
60	for (int i=0; i<size; i++) {
61		ScenarioResults scenarioResults = (ScenarioResults) scenarios.get(i);
62		if (!scenarioResults.isValid()) continue;
63		this.stream.print("<tr>\n");
64		this.stream.print("<td>");
65		boolean hasSummary = scenarioResults.hasSummary();
66		if (hasSummary) this.stream.print("<b>");
67		String scenarioBaseline = scenarioResults.getBaselineBuildName();
68		boolean hasBaseline = baselineName.equals(scenarioBaseline);
69		if (!hasBaseline) {
70			this.stream.print("*");
71			this.stream.print(scenarioResults.getShortName());
72			this.stream.print(" <small>(vs.&nbsp;");
73			this.stream.print(scenarioBaseline);
74			this.stream.print(")</small>");
75		} else {
76			this.stream.print(scenarioResults.getShortName());
77		}
78		if (hasSummary) this.stream.print("</b>");
79		this.stream.print("\n");
80		String[] configs = performanceResults.getConfigNames(true/*sort*/);
81		int length = configs.length;
82		for (int j=0; j<length; j++) {
83			printConfigStats(scenarioResults, configs[j]);
84		}
85	}
86	this.stream.print("</table>\n");
87}
88
89private int computeSize(List scenarios) {
90	int size = scenarios.size();
91	int n = 0;
92	for (int i=0; i<size; i++) {
93		ScenarioResults scenarioResults = (ScenarioResults) scenarios.get(i);
94		if (scenarioResults.isValid()) n++;
95	}
96	return n;
97}
98
99/*
100 * Print the table columns title.
101 */
102private void printColumnsTitle(int size, PerformanceResults performanceResults) {
103	String[] configNames = performanceResults.getConfigNames(true/*sort*/);
104	String[] configBoxes = performanceResults.getConfigBoxes(true/*sort*/);
105	int length = configNames.length;
106	for (int i=0; i<length; i++) {
107		String columnTitle = configNames[i];
108		String boxName = configBoxes[i];
109		int idx = boxName.indexOf('(');
110		if (idx < 0) {
111			columnTitle = boxName;
112		} else {
113			// first line
114			StringTokenizer tokenizer = new StringTokenizer(boxName.substring(0, idx).trim(), " ");
115			StringBuffer buffer = new StringBuffer(tokenizer.nextToken());
116			while (tokenizer.hasMoreTokens()) {
117				buffer.append("&nbsp;");
118				buffer.append(tokenizer.nextToken());
119			}
120			buffer.append(' ');
121			// second line
122			tokenizer = new StringTokenizer(boxName.substring(idx).trim(), " ");
123			buffer.append(tokenizer.nextToken());
124			while (tokenizer.hasMoreTokens()) {
125				buffer.append("&nbsp;");
126				buffer.append(tokenizer.nextToken());
127			}
128			columnTitle = buffer.toString();
129		}
130		this.stream.print("<td><h5>");
131		this.stream.print(columnTitle);
132		this.stream.print("</h5>\n");
133	}
134}
135
136/*
137 * Print the scenario statistics value for the given configuration.
138 */
139private void printConfigStats(ScenarioResults scenarioResults, String config) {
140	ConfigResults configResults = scenarioResults.getConfigResults(config);
141	if (configResults == null || !configResults.isValid()) {
142		this.stream.print("<td>n/a</td>");
143		return;
144	}
145	BuildResults currentBuildResults = configResults.getCurrentBuildResults();
146	String failure = currentBuildResults.getFailure();
147	double[] deviation = configResults.getCurrentBuildDeltaInfo();
148	int confidence = Utils.confidenceLevel(deviation);
149	boolean hasFailure = failure != null;
150	String comment = currentBuildResults.getComment();
151	String image = Utils.getImage(confidence, hasFailure, comment != null);
152	this.stream.print("<td><a ");
153	if (!hasFailure|| (confidence & Utils.NAN) != 0 || failure.length() == 0){
154		// write deviation with error in table when test pass
155		this.stream.print("href=\"");
156		this.stream.print(configResults.getName());
157		this.stream.print('/');
158		this.stream.print(scenarioResults.getFileName());
159		this.stream.print(".html\">\n");
160		this.stream.print("<img hspace=\"10\" border=\"0\" src=\"");
161		this.stream.print(image);
162		this.stream.print("\"/></a>\n");
163	} else {
164		// create message with tooltip text including deviation with error plus failure message
165		this.jsIdCount+=1;
166		this.stream.print("class=\"tooltipSource\" onMouseover=\"show_element('toolTip");
167		this.stream.print(this.jsIdCount);
168		this.stream.print("')\" onMouseout=\"hide_element('toolTip");
169		this.stream.print(this.jsIdCount);
170		this.stream.print("')\" \nhref=\"");
171		this.stream.print(configResults.getName());
172		this.stream.print('/');
173		this.stream.print(scenarioResults.getFileName());
174		this.stream.print(".html\">\n");
175		this.stream.print("<img hspace=\"10\" border=\"0\" src=\"");
176		this.stream.print(image);
177		this.stream.print("\"/>\n");
178		this.stream.print("<span class=\"hidden_tooltip\" id=\"toolTip");
179		this.stream.print(this.jsIdCount);
180		this.stream.print("\">");
181		this.stream.print(failure);
182		this.stream.print("</span></a>\n");
183	}
184	String result = Utils.failureMessage(deviation, false);
185	this.stream.print(result);
186	this.stream.print("\n");
187}
188
189/*
190 * Print the status table explanationtitle.
191 */
192private void printTitle() {
193	this.stream.print("<br><h4>Scenario Status</h4>\n");
194	this.stream.print("The following table gives a complete but compact view of performance results for the component.<br>\n");
195	this.stream.print("Each line of the table shows the results for one scenario on all machines.<br><br>\n");
196	this.stream.print("The name of the scenario is in <b>bold</b> when its results are also displayed in the fingerprints<br>\n");
197	this.stream.print("and starts with an '*' when the scenario has no results in the last baseline run.<br><br>\n");
198	this.stream.print("Here are information displayed for each test (ie. in each cell):\n");
199	this.stream.print("<ul>\n");
200	this.stream.print("<li>an icon showing whether the test fails or passes and whether it's reliable or not.<br>\n");
201	this.stream.print("The legend for this icon is:\n");
202	this.stream.print("<ul>\n");
203	this.stream.print("<li>Green (<img src=\"");
204	this.stream.print(Utils.OK_IMAGE);
205	this.stream.print("\">): mark a <b>successful result</b>, which means this test has neither significant performance regression nor significant standard error</li>");
206	this.stream.print("<li>Red (<img src=\"");
207	this.stream.print(Utils.FAIL_IMAGE);
208	this.stream.print("\">): mark a <b>failing result</b>, which means this test shows a significant performance regression (more than 10%)</li>\n");
209	this.stream.print("<li>Gray (<img src=\"");
210	this.stream.print(Utils.FAIL_IMAGE_EXPLAINED);
211	this.stream.print("\">): mark a <b>failing result</b> (see above) with a comment explaining this degradation.</li>\n");
212	this.stream.print("<li>Yellow (<img src=\"");
213	this.stream.print(Utils.FAIL_IMAGE_WARN);
214	this.stream.print("\"> or <img src=\"");
215	this.stream.print(Utils.OK_IMAGE_WARN);
216	this.stream.print("\">): mark a <b>failing or successful result</b> with a significant standard error (more than ");
217	this.stream.print(Utils.STANDARD_ERROR_THRESHOLD_STRING);
218	this.stream.print(")</li>\n");
219	this.stream.print("<li>Black (<img src=\"");
220	this.stream.print(Utils.UNKNOWN_IMAGE);
221	this.stream.print("\">): mark an <b>undefined result</b>, which means that deviation on this test is not a number (<code>NaN</code>) or is infinite (happens when the reference value is equals to 0!)</li>");
222	this.stream.print("<li>\"n/a\": mark a test for with <b>no</b> performance results</li>\n");
223	this.stream.print("</ul></li>\n");
224	this.stream.print("<li>the value of the deviation from the baseline as a percentage (ie. formula is: <code>(build_test_time - baseline_test_time) / baseline_test_time</code>)</li>\n");
225	this.stream.print("<li>the value of the standard error of this deviation as a percentage (ie. formula is: <code>sqrt(build_test_stddev^2 / N + baseline_test_stddev^2 / N) / baseline_test_time</code>)<br>\n");
226	this.stream.print("When test only has one measure, the standard error cannot be computed and is replaced with a '<font color=\"#CCCC00\">[n/a]</font>'.</li>\n");
227	this.stream.print("</ul>\n");
228	this.stream.print("<u>Hints</u>:<ul>\n");
229	this.stream.print("<li>fly over image of failing tests to see the complete error message</li>\n");
230	this.stream.print("<li>to look at the complete and detailed test results, click on its image</li>\n");
231	this.stream.print("</ul>\n");
232}
233}
234