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.DataInputStream; 14 import java.io.DataOutputStream; 15 import java.io.IOException; 16 import java.util.Arrays; 17 import java.util.Comparator; 18 import java.util.HashSet; 19 import java.util.List; 20 import java.util.Set; 21 import java.util.StringTokenizer; 22 23 import org.eclipse.test.internal.performance.results.utils.Util; 24 25 26 /** 27 * Class to handle performance results of a component's scenario 28 * (for example 'org.eclipse.jdt.core.FullSourceWorkspaceSearchTest#searchAllTypeNames()'). 29 * 30 * It gives access to results for each configuration run on this scenario. 31 * 32 * @see ConfigResults 33 */ 34 public class ScenarioResults extends AbstractResults { 35 String fileName; 36 String label; 37 String shortName; 38 39 public ScenarioResults(int id, String name, String shortName) { 40 super(null, id); 41 this.name = name; 42 this.label = shortName; 43 } 44 45 /* 46 * Complete results with additional database information. 47 */ 48 void completeResults(String lastBuildName) { 49 String[] builds = DB_Results.getBuilds(); 50 class BuildDateComparator implements Comparator { 51 public int compare(Object o1, Object o2) { 52 String s1 = (String) o1; 53 String s2 = (String) o2; 54 return Util.getBuildDate(s1).compareTo(Util.getBuildDate(s2)); 55 } 56 } 57 BuildDateComparator comparator = new BuildDateComparator(); 58 Arrays.sort(builds, comparator); 59 int idx = Arrays.binarySearch(builds, lastBuildName, comparator); 60 if (idx < 0) { 61 builds = null; 62 } else { 63 int size = builds.length - ++idx; 64 System.arraycopy(builds, idx, builds = new String[size], 0, size); 65 } 66 // String[] builds = null; 67 int size = size(); 68 for (int i=0; i<size; i++) { 69 ConfigResults configResults = (ConfigResults) this.children.get(i); 70 configResults.completeResults(builds); 71 } 72 } 73 74 /** 75 * Returns the first configuration baseline build name. 76 * 77 * @return The name of the baseline build 78 * @see ConfigResults#getBaselineBuildName() 79 */ 80 public String getBaselineBuildName() { 81 int size = size(); 82 StringBuffer buffer = new StringBuffer(); 83 for (int i=0; i<size; i++) { 84 ConfigResults configResults = (ConfigResults) this.children.get(i); 85 if (configResults.isValid()) { 86 return configResults.getBaselineBuildName(); 87 /* TODO (frederic) decide what return when baseline is not the same on all configs... 88 * Currently returns the first found, but may be a comma-separated list? 89 String baselineName = configResults.getBaselineBuildName(); 90 if (buffer.indexOf(baselineName) < 0) { 91 if (buffer.length() > 0) buffer.append('|'); 92 buffer.append(baselineName); 93 } 94 */ 95 } 96 } 97 return buffer.toString(); 98 } 99 100 Set getAllBuildNames() { 101 Set buildNames = new HashSet(); 102 int size = size(); 103 for (int i=0; i<size; i++) { 104 ConfigResults configResults = (ConfigResults) this.children.get(i); 105 List builds = configResults.getBuilds(null); 106 int length = builds.size(); 107 for (int j=0; j<length; j++) { 108 buildNames.add(((BuildResults)builds.get(j)).getName()); 109 } 110 } 111 return buildNames; 112 } 113 114 /** 115 * Return the results of the given configuration. 116 * 117 * @param config The configuration name 118 * @return The {@link ConfigResults results} for the given configuration 119 * or <code>null</code> if none was found. 120 */ 121 public ConfigResults getConfigResults(String config) { 122 return (ConfigResults) getResults(config); 123 } 124 125 /** 126 * Return a name which can be used as a file name to store information 127 * related to this scenario. This name does not contain the extension. 128 * 129 * @return The file name 130 */ 131 public String getFileName() { 132 if (this.fileName == null) { 133 this.fileName = "Scenario" + this.id; //$NON-NLS-1$ 134 } 135 return this.fileName; 136 } 137 138 /** 139 * Returns the scenario label. If no label exist as there's no associated summary, 140 * then the short name is returned 141 * 142 * @return The label of the scenario or it's short name if no summary exists 143 */ 144 public String getLabel() { 145 return this.label == null ? getShortName() : this.label; 146 } 147 148 /** 149 * Returns the short name of the scenario. Short name is the name scenario 150 * from which package declaration has been removed. 151 * 152 * @return The scenario short name 153 */ 154 public String getShortName() { 155 if (this.shortName == null) { 156 // Remove class name qualification 157 int testSeparator = this.name.indexOf('#'); 158 boolean hasClassName = testSeparator >= 0; 159 if (!hasClassName) { 160 testSeparator = this.name.lastIndexOf('.'); 161 if (testSeparator <= 0) { 162 return this.shortName = this.name; 163 } 164 } 165 int classSeparator = this.name.substring(0, testSeparator).lastIndexOf('.'); 166 if (classSeparator < 0) { 167 return this.shortName = this.name; 168 } 169 int length = this.name.length(); 170 String testName = this.name.substring(classSeparator+1, length); 171 if (!hasClassName && testName.startsWith("test.")) { // specific case for swt... //$NON-NLS-1$ 172 testName = testName.substring(5); 173 } 174 175 // Remove qualification from test name 176 StringTokenizer tokenizer = new StringTokenizer(testName, " :,", true); //$NON-NLS-1$ 177 StringBuffer buffer = new StringBuffer(tokenizer.nextToken()); 178 while (tokenizer.hasMoreTokens()) { 179 String token = tokenizer.nextToken(); 180 char fc = token.charAt(0); 181 while (fc == ' ' || fc == ',' || fc == ':') { 182 buffer.append(token); // add the separator 183 token = tokenizer.nextToken(); 184 fc = token.charAt(0); 185 } 186 int last = token.lastIndexOf('.'); 187 if (last >= 3) { 188 int first = token .indexOf('.'); 189 if (first == last) { 190 buffer.append(token); 191 } else { 192 buffer.append(token.substring(last+1)); 193 } 194 } else { 195 buffer.append(token); 196 } 197 } 198 this.shortName = buffer.toString(); 199 } 200 return this.shortName; 201 } 202 203 /** 204 * Returns whether one of the scenario's config has a summary or not. 205 * 206 * @return <code>true</code> if one of the scenario's config has a summary 207 * <code>false</code> otherwise. 208 */ 209 public boolean hasSummary() { 210 int size = size(); 211 for (int i=0; i<size; i++) { 212 ConfigResults configResults = (ConfigResults) this.children.get(i); 213 BuildResults currentBuildResults = configResults.getCurrentBuildResults(); 214 if (currentBuildResults != null && currentBuildResults.hasSummary()) return true; 215 } 216 return false; 217 } 218 219 /* (non-Javadoc) 220 * @see org.eclipse.test.internal.performance.results.AbstractResults#hashCode() 221 */ 222 public int hashCode() { 223 return this.id; 224 } 225 226 /** 227 * Returns whether the current scenario is valid or not. 228 * 229 * @return <code>true</code> if all the builds contained in the database are 230 * known by the scenario (ie. at least one its configuration knows each of the 231 * db builds), <code>false</code> otherwise. 232 */ 233 public boolean isValid() { 234 int size = this.children.size(); 235 for (int i=0; i<size; i++) { 236 ConfigResults configResults = (ConfigResults) this.children.get(i); 237 if (configResults.isValid()) { 238 return true; 239 } 240 } 241 return false; 242 } 243 244 /** 245 * Returns whether the current build of the given config has valid results or not. 246 * 247 * @param config The name of the configuration 248 * @return <code>true</code> if the build has valid results 249 * <code>false</code> otherwise. 250 */ 251 public boolean isValid(String config) { 252 return getResults(config) != null; 253 } 254 255 /** 256 * Returns whether the current scenario knows a build or not. 257 * 258 * @param buildName The name of the build 259 * @return <code>true</code> if the at least one of scenario configuration 260 * knows the given build, <code>false</code> otherwise. 261 */ 262 public boolean knowsBuild(String buildName) { 263 String[] buildNames = buildName == null 264 ? DB_Results.getBuilds() 265 : new String[] { buildName }; 266 Set scenarioBuilds = getAllBuildNames(); 267 int length = buildNames.length; 268 for (int i=0; i<length; i++) { 269 if (!scenarioBuilds.contains(buildNames[i])) { 270 return false; 271 } 272 } 273 return true; 274 } 275 276 /* 277 * Read scenario results information from database. 278 * 279 void read(String buildName, long lastBuildTime) { 280 281 // Get values 282 print(" + scenario '"+getShortName()+"': values..."); //$NON-NLS-1$ //$NON-NLS-2$ 283 long start = System.currentTimeMillis(); 284 String configPattern = getPerformance().getConfigurationsPattern(); 285 DB_Results.queryScenarioValues(this, configPattern, buildName, lastBuildTime); 286 print(timeString(System.currentTimeMillis()-start)); 287 288 // Set baseline and current builds 289 print(", infos..."); //$NON-NLS-1$ 290 start = System.currentTimeMillis(); 291 int size = size(); 292 String[] builds = buildName == null ? null : new String[] { buildName }; 293 for (int i=0; i<size; i++) { 294 ConfigResults configResults = (ConfigResults) this.children.get(i); 295 configResults.completeResults(builds); 296 } 297 println(timeString(System.currentTimeMillis()-start)); 298 } 299 */ 300 301 /* 302 * Read data from a local file 303 */ 304 void readData(DataInputStream stream) throws IOException { 305 306 // Read data stored locally 307 int size = stream.readInt(); 308 for (int i=0; i<size; i++) { 309 int config_id = stream.readInt(); 310 ConfigResults configResults = (ConfigResults) getResults(config_id); 311 if (configResults == null) { 312 configResults = new ConfigResults(this, config_id); 313 addChild(configResults, true); 314 } 315 configResults.readData(stream); 316 } 317 } 318 319 /* 320 * Read new data from the database. 321 * This is typically needed when the build results are not in the local file... 322 * 323 boolean readNewData(String lastBuildName, boolean force) { 324 if (lastBuildName == null) { 325 read(null, -1); 326 return true; 327 } 328 PerformanceResults performanceResults = getPerformance(); 329 String lastBuildDate = getBuildDate(lastBuildName, getBaselinePrefix()); 330 if (force || performanceResults.getBuildDate().compareTo(lastBuildDate) > 0) { 331 long lastBuildTime = 0; 332 try { 333 lastBuildTime = DATE_FORMAT.parse(lastBuildDate).getTime(); 334 } catch (ParseException e) { 335 // should not happen 336 } 337 read(lastBuildName, lastBuildTime); 338 return true; 339 } 340 return false; 341 } 342 */ 343 344 /* 345 * Set value from database information. 346 */ 347 void setInfos(int config_id, int build_id, int summaryKind, String comment) { 348 ConfigResults configResults = (ConfigResults) getResults(config_id); 349 if (configResults == null) { 350 configResults = new ConfigResults(this, config_id); 351 addChild(configResults, true); 352 } 353 configResults.setInfos(build_id, summaryKind, comment); 354 } 355 356 /* 357 * Set value from database information. 358 */ 359 void setValue(int build_id, int dim_id, int config_id, int step, long value) { 360 ConfigResults configResults = (ConfigResults) getResults(config_id); 361 if (configResults == null) { 362 configResults = new ConfigResults(this, config_id); 363 addChild(configResults, true); 364 } 365 configResults.setValue(build_id, dim_id, step, value); 366 } 367 368 /* 369 * Read scenario results information from database. 370 */ 371 boolean updateBuild(String buildName, boolean force) { 372 373 if (!force && knowsBuild(buildName)) { 374 return false; 375 } 376 377 // Get values 378 print(" + scenario '"+getShortName()+"': values..."); //$NON-NLS-1$ //$NON-NLS-2$ 379 long start = System.currentTimeMillis(); 380 String configPattern = getPerformance().getConfigurationsPattern(); 381 DB_Results.queryScenarioValues(this, configPattern, buildName); 382 print(Util.timeString(System.currentTimeMillis()-start)); 383 384 // Set baseline and current builds 385 print(", infos..."); //$NON-NLS-1$ 386 start = System.currentTimeMillis(); 387 int size = size(); 388 String[] builds = buildName == null ? null : new String[] { buildName }; 389 for (int i=0; i<size; i++) { 390 ConfigResults configResults = (ConfigResults) this.children.get(i); 391 configResults.completeResults(builds); 392 } 393 println(Util.timeString(System.currentTimeMillis()-start)); 394 return true; 395 } 396 397 void write(DataOutputStream stream) throws IOException { 398 int size = size(); 399 stream.writeInt(this.id); 400 stream.writeInt(size); 401 for (int i=0; i<size; i++) { 402 ConfigResults configResults = (ConfigResults) this.children.get(i); 403 configResults.write(stream); 404 } 405 } 406 407 } 408