• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  *******************************************************************************/
11 package org.eclipse.test.internal.performance.results.db;
12 
13 import java.io.BufferedInputStream;
14 import java.io.BufferedOutputStream;
15 import java.io.DataInputStream;
16 import java.io.DataOutputStream;
17 import java.io.File;
18 import java.io.FileInputStream;
19 import java.io.FileNotFoundException;
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Comparator;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Set;
28 
29 import org.eclipse.core.runtime.SubMonitor;
30 import org.eclipse.test.internal.performance.results.utils.Util;
31 
32 /**
33  * Class to handle performance results of an eclipse component
34  * (for example 'org.eclipse.jdt.core').
35  *
36  * It gives access to results for each scenario run for this component.
37  *
38  * @see ScenarioResults
39  */
40 public class ComponentResults extends AbstractResults {
41 
ComponentResults(AbstractResults parent, String name)42 public ComponentResults(AbstractResults parent, String name) {
43 	super(parent, name);
44 	this.printStream = parent.printStream;
45 }
46 
getAllBuildNames()47 Set getAllBuildNames() {
48 	Set buildNames = new HashSet();
49 	int size = size();
50 	for (int i=0; i<size; i++) {
51 		ScenarioResults scenarioResults = (ScenarioResults) this.children.get(i);
52 		Set builds = scenarioResults.getAllBuildNames();
53 		buildNames.addAll(builds);
54 	}
55 	return buildNames;
56 }
57 
58 /**
59  * Return all the build names for this component sorted by ascending order.
60  *
61  * @return An array of names
62  */
getAllSortedBuildNames()63 public String[] getAllSortedBuildNames() {
64 	return getAllSortedBuildNames(false/*ascending order*/);
65 }
66 
getAllSortedBuildNames(final boolean reverse)67 String[] getAllSortedBuildNames(final boolean reverse) {
68 	Set allBuildNames = getAllBuildNames();
69 	String[] sortedNames = new String[allBuildNames.size()];
70 	allBuildNames.toArray(sortedNames);
71 	Arrays.sort(sortedNames, new Comparator() {
72 		public int compare(Object o1, Object o2) {
73 			String s1 = (String) (reverse ? o2 : o1);
74 			String s2 = (String) (reverse ? o1 : o2);
75 			return Util.getBuildDate(s1).compareTo(Util.getBuildDate(s2));
76 	    }
77 	});
78 	return sortedNames;
79 }
80 
getComponentResults()81 ComponentResults getComponentResults() {
82 	return this;
83 }
84 
85 /**
86  * Get all results numbers for a given machine of the current component.
87  *
88  * @param configName The name of the configuration to get numbers
89  * @param fingerprints Set whether only fingerprints scenario should be taken into account
90  * @return A list of lines. Each line represent a build and is a list of either strings or values.
91   * 	Values are an array of double:
92  * 	<ul>
93  * 		<li>{@link #BUILD_VALUE_INDEX}: the build value in milliseconds</li>
94  * 		<li>{@link #BASELINE_VALUE_INDEX}: the baseline value in milliseconds</li>
95  * 		<li>{@link #DELTA_VALUE_INDEX}: the difference between the build value and its more recent baseline</li>
96  * 		<li>{@link #DELTA_ERROR_INDEX}: the error made while computing the difference</li>
97  * 		<li>{@link #BUILD_ERROR_INDEX}: the error made while measuring the build value</li>
98  * 		<li>{@link #BASELINE_ERROR_INDEX}: the error made while measuring the baseline value</li>
99  * 	</ul>
100 */
getConfigNumbers(String configName, boolean fingerprints, List differences)101 public List getConfigNumbers(String configName, boolean fingerprints, List differences) {
102 
103 	// Initialize lists
104 	AbstractResults[] scenarios = getChildren();
105 	int length = scenarios.length;
106 
107 	// Print scenario names line
108 	List firstLine = new ArrayList();
109 	for (int i=0; i<length; i++) {
110 		ScenarioResults scenarioResults = (ScenarioResults) scenarios[i];
111 		if (!fingerprints || scenarioResults.hasSummary()) {
112 			firstLine.add(scenarioResults.getName());
113 		}
114 	}
115 
116 	// Print each build line
117 	String[] builds = getAllSortedBuildNames(true/*descending order*/);
118 //	int milestoneIndex = 0;
119 //	String milestoneDate = Util.getMilestoneDate(milestoneIndex);
120 	String currentBuildName = null;
121 	int buildsLength= builds.length;
122 	firstLine.add(0, new Integer(buildsLength));
123 	differences.add(firstLine);
124 	for (int i=0; i<buildsLength; i++) {
125 		List line = new ArrayList();
126 		String buildName = builds[i];
127 		line.add(buildName);
128 		if (!buildName.startsWith(DB_Results.getDbBaselinePrefix())) {
129 			for (int j=0; j<length; j++) {
130 				ScenarioResults scenarioResults = (ScenarioResults) scenarios[j];
131 				if (!fingerprints || scenarioResults.hasSummary()) {
132 					ConfigResults configResults = scenarioResults.getConfigResults(configName);
133 					BuildResults buildResults = configResults == null ? null : configResults.getBuildResults(buildName);
134 					if (buildResults == null) {
135 						// no result for this scenario in this build
136 						line.add(NO_BUILD_RESULTS);
137 					} else {
138 						line.add(configResults.getNumbers(buildResults, configResults.getBaselineBuildResults(buildName)));
139 					}
140 				}
141 			}
142 			differences.add(line);
143 			if (currentBuildName != null && currentBuildName.charAt(0) != 'N') {
144             }
145 			currentBuildName = buildName;
146 		}
147 //		if (milestoneDate != null) { // update previous builds
148 //			int dateComparison = milestoneDate.compareTo(Util.getBuildDate(buildName));
149 //			if (dateComparison <= 0) {
150 //				if (dateComparison == 0) {
151 //                }
152 //				if (++milestoneIndex == Util.MILESTONES.length) {
153 //					milestoneDate = null;
154 //				} else {
155 //					milestoneDate = Util.getMilestoneDate(milestoneIndex);
156 //				}
157 //			}
158 //		}
159 	}
160 
161 	// Write differences lines
162 	int last = buildsLength-1;
163 	String lastBuildName = builds[last];
164 	while (last > 0 && lastBuildName.startsWith(DB_Results.getDbBaselinePrefix())) {
165 		lastBuildName = builds[--last];
166 	}
167 //	appendDifferences(lastBuildName, configName, previousMilestoneName, differences, fingerprints);
168 //	appendDifferences(lastBuildName, configName, previousBuildName, differences, fingerprints);
169 
170 	// Return the computed differences
171 	return differences;
172 }
173 
174 /*
175 double[] getConfigNumbers(BuildResults buildResults, BuildResults baselineResults) {
176 	if (baselineResults == null) {
177 		return INVALID_RESULTS;
178 	}
179 	double[] values = new double[NUMBERS_LENGTH];
180 	for (int i=0 ;i<NUMBERS_LENGTH; i++) {
181 		values[i] = Double.NaN;
182 	}
183 	double buildValue = buildResults.getValue();
184 	values[BUILD_VALUE_INDEX] = buildValue;
185 	double baselineValue = baselineResults.getValue();
186 	values[BASELINE_VALUE_INDEX] = baselineValue;
187 	double delta = (baselineValue - buildValue) / baselineValue;
188 	values[DELTA_VALUE_INDEX] = delta;
189 	if (Double.isNaN(delta)) {
190 		return values;
191 	}
192 	long baselineCount = baselineResults.getCount();
193 	long currentCount = buildResults.getCount();
194 	if (baselineCount > 1 && currentCount > 1) {
195 		double baselineError = baselineResults.getError();
196 		double currentError = buildResults.getError();
197 		values[BASELINE_ERROR_INDEX] = baselineError;
198 		values[BUILD_ERROR_INDEX] = currentError;
199 		values[DELTA_ERROR_INDEX] = Double.isNaN(baselineError)
200 				? currentError / baselineValue
201 				: Math.sqrt(baselineError*baselineError + currentError*currentError) / baselineValue;
202 	}
203 	return values;
204 }
205 */
206 
getScenarioResults(List scenarios, int searchedId)207 private ScenarioResults getScenarioResults(List scenarios, int searchedId) {
208 	int size = scenarios.size();
209 	for (int i=0; i<size; i++) {
210 		ScenarioResults scenarioResults = (ScenarioResults) scenarios.get(i);
211 		if (scenarioResults.id == searchedId) {
212 			return scenarioResults;
213 		}
214 	}
215 	return null;
216 }
217 
218 /**
219  * Returns a list of scenario results which have a summary
220  *
221  * @param global Indicates whether the summary must be global or not.
222  * @param config Configuration name
223  * @return A list of {@link ScenarioResults scenario results} which have a summary
224  */
getSummaryScenarios(boolean global, String config)225 public List getSummaryScenarios(boolean global, String config) {
226 	int size= size();
227 	List scenarios = new ArrayList(size);
228 	for (int i=0; i<size; i++) {
229 		ScenarioResults scenarioResults = (ScenarioResults) this.children.get(i);
230 		ConfigResults configResults = scenarioResults.getConfigResults(config);
231 		if (configResults != null) {
232 			BuildResults buildResults = configResults.getCurrentBuildResults();
233 			if ((global && buildResults.summaryKind == 1) || (!global && buildResults.summaryKind >= 0)) {
234 				scenarios.add(scenarioResults);
235 			}
236 		}
237 	}
238 	return scenarios;
239 }
240 
lastBuildName(int kind)241 private String lastBuildName(int kind) {
242 	String[] builds = getAllSortedBuildNames();
243 	int idx = builds.length-1;
244 	String lastBuildName = builds[idx--];
245 	switch (kind) {
246 		case 1: // no ref
247 			while (lastBuildName.startsWith(DB_Results.getDbBaselinePrefix())) {
248 				lastBuildName = builds[idx--];
249 			}
250 			break;
251 		case 2: // only I-build or M-build
252 			char ch = lastBuildName.charAt(0);
253 			while (ch != 'I' && ch != 'M') {
254 				lastBuildName = builds[idx--];
255 				ch = lastBuildName.charAt(0);
256 			}
257 			break;
258 		default:
259 			break;
260 	}
261 	return lastBuildName;
262 }
263 
264 /*
265  * Read local file contents and populate the results model with the collected
266  * information.
267  */
readLocalFile(File dir, List scenarios)268 String readLocalFile(File dir, List scenarios) throws FileNotFoundException {
269 //	if (!dir.exists()) return null;
270 	File dataFile = new File(dir, getName()+".dat");	//$NON-NLS-1$
271 	if (!dataFile.exists()) throw new FileNotFoundException();
272 	DataInputStream stream = null;
273 	try {
274 		// Read local file info
275 		stream = new DataInputStream(new BufferedInputStream(new FileInputStream(dataFile)));
276 		print(" - read local files info"); //$NON-NLS-1$
277 		String lastBuildName = stream.readUTF(); // first string is the build name
278 
279 		// Next field is the number of scenarios for the component
280 		int size = stream.readInt();
281 
282 		// Then follows all the scenario information
283 		for (int i=0; i<size; i++) {
284 			// ... which starts with the scenario id
285 			int scenario_id = stream.readInt();
286 			ScenarioResults scenarioResults = scenarios == null ? null : getScenarioResults(scenarios, scenario_id);
287 			if (scenarioResults == null) {
288 				// this can happen if scenario pattern does not cover all those stored in local data file
289 				// hence, creates a fake scenario to read the numbers and skip to the next scenario
290 				scenarioResults = new ScenarioResults(-1, null, null);
291 //				scenarioResults.parent = this;
292 //				scenarioResults.readData(stream);
293 				// Should no longer occur as we get all scenarios from database now
294 //				throw new RuntimeException("Unexpected unfound scenario!"); //$NON-NLS-1$
295 			}
296 			scenarioResults.parent = this;
297 			scenarioResults.printStream = this.printStream;
298 			scenarioResults.readData(stream);
299 			addChild(scenarioResults, true);
300 			if (this.printStream != null) this.printStream.print('.');
301 		}
302 		println();
303 		println("	=> "+size+" scenarios data were read from file "+dataFile); //$NON-NLS-1$ //$NON-NLS-2$
304 
305 		// Return last build name stored in the local files
306 		return lastBuildName;
307 	} catch (IOException ioe) {
308 		println("	!!! "+dataFile+" should be deleted as it contained invalid data !!!"); //$NON-NLS-1$ //$NON-NLS-2$
309 	} finally {
310 		try {
311 	        stream.close();
312         } catch (IOException e) {
313 	        // nothing else to do!
314         }
315 	}
316 	return null;
317 }
318 
319 /*
320  * Read the database values for a build name and a list of scenarios.
321  * The database is read only if the components does not already knows the
322  * given build (i.e. if it has not been already read) or if the force arguments is set.
323  */
updateBuild(String buildName, List scenarios, boolean force, File dataDir, SubMonitor subMonitor, PerformanceResults.RemainingTimeGuess timeGuess)324 void updateBuild(String buildName, List scenarios, boolean force, File dataDir, SubMonitor subMonitor, PerformanceResults.RemainingTimeGuess timeGuess) {
325 
326 	// Read all variations
327 	println("Component '"+this.name+"':"); //$NON-NLS-1$ //$NON-NLS-2$
328 
329 	// manage monitor
330 	int size = scenarios.size();
331 	subMonitor.setWorkRemaining(size+1);
332 	StringBuffer buffer = new StringBuffer("Component "); //$NON-NLS-1$
333 	buffer.append(this.name);
334 	buffer.append("..."); //$NON-NLS-1$
335 	String title = buffer.toString();
336 	subMonitor.subTask(title+timeGuess.display());
337 	timeGuess.count++;
338 	subMonitor.worked(1);
339 	if (subMonitor.isCanceled()) return;
340 
341 	// Read new values for the local result
342 	boolean dirty = false;
343 	long readTime = System.currentTimeMillis();
344 	String log = " - read scenarios from DB:"; //$NON-NLS-1$
345 	if (size > 0) {
346 		for (int i=0; i<size; i++) {
347 
348 			// manage monitor
349 			subMonitor.subTask(title+timeGuess.display());
350 			timeGuess.count++;
351 			if (log != null) {
352 				println(log);
353 				log = null;
354 			}
355 
356 			// read results
357 			ScenarioResults nextScenarioResults= (ScenarioResults) scenarios.get(i);
358 			ScenarioResults scenarioResults = (ScenarioResults) getResults(nextScenarioResults.id);
359 			if (scenarioResults == null) {
360 				// Scenario is not known yet, force an update
361 				scenarioResults = nextScenarioResults;
362 				scenarioResults.parent = this;
363 				scenarioResults.printStream = this.printStream;
364 				scenarioResults.updateBuild(buildName, true);
365 				dirty = true;
366 				addChild(scenarioResults, true);
367 			} else {
368 				if (scenarioResults.updateBuild(buildName, force)) {
369 					dirty = true;
370 				}
371 			}
372 			if (dataDir != null && dirty && (System.currentTimeMillis() - readTime) > 300000) { // save every 5mn
373 				writeData(buildName, dataDir, true, true);
374 				dirty = false;
375 				readTime = System.currentTimeMillis();
376 			}
377 
378 			// manage monitor
379 			subMonitor.worked(1);
380 			if (subMonitor.isCanceled()) return;
381 		}
382 	}
383 
384 	// Write local files
385 	if (dataDir != null) {
386 		writeData(buildName, dataDir, false, dirty);
387 	}
388 
389 	// Print global time
390 	printGlobalTime(readTime);
391 
392 }
393 
394 /*
395  * Write the component results data to the file '<component name>.dat' in the given directory.
396  */
writeData(String buildName, File dir, boolean temp, boolean dirty)397 void writeData(String buildName, File dir, boolean temp, boolean dirty) {
398 //	if (!dir.exists() && !dir.mkdirs()) {
399 //		System.err.println("can't create directory "+dir); //$NON-NLS-1$
400 //	}
401 	File tmpFile = new File(dir, getName()+".tmp"); //$NON-NLS-1$
402 	File dataFile = new File(dir, getName()+".dat"); //$NON-NLS-1$
403 	if (!dirty) { // only possible on final write
404 		if (tmpFile.exists()) {
405 			if (dataFile.exists()) dataFile.delete();
406 			tmpFile.renameTo(dataFile);
407 			println("	=> rename temporary file to "+dataFile); //$NON-NLS-1$
408 		}
409 		return;
410 	}
411 	if (tmpFile.exists()) {
412 		tmpFile.delete();
413 	}
414 	File file;
415 	if (temp) {
416 		file = tmpFile;
417 	} else {
418 		if (dataFile.exists()) {
419 			dataFile.delete();
420 		}
421 		file = dataFile;
422 	}
423 	try {
424 		DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
425 		try {
426 			int size = this.children.size();
427 			stream.writeUTF(lastBuildName(0));
428 			stream.writeInt(size);
429 			for (int i=0; i<size; i++) {
430 				ScenarioResults scenarioResults = (ScenarioResults) this.children.get(i);
431 				scenarioResults.write(stream);
432 			}
433 		}
434 		finally {
435 			stream.close();
436 			println("	=> extracted data "+(temp?"temporarily ":"")+"written in file "+file); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
437 		}
438 	} catch (FileNotFoundException e) {
439 		System.err.println("can't create output file"+file); //$NON-NLS-1$
440 	} catch (IOException e) {
441 		e.printStackTrace();
442 	}
443 }
444 
445 }
446