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.model; 12 13 import java.util.ArrayList; 14 import java.util.List; 15 import java.util.Vector; 16 17 import org.eclipse.test.internal.performance.data.Dim; 18 import org.eclipse.test.internal.performance.eval.StatisticsUtil; 19 import org.eclipse.test.internal.performance.results.db.*; 20 import org.eclipse.test.internal.performance.results.utils.Util; 21 import org.eclipse.ui.views.properties.ComboBoxPropertyDescriptor; 22 import org.eclipse.ui.views.properties.IPropertyDescriptor; 23 import org.eclipse.ui.views.properties.PropertyDescriptor; 24 import org.eclipse.ui.views.properties.TextPropertyDescriptor; 25 26 public class BuildResultsElement extends ResultsElement { 27 28 // Property descriptors 29 static final String P_ID_BUILD_DATE = "BuildResultsElement.date"; //$NON-NLS-1$ 30 static final String P_ID_BUILD_BASELINE = "BuildResultsElement.baseline"; //$NON-NLS-1$ 31 static final String P_ID_BUILD_COMMENT = "BuildResultsElement.comment"; //$NON-NLS-1$ 32 static final String P_ID_BUILD_SUMMARY_KIND = "BuildResultsElement.summarykind"; //$NON-NLS-1$ 33 static final String P_ID_BUILD_IS_BASELINE = "BuildResultsElement.isbaseline"; //$NON-NLS-1$ 34 static final String P_ID_BUILD_FAILURE = "BuildResultsElement.failure"; //$NON-NLS-1$ 35 static final String P_ID_BUILD_DELTA = "BuildResultsElement.delta"; //$NON-NLS-1$ 36 static final String P_ID_BUILD_ERROR = "BuildResultsElement.error"; //$NON-NLS-1$ 37 static final String P_ID_BUILD_TTEST = "BuildResultsElement.ttest"; //$NON-NLS-1$ 38 39 static final String P_STR_BUILD_DATE = "date"; //$NON-NLS-1$ 40 static final String P_STR_BUILD_COMMENT = "comment"; //$NON-NLS-1$ 41 static final String P_STR_BUILD_SUMMARY_KIND = "summary kind"; //$NON-NLS-1$ 42 static final String P_STR_BUILD_IS_BASELINE = "is baseline"; //$NON-NLS-1$ 43 static final String P_STR_BUILD_BASELINE = "baseline"; //$NON-NLS-1$ 44 static final String P_STR_BUILD_FAILURE = "failure"; //$NON-NLS-1$ 45 static final String P_STR_BUILD_DELTA = "delta with baseline"; //$NON-NLS-1$ 46 static final String P_STR_BUILD_ERROR = "delta error"; //$NON-NLS-1$ 47 static final String P_STR_BUILD_TTEST = "student's ttest"; //$NON-NLS-1$ 48 49 private static final TextPropertyDescriptor BUILD_DATE_DESCRIPTOR = new TextPropertyDescriptor(P_ID_BUILD_DATE, P_STR_BUILD_DATE); 50 private static final TextPropertyDescriptor BUILD_COMMENT_DESCRIPTOR = new TextPropertyDescriptor(P_ID_BUILD_COMMENT, P_STR_BUILD_COMMENT); 51 private static final TextPropertyDescriptor BUILD_SUMMARY_DESCRIPTOR = new TextPropertyDescriptor(P_ID_BUILD_SUMMARY_KIND, P_STR_BUILD_SUMMARY_KIND); 52 private static final PropertyDescriptor BUILD_IS_BASELINE_DESCRIPTOR = new PropertyDescriptor(P_ID_BUILD_IS_BASELINE, P_STR_BUILD_IS_BASELINE); 53 private static final PropertyDescriptor BUILD_BASELINE_DESCRIPTOR = new PropertyDescriptor(P_ID_BUILD_BASELINE, P_STR_BUILD_BASELINE); 54 private static final TextPropertyDescriptor BUILD_TEST_FAILURE_DESCRIPTOR = new TextPropertyDescriptor(P_ID_BUILD_FAILURE, P_STR_BUILD_FAILURE); 55 private static final PropertyDescriptor BUILD_TEST_DELTA_DESCRIPTOR = new PropertyDescriptor(P_ID_BUILD_DELTA, P_STR_BUILD_DELTA); 56 private static final PropertyDescriptor BUILD_TEST_ERROR_DESCRIPTOR = new PropertyDescriptor(P_ID_BUILD_ERROR, P_STR_BUILD_ERROR); 57 private static final PropertyDescriptor BUILD_STUDENTS_TTEST_DESCRIPTOR = new PropertyDescriptor(P_ID_BUILD_TTEST, P_STR_BUILD_TTEST); 58 59 private static Vector DESCRIPTORS; 60 static Vector initDescriptors(int status) { 61 DESCRIPTORS = new Vector(); 62 // Status category 63 DESCRIPTORS.add(getInfosDescriptor(status)); 64 DESCRIPTORS.add(getWarningsDescriptor(status)); 65 DESCRIPTORS.add(ERROR_DESCRIPTOR); 66 ERROR_DESCRIPTOR.setCategory("Status"); 67 // Results category 68 DESCRIPTORS.add(BUILD_DATE_DESCRIPTOR); 69 BUILD_DATE_DESCRIPTOR.setCategory("Results"); 70 DESCRIPTORS.add(BUILD_BASELINE_DESCRIPTOR); 71 BUILD_BASELINE_DESCRIPTOR.setCategory("Results"); 72 DESCRIPTORS.add(BUILD_COMMENT_DESCRIPTOR); 73 BUILD_COMMENT_DESCRIPTOR.setCategory("Results"); 74 DESCRIPTORS.add(BUILD_SUMMARY_DESCRIPTOR); 75 BUILD_SUMMARY_DESCRIPTOR.setCategory("Results"); 76 DESCRIPTORS.add(BUILD_IS_BASELINE_DESCRIPTOR); 77 BUILD_IS_BASELINE_DESCRIPTOR.setCategory("Results"); 78 DESCRIPTORS.add(BUILD_TEST_FAILURE_DESCRIPTOR); 79 BUILD_TEST_FAILURE_DESCRIPTOR.setCategory("Results"); 80 DESCRIPTORS.add(BUILD_TEST_DELTA_DESCRIPTOR); 81 BUILD_TEST_DELTA_DESCRIPTOR.setCategory("Results"); 82 DESCRIPTORS.add(BUILD_TEST_ERROR_DESCRIPTOR); 83 BUILD_TEST_ERROR_DESCRIPTOR.setCategory("Results"); 84 DESCRIPTORS.add(BUILD_STUDENTS_TTEST_DESCRIPTOR); 85 BUILD_STUDENTS_TTEST_DESCRIPTOR.setCategory("Results"); 86 // Survey category 87 DESCRIPTORS.add(COMMENT_DESCRIPTOR); 88 COMMENT_DESCRIPTOR.setCategory("Survey"); 89 return DESCRIPTORS; 90 } 91 static ComboBoxPropertyDescriptor getInfosDescriptor(int status) { 92 List list = new ArrayList(); 93 if ((status & SMALL_VALUE) != 0) { 94 list.add("This test and/or its variation has a small value, hence it may not be necessary to spend time on fixing it if a regression occurs"); 95 } 96 if ((status & STUDENT_TTEST) != 0) { 97 list.add("The student-t test error on this test is over the threshold"); 98 } 99 String[] infos = new String[list.size()]; 100 if (list.size() > 0) { 101 list.toArray(infos); 102 } 103 ComboBoxPropertyDescriptor infoDescriptor = new ComboBoxPropertyDescriptor(P_ID_STATUS_INFO, P_STR_STATUS_INFO, infos); 104 infoDescriptor.setCategory("Status"); 105 return infoDescriptor; 106 } 107 static PropertyDescriptor getWarningsDescriptor(int status) { 108 List list = new ArrayList(); 109 if ((status & BIG_ERROR) != 0) { 110 list.add("The error on this test is over the 3% threshold, hence its result may not be really reliable"); 111 } 112 if ((status & NOT_RELIABLE) != 0) { 113 list.add("The results history shows that the variation of its delta is over 20%, hence its result is surely not reliable"); 114 } 115 if ((status & NOT_STABLE) != 0) { 116 list.add("The results history shows that the variation of its delta is between 10% and 20%, hence its result may not be really reliable"); 117 } 118 if ((status & NO_BASELINE) != 0) { 119 list.add("There's no baseline to compare with"); 120 } 121 if ((status & SINGLE_RUN) != 0) { 122 list.add("This test has only one run, hence no error can be computed to verify if it's stable enough to be reliable"); 123 } 124 String[] warnings = new String[list.size()]; 125 if (list.size() > 0) { 126 list.toArray(warnings); 127 } 128 ComboBoxPropertyDescriptor warningDescriptor = new ComboBoxPropertyDescriptor(P_ID_STATUS_WARNING, P_STR_STATUS_WARNING, warnings); 129 warningDescriptor.setCategory("Status"); 130 return warningDescriptor; 131 } 132 static Vector getDescriptors() { 133 return DESCRIPTORS; 134 } 135 136 // Model info 137 boolean important; 138 boolean milestone; 139 140 public BuildResultsElement(AbstractResults results, ResultsElement parent) { 141 super(results, parent); 142 initInfo(); 143 } 144 145 public BuildResultsElement(String name, ResultsElement parent) { 146 super(name, parent); 147 initInfo(); 148 } 149 150 public int compareTo(Object o) { 151 if (o instanceof BuildResultsElement && getName() != null) { 152 BuildResultsElement element = (BuildResultsElement)o; 153 if (element.getName() != null) { 154 String buildDate = Util.getBuildDate(element.name); 155 return Util.getBuildDate(this.name).compareTo(buildDate); 156 } 157 } 158 return super.compareTo(o); 159 } 160 161 ResultsElement createChild(AbstractResults testResults) { 162 return null; 163 } 164 165 private BuildResults getBuildResults() { 166 return (BuildResults) this.results; 167 } 168 169 public Object[] getChildren(Object o) { 170 if (this.results == null) { 171 return new Object[0]; 172 } 173 if (this.children == null) { 174 initChildren(); 175 } 176 return this.children; 177 } 178 179 public Object getEditableValue() { 180 if (this.results == null) { 181 return "Build "+this.name; 182 } 183 return this.results.toString(); 184 } 185 186 /* (non-Javadoc) 187 * @see org.eclipse.ui.views.properties.IPropertySource#getPropertyDescriptors() 188 */ 189 public IPropertyDescriptor[] getPropertyDescriptors() { 190 Vector descriptors = getDescriptors(); 191 if (descriptors == null) { 192 descriptors = initDescriptors(getStatus()); 193 } 194 int size = descriptors.size(); 195 IPropertyDescriptor[] descriptorsArray = new IPropertyDescriptor[size]; 196 descriptorsArray[0] = getInfosDescriptor(getStatus()); 197 descriptorsArray[1] = getWarningsDescriptor(getStatus()); 198 for (int i=2; i<size; i++) { 199 descriptorsArray[i] = (IPropertyDescriptor) descriptors.get(i); 200 } 201 return descriptorsArray; 202 } 203 204 /* (non-Javadoc) 205 * @see org.eclipse.ui.views.properties.IPropertySource#getPropertyValue(java.lang.Object) 206 */ 207 public Object getPropertyValue(Object propKey) { 208 BuildResults buildResults = getBuildResults(); 209 if (buildResults != null) { 210 ConfigResults configResults = (ConfigResults) buildResults.getParent(); 211 BuildResults baselineResults = configResults.getBaselineBuildResults(buildResults.getName()); 212 if (propKey.equals(P_ID_BUILD_DATE)) 213 return buildResults.getDate(); 214 if (propKey.equals(P_ID_BUILD_COMMENT)) 215 return buildResults.getComment(); 216 if (propKey.equals(P_ID_BUILD_SUMMARY_KIND)) { 217 int summaryKind = buildResults.getSummaryKind(); 218 if (summaryKind == 1) { 219 return "global"; 220 } 221 if (summaryKind >= 0) { 222 return "component"; 223 } 224 return "none"; 225 } 226 if (propKey.equals(P_ID_BUILD_IS_BASELINE)) 227 return new Boolean(buildResults.isBaseline()); 228 if (propKey.equals(P_ID_BUILD_FAILURE)) 229 return buildResults.getFailure(); 230 if (baselineResults != null) { 231 if (propKey.equals(P_ID_BUILD_BASELINE)) { 232 return baselineResults.getName(); 233 } 234 double buildValue = buildResults.getValue(); 235 double baselineValue = baselineResults.getValue(); 236 double delta = (baselineValue - buildValue) / baselineValue; 237 if (Double.isNaN(delta)) { 238 if (propKey.equals(P_ID_BUILD_DELTA) || propKey.equals(P_ID_BUILD_ERROR)) { 239 return new Double(Double.NaN); 240 } 241 } else if (propKey.equals(P_ID_BUILD_DELTA)) { 242 return new Double(delta); 243 } else { 244 long baselineCount = baselineResults.getCount(); 245 long currentCount = buildResults.getCount(); 246 if (baselineCount > 1 && currentCount > 1) { 247 if (propKey.equals(P_ID_BUILD_TTEST)) { 248 double ttestValue = Util.computeTTest(baselineResults, buildResults); 249 int degreeOfFreedom = (int) (baselineResults.getCount()+buildResults.getCount()-2); 250 if (ttestValue >= 0 && StatisticsUtil.getStudentsT(degreeOfFreedom, StatisticsUtil.T90) >= ttestValue) { 251 return new Double(ttestValue); 252 } 253 } 254 if (propKey.equals(P_ID_BUILD_ERROR)) { 255 double baselineError = baselineResults.getError(); 256 double currentError = buildResults.getError(); 257 double error = Double.isNaN(baselineError) 258 ? currentError / baselineValue 259 : Math.sqrt(baselineError*baselineError + currentError*currentError) / baselineValue; 260 return new Double(error); 261 } 262 } else { 263 if (propKey.equals(P_ID_BUILD_ERROR)) 264 return new Double(-1); 265 } 266 } 267 } 268 } 269 if (propKey.equals(P_ID_STATUS_ERROR)) { 270 if ((getStatus() & BIG_DELTA) != 0) { 271 return "The delta on this test is over the 10% threshold, hence may indicate a possible regression."; 272 } 273 } 274 return super.getPropertyValue(propKey); 275 } 276 277 /** 278 * Return the statistics of the build along its history. 279 * 280 * @return An array of double built as follows: 281 * <ul> 282 * <li>0: numbers of values</li> 283 * <li>1: mean of values</li> 284 * <li>2: standard deviation of these values</li> 285 * <li>3: coefficient of variation of these values</li> 286 * </ul> 287 */ 288 double[] getStatistics() { 289 if (this.statistics == null) { 290 this.statistics = ((ConfigResults)getBuildResults().getParent()).getStatistics(Util.BASELINE_BUILD_PREFIXES); 291 } 292 return this.statistics; 293 } 294 295 void initChildren() { 296 BuildResults buildResults = (BuildResults) this.results; 297 Dim[] dimensions = buildResults.getDimensions(); 298 int length = dimensions.length; 299 this.children = new DimResultsElement[length]; 300 for (int i=0; i<length; i++) { 301 this.children[i] = new DimResultsElement(this.results, this, dimensions[i]); 302 } 303 } 304 305 /* 306 * Init information 307 */ 308 void initInfo() { 309 this.milestone = Util.isMilestone(getName()); 310 this.important = this.milestone || Util.getNextMilestone(this.name) == null; 311 } 312 313 void initStatus() { 314 if (this.results == null) { 315 if (this.parent.isInitialized()) { 316 if (((PerformanceResultsElement) this.parent).hasRead(this)) { 317 this.status = READ; 318 } else { 319 this.status = UNREAD; 320 } 321 } else { 322 this.status = UNKNOWN; 323 } 324 } else if (getBuildResults().isBaseline()) { 325 // TODO (frederic) report high variation in baseline results along history 326 this.status = READ; 327 } else { 328 initStatus(getBuildResults()); 329 } 330 } 331 332 /** 333 * Returns whether the build is important to be shown. 334 * This is the case for milestone builds or for the last builds. 335 * 336 * @return <code>true</code> or <code>false</code> . 337 */ 338 public boolean isImportant() { 339 return this.important; 340 } 341 342 /** 343 * Returns whether the build is a milestone one or not. 344 * 345 * @return <code>true</code> or <code>false</code> . 346 */ 347 public boolean isMilestone() { 348 return this.milestone; 349 } 350 351 public boolean isRead() { 352 return (getStatus() & STATE_MASK) == READ; 353 } 354 355 public boolean isUnknown() { 356 return (getStatus() & STATE_MASK) == UNKNOWN; 357 } 358 359 /* (non-Javadoc) 360 * @see java.lang.Object#toString() 361 */ 362 public String toString() { 363 return getName(); 364 } 365 public boolean isBefore(String build) { 366 if (this.results != null) { 367 return Util.getBuildDate(this.name).compareTo(Util.getBuildDate(build)) <= 0; 368 } 369 return true; 370 } 371 372 } 373