• 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.utils;
12 
13 import java.io.File;
14 import java.io.FileInputStream;
15 import java.io.FileNotFoundException;
16 import java.io.FileOutputStream;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.OutputStream;
20 import java.text.NumberFormat;
21 import java.text.ParseException;
22 import java.text.SimpleDateFormat;
23 import java.util.ArrayList;
24 import java.util.Calendar;
25 import java.util.Comparator;
26 import java.util.Date;
27 import java.util.GregorianCalendar;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.StringTokenizer;
31 
32 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
33 import org.eclipse.test.internal.performance.results.db.BuildResults;
34 import org.eclipse.test.internal.performance.results.db.DB_Results;
35 
36 /**
37  * Utility methods for statistics. Got from org.eclipse.test.performance
38  * framework
39  */
40 public final class Util implements IPerformancesConstants {
41 
42 	// Percentages
43 	public static final NumberFormat PERCENTAGE_FORMAT = NumberFormat.getPercentInstance(Locale.US);
44 	static {
45 		PERCENTAGE_FORMAT.setMaximumFractionDigits(2);
46 	}
47 	public static final NumberFormat DOUBLE_FORMAT = NumberFormat.getNumberInstance(Locale.US);
48 	static {
49 		DOUBLE_FORMAT.setMaximumFractionDigits(2);
50 	}
51 
52 	// Strings
53 	public static final String LINE_SEPARATOR = System.getProperty("line.separator");
54 
55 	// Build prefixes
56 	public static final List ALL_BUILD_PREFIXES = new ArrayList(3);
57 	static {
58 		ALL_BUILD_PREFIXES.add("I");
59 		ALL_BUILD_PREFIXES.add("N");
60 		ALL_BUILD_PREFIXES.add("M");
61 	}
62 	public static final List BUILD_PREFIXES = new ArrayList(2);
63 	static {
64 		BUILD_PREFIXES.add("I");
65 		BUILD_PREFIXES.add("N");
66 	}
67 	public static final List MAINTENANCE_BUILD_PREFIXES = new ArrayList(2);
68 	static {
69 		MAINTENANCE_BUILD_PREFIXES.add("I");
70 		MAINTENANCE_BUILD_PREFIXES.add("M");
71 	}
72 	public static final List BASELINE_BUILD_PREFIXES = new ArrayList(1);
73 	static {
DB_Results.getDbBaselinePrefix()74 		BASELINE_BUILD_PREFIXES.add(DB_Results.getDbBaselinePrefix());
75 	}
76 
77 	// Milestones constants
78 	private static String[] MILESTONES;
79 	public static final BuildDateComparator BUILD_DATE_COMPARATOR = new BuildDateComparator();
80 
81 static class BuildDateComparator implements Comparator {
compare(Object o1, Object o2)82 	public int compare(Object o1, Object o2) {
83 		String s1 = (String) o1;
84 		String s2 = (String) o2;
85 		return getBuildDate(s1).compareTo(getBuildDate(s2));
86 	}
87 }
88 
initMilestones()89 private static void initMilestones() {
90 	String version = DB_Results.getDbVersion();
91 
92 	// Initialize reference version and database directory
93 	char mainVersion = version.charAt(1);
94 	char minorVersion = version.charAt(2);
95 
96 	// Initialize milestones
97 	if (mainVersion == '3') {
98 		switch (minorVersion) {
99 			case '3':
100 			case '4':
101 				throw new RuntimeException("Version "+mainVersion+'.'+minorVersion+" is no longer supported!");
102 			case '5':
103 				MILESTONES = V35_MILESTONES;
104 				break;
105 			case '6':
106 				MILESTONES = V36_MILESTONES;
107 				break;
108 			default:
109 				throw new RuntimeException("Version "+mainVersion+'.'+minorVersion+" is not supported yet!");
110 		}
111 	} else {
112 		throw new RuntimeException("Version "+mainVersion+'.'+minorVersion+" is not supported yet!");
113 	}
114 }
115 
116 // Static information for time and date
117 public static final int ONE_MINUTE = 60000;
118 public static final long ONE_HOUR = 3600000L;
119 public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmm"); //$NON-NLS-1$
120 
121 /**
122  * Compute the student t-test values.
123  *
124  * @see "http://en.wikipedia.org/wiki/Student's_t-test"
125  *
126  * @param baselineResults The baseline build
127  * @param buildResults The current build
128  * @return The student t-test value as a double.
129  */
computeTTest(BuildResults baselineResults, BuildResults buildResults)130 public static double computeTTest(BuildResults baselineResults, BuildResults buildResults) {
131 
132 	double ref = baselineResults.getValue();
133 	double val = buildResults.getValue();
134 
135 	double delta = ref - val;
136 	long dfRef = baselineResults.getCount() - 1;
137 	double sdRef = baselineResults.getDeviation();
138 	long dfVal = buildResults.getCount() - 1;
139 	double sdVal = buildResults.getDeviation();
140 	// TODO if the stdev's are not sufficiently similar, we have to take a
141 	// different approach
142 
143 	if (!Double.isNaN(sdRef) && !Double.isNaN(sdVal) && dfRef > 0 && dfVal > 0) {
144 		long df = dfRef + dfVal;
145 		double sp_square = (dfRef * sdRef * sdRef + dfVal * sdVal * sdVal) / df;
146 
147 		double se_diff = Math.sqrt(sp_square * (1.0 / (dfRef + 1) + 1.0 / (dfVal + 1)));
148 		double t = Math.abs(delta / se_diff);
149 		return t;
150 	}
151 
152 	return -1;
153 }
154 
155 /**
156  * Copy a file to another location.
157  *
158  * @param src the source file.
159  * @param dest the destination.
160  * @return <code>true</code> if the file was successfully copied,
161  * 	<code>false</code> otherwise.
162  */
copyFile(File src, File dest)163 public static boolean copyFile(File src, File dest) {
164 
165 	try {
166 		InputStream in = new FileInputStream(src);
167 		OutputStream out = new FileOutputStream(dest);
168 		byte[] buf = new byte[1024];
169 		int len;
170 		while ((len = in.read(buf)) > 0) {
171 			out.write(buf, 0, len);
172 		}
173 		in.close();
174 		out.close();
175 	} catch (FileNotFoundException e) {
176 		e.printStackTrace();
177 		return false;
178 	} catch (IOException e) {
179 		e.printStackTrace();
180 		return false;
181 	}
182 	return true;
183 }
184 
185 /**
186  * Copy a file content to another location.
187  *
188  * @param in the input stream.
189  * @param dest the destination.
190  * @return <code>true</code> if the file was successfully copied,
191  * 	<code>false</code> otherwise.
192  */
copyStream(InputStream in, File dest)193 public static boolean copyStream(InputStream in, File dest) {
194 
195 	try {
196 		OutputStream out = new FileOutputStream(dest);
197 		byte[] buf = new byte[1024];
198 		int len;
199 		while ((len = in.read(buf)) > 0) {
200 			out.write(buf, 0, len);
201 		}
202 		in.close();
203 		out.close();
204 	} catch (FileNotFoundException e) {
205 		e.printStackTrace();
206 		return false;
207 	} catch (IOException e) {
208 		e.printStackTrace();
209 		return false;
210 	}
211 	return true;
212 }
213 
214 /**
215  * Return the build date as yyyyMMddHHmm.
216  *
217  * @param buildName The build name (e.g. I20090806-0100)
218  * @return The date as a string.
219  */
getBuildDate(String buildName)220 public static String getBuildDate(String buildName) {
221 	return getBuildDate(buildName, DB_Results.getDbBaselinePrefix());
222 }
223 
224 /**
225  * Return the build date as yyyyMMddHHmm.
226  *
227  * @param buildName The build name (e.g. I20090806-0100)
228  * @param baselinePrefix The baseline prefix (e.g. {@link DB_Results#getDbBaselinePrefix()})
229  * @return The date as a string.
230  */
getBuildDate(String buildName, String baselinePrefix)231 public static String getBuildDate(String buildName, String baselinePrefix) {
232 
233 	// Baseline name
234 	if (baselinePrefix != null && buildName.startsWith(baselinePrefix)) {
235 		int length = buildName.length();
236 		return buildName.substring(length-12, length);
237 	}
238 
239 	// Build name
240 	char first = buildName.charAt(0);
241 	if (first == 'N' || first == 'I' || first == 'M') { // TODO (frederic) should be buildIdPrefixes...
242 		return buildName.substring(1, 9)+buildName.substring(10, 14);
243 	}
244 
245 	// Try with date format
246 	int length = buildName.length() - 12 /* length of date */;
247 	for (int i=0; i<=length; i++) {
248 		try {
249 			String substring = i == 0 ? buildName : buildName.substring(i);
250 			Util.DATE_FORMAT.parse(substring);
251 			return substring; // if no exception is raised then the substring has a correct date format => return it
252 		} catch(ParseException ex) {
253 			// skip
254 		}
255 	}
256 	return null;
257 }
258 
259 /**
260  * Returns the date of the milestone corresponding at the given index.
261  *
262  * @param index The index of the milestone
263  * @return The date as a YYYYMMDD-hhmm string.
264  */
getMilestoneDate(int index)265 public static String getMilestoneDate(int index) {
266 	int length = getMilestonesLength();
267 	if (index >= length) return null;
268 	int dash = MILESTONES[index].indexOf('-');
269 	return MILESTONES[index].substring(dash+1);
270 }
271 
272 /**
273  * Returns the milestone matching the given build name.
274  *
275  * @param buildName The name of the build
276  * @return The milestone as a string (e.g. M1)
277  */
getMilestone(String buildName)278 public static String getMilestone(String buildName) {
279 	if (buildName != null && buildName.length() >= 12) {
280 		int length = getMilestonesLength();
281 		String buildDate = getBuildDate(buildName, DB_Results.getDbBaselinePrefix());
282 		for (int i=0; i<length; i++) {
283 			int start = MILESTONES[i].indexOf(buildDate);
284 			if (start > 0) {
285 				return MILESTONES[i];
286 			}
287 		}
288 	}
289 	return null;
290 }
291 
292 /**
293  * Returns the name the milestone matching the given build name.
294  *
295  * @param buildName The name of the build
296  * @return The milestone name as a string (e.g. M1)
297  */
getMilestoneName(String buildName)298 public static String getMilestoneName(String buildName) {
299 	if (buildName != null && buildName.length() >= 12) {
300 		int length = getMilestonesLength();
301 		String buildDate = getBuildDate(buildName, DB_Results.getDbBaselinePrefix());
302 		for (int i=0; i<length; i++) {
303 			int start = MILESTONES[i].indexOf(buildDate);
304 			if (start > 0) {
305 				return MILESTONES[i].substring(0, start - 1);
306 			}
307 		}
308 	}
309 	return null;
310 }
311 
312 /**
313  * Returns whether the given build name is a milestone or not.
314  *
315  * @param buildName The build name
316  * @return <code>true</code> if the build name matches a milestone one,
317  * 	<code>false</code> otherwise.
318  */
isMilestone(String buildName)319 public static boolean isMilestone(String buildName) {
320 	return getMilestoneName(buildName) != null;
321 }
322 
323 /**
324  * Returns the name of the milestone which run after the given build name
325  * or <code>null</code> if there's no milestone since the build has run.
326  *
327  * @param buildName The build name
328  * @return <code>true</code> if the build name matches a milestone one,
329  * 	<code>false</code> otherwise.
330  */
getNextMilestone(String buildName)331 public static String getNextMilestone(String buildName) {
332 	int length = getMilestonesLength();
333 	String buildDate = getBuildDate(buildName);
334 	for (int i=0; i<length; i++) {
335 		String milestoneDate = MILESTONES[i].substring(MILESTONES[i].indexOf('-')+1);
336 		if (milestoneDate.compareTo(buildDate) > 0) {
337 			return milestoneDate;
338 		}
339 	}
340 	return null;
341 }
342 
343 /**
344  * Return the number of milestones.
345  *
346  * @return The number as an int
347  */
getMilestonesLength()348 public static int getMilestonesLength() {
349 	if (MILESTONES == null) initMilestones();
350 	int length = MILESTONES.length;
351 	return length;
352 }
353 
354 /**
355  * @deprecated
356  */
matchPattern(String name, String pattern)357 public static boolean matchPattern(String name, String pattern) {
358 	if (pattern.equals("*")) return true; //$NON-NLS-1$
359 	if (pattern.indexOf('*') < 0 && pattern.indexOf('?') < 0) {
360 		pattern += "*"; //$NON-NLS-1$
361 	}
362 	StringTokenizer tokenizer = new StringTokenizer(pattern, "*?", true); //$NON-NLS-1$
363 	int start = 0;
364 	String previous = ""; //$NON-NLS-1$
365 	while (tokenizer.hasMoreTokens()) {
366 		String token = tokenizer.nextToken();
367 		if (!token.equals("*") && !token.equals("?")) { //$NON-NLS-1$ //$NON-NLS-2$
368 			if (previous.equals("*")) { //$NON-NLS-1$
369 				int idx = name.substring(start).indexOf(token);
370 				if (idx < 0) return false;
371 				start += idx;
372 			} else {
373 				if (previous.equals("?")) start++; //$NON-NLS-1$
374 				if (!name.substring(start).startsWith(token)) return false;
375 			}
376 			start += token.length();
377 		}
378 		previous = token;
379 	}
380 	if (previous.equals("*")) { //$NON-NLS-1$
381 		return true;
382 	} else if (previous.equals("?")) { //$NON-NLS-1$
383 		return name.length() == start;
384 	}
385 	return name.endsWith(previous);
386 }
387 
388 /**
389  * @deprecated
390  */
round(double value)391 public static double round(double value) {
392 	return Math.round(value * 10000) / 10000.0;
393 }
394 
395 /**
396  * @deprecated
397  */
round(double value, int precision)398 public static double round(double value, int precision) {
399 	if (precision < 0) {
400 		throw new IllegalArgumentException("Should have a precision at least greater than 0!");
401 	}
402 	if (precision == 0) return (long) Math.floor(value);
403 	double factor = 10;
404 	int n = 1;
405 	while (n++ < precision)
406 		factor *= 10;
407 	return Math.round(value * factor) / factor;
408 }
409 
410 /**
411  * Returns a string to display the given time as a duration
412  * formatted as "hh:mm:ss".
413  *
414  * @param time The time to format as a long.
415  * @return The formatted string.
416  */
timeChrono(long time)417 public static String timeChrono(long time) {
418 	if (time < 1000) { // less than 1s
419 		return "00:00:00"; //$NON-NLS-1$
420 	}
421 	StringBuffer buffer = new StringBuffer();
422 	int seconds = (int) (time / 1000);
423 	if (seconds < 60) {
424 		buffer.append("00:00:"); //$NON-NLS-1$
425 		if (seconds < 10) buffer.append('0');
426 		buffer.append(seconds);
427 	} else {
428 		int minutes = seconds / 60;
429 		if (minutes < 60) {
430 			buffer.append("00:"); //$NON-NLS-1$
431 			if (minutes < 10) buffer.append('0');
432 			buffer.append(minutes);
433 			buffer.append(':');
434 			seconds = seconds % 60;
435 			if (seconds < 10) buffer.append('0');
436 			buffer.append(seconds);
437 		} else {
438 			int hours = minutes / 60;
439 			if (hours < 10) buffer.append('0');
440 			buffer.append(hours);
441 			buffer.append(':');
442 			minutes = minutes % 60;
443 			if (minutes < 10) buffer.append('0');
444 			buffer.append(minutes);
445 			buffer.append(':');
446 			seconds = seconds % 60;
447 			if (seconds < 10) buffer.append('0');
448 			buffer.append(seconds);
449 		}
450 	}
451 	return buffer.toString();
452 }
453 
454 /**
455  * Returns a string to display the given time as the hour of the day
456  * formatted as "hh:mm:ss".
457  *
458  * @param time The time to format as a long.
459  * @return The formatted string.
460  */
timeEnd(long time)461 public static String timeEnd(long time) {
462 	GregorianCalendar calendar = new GregorianCalendar();
463 	calendar.add(Calendar.SECOND, (int)(time/1000));
464 	Date date = calendar.getTime();
465 	SimpleDateFormat dateFormat = new SimpleDateFormat("KK:mm:ss"); //$NON-NLS-1$
466 	return dateFormat.format(date);
467 }
468 
469 /**
470  * Returns a string to display the given time as a duration
471  * formatted as:
472  *	<ul>
473  *	<li>"XXXms" if the duration is less than 0.1s (e.g. "543ms")</li>
474  *	<li>"X.YYs" if the duration is less than 1s (e.g. "5.43s")</li>
475  *	<li>"XX.Ys" if the duration is less than 1mn (e.g. "54.3s")</li>
476  *	<li>"XXmn XXs" if the duration is less than 1h (e.g. "54mn 3s")</li>
477  *	<li>"XXh XXmn XXs" if the duration is over than 1h (e.g. "5h 4mn 3s")</li>
478  *	</ul>
479  *
480  * @param time The time to format as a long.
481  * @return The formatted string.
482  */
timeString(long time)483 public static String timeString(long time) {
484 	NumberFormat format = NumberFormat.getInstance();
485 	format.setMaximumFractionDigits(1);
486 	StringBuffer buffer = new StringBuffer();
487 	if (time == 0) {
488 		// print nothing
489 	} if (time < 100) { // less than 0.1s
490 		buffer.append(time);
491 		buffer.append("ms"); //$NON-NLS-1$
492 	} else if (time < 1000) { // less than 1s
493 		if ((time%100) != 0) {
494 			format.setMaximumFractionDigits(2);
495 		}
496 		buffer.append(format.format(time/1000.0));
497 		buffer.append("s"); //$NON-NLS-1$
498 	} else if (time < Util.ONE_MINUTE) {  // less than 1mn
499 		if ((time%1000) == 0) {
500 			buffer.append(time/1000);
501 		} else {
502 			buffer.append(format.format(time/1000.0));
503 		}
504 		buffer.append("s"); //$NON-NLS-1$
505 	} else if (time < Util.ONE_HOUR) {  // less than 1h
506 		buffer.append(time/Util.ONE_MINUTE).append("mn "); //$NON-NLS-1$
507 		long seconds = time%Util.ONE_MINUTE;
508 		buffer.append(seconds/1000);
509 		buffer.append("s"); //$NON-NLS-1$
510 	} else {  // more than 1h
511 		long h = time / Util.ONE_HOUR;
512 		buffer.append(h).append("h "); //$NON-NLS-1$
513 		long m = (time % Util.ONE_HOUR) / Util.ONE_MINUTE;
514 		buffer.append(m).append("mn "); //$NON-NLS-1$
515 		long seconds = m%Util.ONE_MINUTE;
516 		buffer.append(seconds/1000);
517 		buffer.append("s"); //$NON-NLS-1$
518 	}
519 	return buffer.toString();
520 }
521 
Util()522 private Util() {
523 	// don't instantiate
524 }
525 
526 /**
527  * Set the milestones.
528  *
529  * @param items The milestones list (e.g. {@link IPerformancesConstants#V35_MILESTONES}).
530  */
setMilestones(String[] items)531 public static void setMilestones(String[] items) {
532 	MILESTONES = items;
533 }
534 
535 /**
536  * Init the milestones from preferences
537  *
538  * @param preferences The preferences from which got milestones list
539  */
initMilestones(IEclipsePreferences preferences)540 public static void initMilestones(IEclipsePreferences preferences) {
541 	int eclipseVersion = preferences.getInt(IPerformancesConstants.PRE_ECLIPSE_VERSION, IPerformancesConstants.DEFAULT_ECLIPSE_VERSION);
542 	String prefix = IPerformancesConstants.PRE_MILESTONE_BUILDS + "." + eclipseVersion;
543 	int index = 0;
544 	String milestone = preferences.get(prefix + index, null);
545 	String[] milestones = new String[20];
546 	while (milestone != null) {
547 		milestones[index] = milestone;
548 		index++;
549 		milestone = preferences.get(prefix + index, null);
550 	}
551 	int length = milestones.length;
552 	if (index < length) {
553 		System.arraycopy(milestones, 0, milestones = new String[index], 0, index);
554 	}
555 	MILESTONES = milestones;
556 }
557 }
558