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.internal.performance.results.model;
12
13import java.io.BufferedOutputStream;
14import java.io.DataOutputStream;
15import java.io.File;
16import java.io.FileNotFoundException;
17import java.io.FileOutputStream;
18import java.io.IOException;
19import java.util.Arrays;
20import org.eclipse.core.runtime.IProgressMonitor;
21import org.eclipse.test.internal.performance.results.db.*;
22import org.eclipse.test.internal.performance.results.utils.IPerformancesConstants;
23import org.eclipse.test.internal.performance.results.utils.Util;
24
25public class PerformanceResultsElement extends ResultsElement {
26
27// Singleton pattern
28public static PerformanceResultsElement PERF_RESULTS_MODEL = new PerformanceResultsElement();
29
30	String[] buildNames;
31	String lastBuildName;
32	boolean fingerprints = true;
33
34public PerformanceResultsElement() {
35	super();
36}
37
38ResultsElement createChild(AbstractResults testResults) {
39	return new ComponentResultsElement(testResults, this);
40}
41
42public String[] getBaselines() {
43	getBuildNames();
44	if (this.buildNames == null) {
45		return new String[0];
46	}
47	int length = this.buildNames.length;
48	String[] baselines = new String[length];
49	int count = 0;
50	for (int i=0; i<length; i++) {
51		if (this.buildNames[i].startsWith("R-")) {
52			baselines[count++] = this.buildNames[i];
53		}
54	}
55	if (count < length) {
56		System.arraycopy(baselines, 0, baselines = new String [count], 0, count);
57	}
58	return baselines;
59}
60
61String[] getBuildNames() {
62	if (this.buildNames == null) {
63		this.buildNames = DB_Results.DB_CONNECTION
64			? DB_Results.getBuilds()
65			: this.results == null
66				? new String[0]
67				: getPerformanceResults().getAllBuildNames();
68	}
69	return this.buildNames;
70}
71
72public Object[] getBuilds() {
73	getBuildNames();
74	int length = this.buildNames == null ? 0 : this.buildNames.length;
75	BuildResultsElement[] elements = new BuildResultsElement[length];
76	for (int i=0; i<length; i++) {
77		elements[i] = new BuildResultsElement(this.buildNames[i], this);
78	}
79	return elements;
80}
81
82public String[] getComponents() {
83	if (!isInitialized()) {
84		String[] components = DB_Results.getComponents();
85		int length = components.length;
86		if (length == 0) {
87			DB_Results.queryAllScenarios();
88			components = DB_Results.getComponents();
89		}
90		return components;
91	}
92	return getPerformanceResults().getComponents();
93}
94
95/**
96 * Returns the names of the configurations.
97 *
98 * @return An array of String
99 */
100public String[] getConfigs() {
101	if (!isInitialized()) {
102		String[] configs = DB_Results.getConfigs();
103		int length = configs.length;
104		if (length == 0) {
105			DB_Results.queryAllScenarios();
106			configs = DB_Results.getConfigs();
107		}
108		return configs;
109	}
110	return getPerformanceResults().getConfigNames(false);
111}
112
113/**
114 * Returns the descriptions of the configurations.
115 *
116 * @return An array of String
117 */
118public String[] getConfigDescriptions() {
119	if (!isInitialized()) {
120		String[] descriptions = DB_Results.getConfigDescriptions();
121		int length = descriptions.length;
122		if (length == 0) {
123			DB_Results.queryAllScenarios();
124			descriptions = DB_Results.getConfigDescriptions();
125		}
126		return descriptions;
127	}
128	return getPerformanceResults().getConfigBoxes(false);
129}
130
131public Object[] getElements() {
132	if (!isInitialized()) {
133		String[] components = getComponents();
134		int length = components.length;
135		ComponentResultsElement[] elements = new ComponentResultsElement[length];
136		for (int i=0; i<length; i++) {
137			elements[i] = new ComponentResultsElement(components[i], this);
138		}
139		return elements;
140	}
141	return getChildren(null);
142}
143
144public PerformanceResults getPerformanceResults() {
145	return (PerformanceResults) this.results;
146}
147
148boolean hasRead(BuildResultsElement buildResultsElement) {
149	String[] builds = this.results == null ? getBuildNames() : getPerformanceResults().getAllBuildNames();
150	if (Arrays.binarySearch(builds, buildResultsElement.getName(), Util.BUILD_DATE_COMPARATOR) < 0) {
151		return false;
152	}
153	return true;
154}
155
156public boolean isInitialized() {
157	return super.isInitialized() && this.results.size() > 0;
158}
159
160public void readLocal(File dataDir, IProgressMonitor monitor, String lastBuild) {
161	reset(lastBuild);
162	PerformanceResults performanceResults = getPerformanceResults();
163	performanceResults.setLastBuildName(lastBuild);
164	performanceResults.readLocal(dataDir, monitor);
165}
166
167public void reset(String buildName) {
168	if (buildName == null) {
169		this.results = new PerformanceResults(this.lastBuildName, null, null, System.out);
170	} else {
171		this.results = new PerformanceResults(buildName, null, null, System.out);
172	}
173	this.children = null;
174	this.buildNames = null;
175}
176
177public void resetBuildNames() {
178	this.buildNames = null;
179}
180
181public void updateBuild(String buildName, boolean force, File dataDir, IProgressMonitor monitor) {
182	if (this.results == null) {
183		reset(buildName);
184	}
185	getPerformanceResults().updateBuild(buildName, force, dataDir, monitor);
186}
187
188public void updateBuilds(String[] builds, boolean force, File dataDir, IProgressMonitor monitor) {
189	if (this.results == null) {
190		reset(null);
191	}
192	getPerformanceResults().updateBuilds(builds, force, dataDir, monitor);
193}
194
195/**
196 * Set whether only fingerprints should be taken into account or not.
197 *
198 * @param fingerprints
199 */
200public void setFingerprints(boolean fingerprints) {
201	this.fingerprints = fingerprints;
202	resetStatus();
203}
204
205public void setLastBuildName(String lastBuildName) {
206	this.lastBuildName = lastBuildName;
207	this.name = null;
208}
209
210/*
211 * Write the component status in the given file
212 */
213public StringBuffer writeStatus(File resultsFile, int kind) {
214	if (this.results == null) {
215		return null;
216	}
217	boolean values = (kind & IPerformancesConstants.STATUS_VALUES) != 0;
218	// Write status only for component with error
219	StringBuffer excluded = new StringBuffer();
220	try {
221		DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(resultsFile)));
222		try {
223			StringBuffer buffer = new StringBuffer();
224			// Print build name
225			buffer.append("Status for ");
226			buffer.append(getPerformanceResults().getName());
227			buffer.append(Util.LINE_SEPARATOR);
228			// Print status options
229			if ((kind & ~IPerformancesConstants.STATUS_VALUES) > 0) {
230				buffer.append("Options: ");
231				buffer.append(Util.LINE_SEPARATOR);
232				final int errorLevel = kind & IPerformancesConstants.STATUS_ERROR_LEVEL_MASK;
233				if (errorLevel != 0) {
234					buffer.append("	error level: ");
235					switch (errorLevel) {
236						case IPerformancesConstants.STATUS_ERROR_NONE:
237							buffer.append("include all failures whatever the error level is");
238							break;
239						case IPerformancesConstants.STATUS_ERROR_NOTICEABLE:
240							buffer.append("all failures with at least a noticeable error (> 3%) are excluded!");
241							break;
242						case IPerformancesConstants.STATUS_ERROR_SUSPICIOUS:
243							buffer.append("all failures with at least a suspicious error (> 25%) are excluded!");
244							break;
245						case IPerformancesConstants.STATUS_ERROR_WEIRD:
246							buffer.append("all failures with at least a weird error (> 50%) are excluded!");
247							break;
248						case IPerformancesConstants.STATUS_ERROR_INVALID:
249							buffer.append("all failures with an invalid error (> 100%) are excluded!");
250							break;
251					}
252					buffer.append(Util.LINE_SEPARATOR);
253				}
254				final int smallValue = kind & IPerformancesConstants.STATUS_SMALL_VALUE_MASK;
255				if (smallValue > 0) {
256					buffer.append("	small value: ");
257					switch (smallValue) {
258						case IPerformancesConstants.STATUS_SMALL_VALUE_BUILD:
259							buffer.append("all failures with a small build value (<100ms) are excluded!");
260							break;
261						case IPerformancesConstants.STATUS_SMALL_VALUE_DELTA:
262							buffer.append("all failures with a small delta value (<100ms) are excluded!");
263							break;
264						case IPerformancesConstants.STATUS_SMALL_VALUE_MASK:
265							buffer.append("all failures with a small build or delta value (<100ms) are excluded!");
266							break;
267					}
268					buffer.append(Util.LINE_SEPARATOR);
269				}
270				final int stats = kind & IPerformancesConstants.STATUS_STATISTICS_MASK;
271				if (stats > 0) {
272					buffer.append("	statistics: ");
273					switch (stats) {
274						case IPerformancesConstants.STATUS_STATISTICS_ERRATIC:
275							buffer.append("all failures with erratic baseline results (variation > 20%) are excluded!");
276							break;
277						case IPerformancesConstants.STATUS_STATISTICS_UNSTABLE:
278							buffer.append("all failures with unstable baseline results (10% < variation < 20%) are excluded!");
279							break;
280					}
281					buffer.append(Util.LINE_SEPARATOR);
282				}
283				int buildsNumber = kind & IPerformancesConstants.STATUS_BUILDS_NUMBER_MASK;
284				buffer.append("	builds to confirm a regression: ");
285				buffer.append(buildsNumber);
286				buffer.append(Util.LINE_SEPARATOR);
287			}
288			// Print columns title
289			buffer.append("Component");
290			buffer.append("	Scenario");
291			buffer.append("	Machine");
292			if (values) {
293				buffer.append("			Build		");
294				buffer.append("		History		");
295			}
296			buffer.append("	Comment");
297			buffer.append(Util.LINE_SEPARATOR);
298			if (values) {
299				buffer.append("			value");
300				buffer.append("	baseline");
301				buffer.append("	variation");
302				buffer.append("	delta");
303				buffer.append("	error");
304				buffer.append("	n");
305				buffer.append("	mean");
306				buffer.append("	deviation");
307				buffer.append("	coeff");
308				buffer.append(Util.LINE_SEPARATOR);
309			}
310			stream.write(buffer.toString().getBytes());
311			StringBuffer componentBuffer = writableStatus(new StringBuffer(), kind, excluded);
312			if (componentBuffer.length() > 0) {
313				stream.write(componentBuffer.toString().getBytes());
314			}
315		}
316		finally {
317			stream.close();
318		}
319	} catch (FileNotFoundException e) {
320		System.err.println("Can't create output file"+resultsFile); //$NON-NLS-1$
321	} catch (IOException e) {
322		e.printStackTrace();
323	}
324	return excluded;
325}
326
327}
328