PerformanceResults.java revision 402794e73aed8611d62eb4b01cd155e2d76fcb87
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.db; 12 13import java.io.BufferedInputStream; 14import java.io.BufferedOutputStream; 15import java.io.DataInputStream; 16import java.io.DataOutputStream; 17import java.io.File; 18import java.io.FileInputStream; 19import java.io.FileNotFoundException; 20import java.io.FileOutputStream; 21import java.io.IOException; 22import java.io.PrintStream; 23import java.util.*; 24 25import org.eclipse.core.runtime.IProgressMonitor; 26import org.eclipse.core.runtime.OperationCanceledException; 27import org.eclipse.core.runtime.SubMonitor; 28import org.eclipse.test.internal.performance.results.utils.Util; 29 30 31/** 32 * Root class to handle performance results. 33 * 34 * Usually performance results are built for a current build vs. a baseline build. 35 * 36 * This class allow to read all data from releng performance database for given 37 * configurations and scenario pattern. 38 * 39 * Then it provides easy and speedy access to all stored results. 40 */ 41public class PerformanceResults extends AbstractResults { 42 43 String[] allBuildNames = null; 44 Map allScenarios; 45 String lastBuildName; // Name of the last used build 46 String baselineName; // Name of the baseline build used for comparison 47 String baselinePrefix; 48 private String scenarioPattern = "%"; //$NON-NLS-1$ 49 private String[] components; 50 String[] configNames, sortedConfigNames; 51 String[] configDescriptions, sortedConfigDescriptions; 52 private String configPattern; 53 54 boolean dbRequired; 55 boolean needToUpdateLocalFile; 56 57 /* 58 * Local class helping to guess remaining time while reading results from DB 59 */ 60 class RemainingTimeGuess { 61 int all, count; 62 long start; 63 double remaining; 64 RemainingTimeGuess(int all, long start) { 65 this.all = all; 66 this.start = start; 67 } 68 String display() { 69 StringBuffer buffer = new StringBuffer(" [elapsed: "); //$NON-NLS-1$ 70 long elapsed = getElapsed(); 71 buffer.append(Util.timeChrono(elapsed)); 72 if (this.count > 0) { 73 buffer.append(" | left: "); //$NON-NLS-1$ 74 long remainingTime = getRemainingTime(elapsed); 75 buffer.append(Util.timeChrono(remainingTime)); 76 buffer.append(" | end: "); //$NON-NLS-1$ 77 buffer.append(Util.timeEnd(remainingTime)); 78 } 79 buffer.append(']'); 80 return buffer.toString(); 81 } 82 private long getRemainingTime(long elapsed) { 83 return (long) ((((double)elapsed) / this.count) * (this.all - this.count)); 84 } 85 private long getElapsed() { 86 return System.currentTimeMillis() - this.start; 87 } 88 } 89 90 91 // Failure threshold 92 public static final int DEFAULT_FAILURE_THRESHOLD = 10; 93 int failure_threshold = DEFAULT_FAILURE_THRESHOLD; 94 95public PerformanceResults(PrintStream stream) { 96 super(null, null); 97 this.printStream = stream; 98 this.dbRequired = false; 99 setDefaults(); 100} 101 102public PerformanceResults(String name, String baseline, String baselinePrefix, PrintStream stream) { 103 super(null, name); 104 this.baselineName = baseline; 105 this.baselinePrefix = baselinePrefix; 106 this.printStream = stream; 107 this.dbRequired = true; 108 setDefaults(); 109} 110 111/** 112 * Returns the list of all builds currently read. 113 * 114 * @return The names list of all currently known builds 115 */ 116public String[] getAllBuildNames() { 117 if (this.allBuildNames == null) { 118 setAllBuildNames(); 119 } 120 return this.allBuildNames; 121} 122 123/** 124 * Returns the name of the baseline used for extracted results 125 * 126 * @return The build name of the baseline of <code>null</code> 127 * if no specific baseline is used for the extracted results. 128 */ 129public String getBaselineName() { 130 return this.baselineName; 131} 132 133/* 134 * Get the baseline prefix (computed from #baselineName). 135 */ 136String getBaselinePrefix() { 137 return this.baselinePrefix; 138} 139 140/* 141 * Get the build date (see #getBuildDate(String, String)). 142 */ 143public String getBuildDate() { 144 String buildName = getName(); 145 if (buildName == null) return ""; //$NON-NLS-1$ 146 return Util.getBuildDate(getName(), getBaselinePrefix()); 147} 148 149/** 150 * Return the list of components concerned by performance results. 151 * 152 * @return The list of the components 153 */ 154public String[] getComponents() { 155 return this.components; 156} 157 158/** 159 * Get the scenarios of a given component. 160 * 161 * @param componentName The component name. Should not be <code>null</code> 162 * @return A list of {@link ScenarioResults scenario results} 163 */ 164public List getComponentScenarios(String componentName) { 165 ComponentResults componentResults = (ComponentResults) getResults(componentName); 166 if (componentResults == null) return null; 167 return Collections.unmodifiableList(componentResults.children); 168} 169 170/** 171 * Get the scenarios which have a summary for a given component. 172 * 173 * @param componentName The component name 174 * @param config Configuration name 175 * @return A list of {@link ScenarioResults scenario results} which have a summary 176 */ 177public List getComponentSummaryScenarios(String componentName, String config) { 178 if (componentName == null) { 179 int size = size(); 180 List scenarios = new ArrayList(); 181 for (int i=0; i< size; i++) { 182 ComponentResults componentResults = (ComponentResults) this.children.get(i); 183 scenarios.addAll(componentResults.getSummaryScenarios(true, config)); 184 } 185 return scenarios; 186 } 187 ComponentResults componentResults = (ComponentResults) getResults(componentName); 188 return componentResults.getSummaryScenarios(false, config); 189} 190 191/** 192 * Return the configuration boxes considered for this performance results 193 * sorted or not depending on the given flag. 194 * 195 * @param sort Indicates whether the list must be sorted or not. 196 * The order is defined by the configuration names, not by the box names 197 * @return The list of configuration boxes sorted by configuration names 198 */ 199public String[] getConfigBoxes(boolean sort) { 200 return sort ? this.sortedConfigDescriptions : this.configDescriptions; 201} 202 203/** 204 * Return the configuration names considered for this performance results 205 * sorted or not depending on the given flag. 206 * 207 * @param sort Indicates whether the list must be sorted or not 208 * @return The list of configuration names 209 */ 210public String[] getConfigNames(boolean sort) { 211 return sort ?this.sortedConfigNames : this.configNames; 212} 213 214/* 215 * Compute a SQL pattern from all stored configuration names. 216 * For example 'eclipseperflnx1', 'eclipseperflnx2' and 'eclipseperflnx3' 217 * will return 'eclipseperflnx_'. 218 */ 219String getConfigurationsPattern() { 220 if (this.configPattern == null) { 221 int length = this.sortedConfigNames == null ? 0 : this.sortedConfigNames.length; 222 if (length == 0) return null; 223 this.configPattern = this.sortedConfigNames[0]; 224 int refLength = this.configPattern.length(); 225 for (int i=1; i<length; i++) { 226 String config = this.sortedConfigNames[i]; 227 StringBuffer newConfig = null; 228 if (refLength != config.length()) return null; // strings have not the same length => cannot find a pattern 229 for (int j=0; j<refLength; j++) { 230 char c = this.configPattern.charAt(j); 231 if (config.charAt(j) != c) { 232 if (newConfig == null) { 233 newConfig = new StringBuffer(refLength); 234 if (j == 0) return null; // first char is already different => cannot find a pattern 235 newConfig.append(this.configPattern.substring(0, j)); 236 } 237 newConfig.append('_'); 238 } else if (newConfig != null) { 239 newConfig.append(c); 240 } 241 } 242 if (newConfig != null) { 243 this.configPattern = newConfig.toString(); 244 } 245 } 246 } 247 return this.configPattern; 248} 249 250/** 251 * Return the name of the last build name except baselines. 252 * 253 * @return the name of the last build 254 */ 255public String getLastBuildName() { 256 return getLastBuildName(1/*all except baselines*/); 257} 258/** 259 * Return the name of the last build name 260 * 261 * @param kind Decide what kind of build is taken into account 262 * 0: all kind of build 263 * 1: all except baseline builds 264 * 2: all except baseline and nightly builds 265 * 3: only integration builds 266 * @return the name of the last build of the selected kind 267 */ 268public String getLastBuildName(int kind) { 269 if (this.name == null) { 270 getAllBuildNames(); // init build names if necessary 271 int idx = this.allBuildNames.length-1; 272 this.name = this.allBuildNames[idx]; 273 if (kind > 0) { 274 loop: while (idx-- >= 0) { 275 switch (this.name.charAt(0)) { 276 case 'N': 277 if (kind < 2) break loop; 278 break; 279 case 'M': 280 if (kind < 3) break loop; 281 break; 282 case 'I': 283 if (kind < 4) break loop; 284 break; 285 } 286 this.name = this.allBuildNames[idx]; 287 } 288 } 289 } 290 return this.name; 291} 292 293public String getName() { 294 if (this.name == null) { 295 setAllBuildNames(); 296 } 297 return this.name; 298} 299 300/* 301 * (non-Javadoc) 302 * @see org.eclipse.test.internal.performance.results.AbstractResults#getPerformance() 303 */ 304PerformanceResults getPerformance() { 305 return this; 306} 307 308/** 309 * Get the results of a given scenario. 310 * 311 * @param scenarioName The scenario name 312 * @return The {@link ScenarioResults scenario results} 313 */ 314public ScenarioResults getScenarioResults(String scenarioName) { 315 ComponentResults componentResults = (ComponentResults) getResults(DB_Results.getComponentNameFromScenario(scenarioName)); 316 return componentResults == null ? null : (ScenarioResults) componentResults.getResults(scenarioName); 317} 318 319/* 320 * Init configurations from performance results database. 321 */ 322private void initConfigs() { 323 // create config names 324 this.configNames = DB_Results.getConfigs(); 325 this.configDescriptions = DB_Results.getConfigDescriptions(); 326 int length = this.configNames.length; 327 this.sortedConfigNames = new String[length]; 328 for (int i = 0; i < length; i++) { 329 this.sortedConfigNames[i] = this.configNames[i]; 330 } 331 332 // Sort the config names 333 Arrays.sort(this.sortedConfigNames); 334 this.sortedConfigDescriptions = new String[length]; 335 for (int i=0; i<length; i++) { 336 for (int j=0; j<length; j++) { 337 if (this.sortedConfigNames[i] == this.configNames[j]) { // == is intentional! 338 this.sortedConfigDescriptions[i] = this.configDescriptions[j]; 339 break; 340 } 341 } 342 } 343} 344 345/* 346 * Read or update data for a build from a directory supposed to have local files. 347 */ 348private String[] read(boolean local, String buildName, String[][] configs, boolean force, File dataDir, String taskName, SubMonitor subMonitor) { 349 if (local && dataDir == null) { 350 throw new IllegalArgumentException("Must specify a directory to read local files!"); //$NON-NLS-1$ 351 } 352 subMonitor.setWorkRemaining(100); 353 354 // Update info 355 long start = System.currentTimeMillis(); 356 int allScenariosSize; 357 if (DB_Results.DB_CONNECTION) { 358 try { 359 // Read all scenarios 360 allScenariosSize = readScenarios(buildName, subMonitor.newChild(10)) ; 361 if (allScenariosSize < 0) { 362 return null; 363 } 364 365 // Read all builds 366 DB_Results.queryAllVariations(getConfigurationsPattern()); 367 368 // Refresh configs 369 if (configs == null) { 370 initConfigs(); 371 } else { 372 setConfigInfo(configs); 373 } 374 } catch (OperationCanceledException e) { 375 return null; 376 } 377 } else { 378 if (this.allScenarios == null) return null; 379 allScenariosSize = this.allScenarios.size(); 380 if (configs != null) { 381 setConfigInfo(configs); 382 } 383 } 384 385 // Create corresponding children 386 int componentsLength = this.components.length; 387 subMonitor.setWorkRemaining(componentsLength); 388 RemainingTimeGuess timeGuess = null; 389 for (int i=0; i<componentsLength; i++) { 390 String componentName = this.components[i]; 391 List scenarios = this.allScenarios == null ? null : (List) this.allScenarios.get(componentName); 392 393 // Manage monitor 394 int percentage = (int) ((((double)(i+1)) / (componentsLength+1)) * 100); 395 StringBuffer tnBuffer= taskName==null ? new StringBuffer() : new StringBuffer(taskName); 396 tnBuffer.append(" ("); //$NON-NLS-1$ 397 if (buildName != null) { 398 tnBuffer.append(buildName).append(": "); //$NON-NLS-1$ 399 } 400 tnBuffer.append(percentage).append("%)"); //$NON-NLS-1$ 401 subMonitor.setTaskName(tnBuffer.toString()); 402 StringBuffer subTaskBuffer = new StringBuffer("Component "); //$NON-NLS-1$ 403 subTaskBuffer.append(componentName); 404 subTaskBuffer.append("..."); //$NON-NLS-1$ 405 subMonitor.subTask(subTaskBuffer.toString()); 406 407 // Get component results 408 if (scenarios == null && !local) continue; 409 ComponentResults componentResults; 410 if (local || (buildName == null && force)) { 411 componentResults = new ComponentResults(this, componentName); 412 addChild(componentResults, true); 413 } else { 414 componentResults = (ComponentResults) getResults(componentName); 415 if (componentResults == null) { 416 componentResults = new ComponentResults(this, componentName); 417 addChild(componentResults, true); 418 } 419 } 420 421 // Read the component results 422 if (local) { 423 try { 424 componentResults.readLocalFile(dataDir, scenarios); 425 } 426 catch (FileNotFoundException ex) { 427 return null; 428 } 429 subMonitor.worked(1); 430 } else { 431 if (timeGuess == null) { 432 timeGuess = new RemainingTimeGuess(1+componentsLength+allScenariosSize, start); 433 } 434 componentResults.updateBuild(buildName, scenarios, force, dataDir, subMonitor.newChild(1), timeGuess); 435 } 436 if (subMonitor.isCanceled()) return null; 437 } 438 439 // Update names 440 setAllBuildNames(); 441 writeData(dataDir); 442 443 // Print time 444 printGlobalTime(start); 445 446 return this.allBuildNames; 447} 448 449/** 450 * Read all data from performance database for the given configurations 451 * and scenario pattern. 452 * 453 * This method is typically called when generated performance results 454 * from a non-UI application. 455 * 456 * @param buildName The name of the build 457 * @param configs All configurations to extract results. If <code>null</code>, 458 * then all known configurations ({@link DB_Results#getConfigs()}) are read. 459 * @param pattern The pattern of the concerned scenarios 460 * @param dataDir The directory where data will be read/stored locally. 461 * If <code>null</code>, then database will be read instead and no storage 462 * will be performed 463 * @param threshold The failure percentage threshold over which a build result 464 * value compared to the baseline is considered as failing. 465 * @param monitor The progress monitor 466 * 467 * @return All known build names 468 */ 469public String[] readAll(String buildName, String[][] configs, String pattern, File dataDir, int threshold, IProgressMonitor monitor) { 470 471 // Init 472 this.scenarioPattern = pattern == null ? "%" : pattern; //$NON-NLS-1$ 473 this.failure_threshold = threshold; 474 SubMonitor subMonitor = SubMonitor.convert(monitor, 1000); 475 476 // Set default names 477 setDefaults(); 478 479 // Read local data files first 480 reset(dataDir); 481 String[] names = read(true, null, configs, true, dataDir, null, subMonitor.newChild(100)); 482 if (names==null) { 483 // if one local files is missing then force a full DB read! 484 // TODO moderate this to force the DB read only for the missing file... 485 return read(false, null, configs, true, dataDir, null, subMonitor.newChild(900)); 486 } 487 488 // Search build name in read data 489 boolean buildMissing = true; 490 if (buildName != null) { 491 this.name = buildName; 492 buildMissing = Arrays.binarySearch(names, buildName, Util.BUILD_DATE_COMPARATOR) < 0; 493 } 494 495 // Look for missing builds 496 if (buildMissing) { 497 String[] builds = DB_Results.getBuilds(); 498 Arrays.sort(builds, Util.BUILD_DATE_COMPARATOR); 499 for (int i=builds.length-1; i>=0; i--) { 500 if (Arrays.binarySearch(names, builds[i], Util.BUILD_DATE_COMPARATOR) >= 0) { 501 break; 502 } 503 read(false, builds[i], configs, true, dataDir, null, subMonitor.newChild(900)); 504 } 505 } 506 return this.allBuildNames; 507} 508 509/** 510 * Read all data from performance database for the given configurations 511 * and scenario pattern. 512 * 513 * Note that calling this method flush all previous read data. 514 * 515 * @param dataDir The directory where local files are located 516 * @param monitor The progress monitor 517 */ 518public void readLocal(File dataDir, IProgressMonitor monitor) { 519 520 // Print title 521 String taskName = "Read local performance results"; //$NON-NLS-1$ 522 println(taskName); 523 524 // Create monitor 525 SubMonitor subMonitor = SubMonitor.convert(monitor, 1000); 526 subMonitor.setTaskName(taskName); 527 528 // Read 529 reset(dataDir); 530 read(true, null, null, true, dataDir, taskName, subMonitor); 531} 532 533void readLocalFile(File dir) { 534 if (!dir.exists()) return; 535 File dataFile = new File(dir, "performances.dat"); //$NON-NLS-1$ 536 if (!dataFile.exists()) return; 537 DataInputStream stream = null; 538 try { 539 // Read local file info 540 stream = new DataInputStream(new BufferedInputStream(new FileInputStream(dataFile))); 541 542 // Read build info 543 String str = stream.readUTF(); 544 this.needToUpdateLocalFile = this.name == null || Util.getBuildDate(this.name).compareTo(Util.getBuildDate(str)) > 0; 545 if (this.name != null && Util.getBuildDate(this.name).compareTo(Util.getBuildDate(str)) >= 0) { 546 return; 547 } 548 println(" - read performance results local files info: "); //$NON-NLS-1$ 549 println(" + name : "+str); 550 this.name = str == "" ? null : str; 551 str = stream.readUTF(); 552 println(" + baseline : "+str); 553 if (this.baselineName == null) { 554 this.baselineName = str == "" ? null : str; 555 } 556 str = stream.readUTF(); 557 println(" + baseline prefix: "+str); 558 this.baselinePrefix = str == "" ? null : str; 559 560 // Write configs info 561 int length = stream.readInt(); 562 println(" + "+length+" configs"); 563 this.configNames = new String[length]; 564 this.sortedConfigNames = new String[length]; 565 this.configDescriptions = new String[length]; 566 this.sortedConfigDescriptions = new String[length]; 567 for (int i = 0; i < length; i++) { 568 this.configNames[i] = stream.readUTF(); 569 this.sortedConfigNames[i] = this.configNames[i]; 570 this.configDescriptions[i] = stream.readUTF(); 571 this.sortedConfigDescriptions[i] = this.configDescriptions[i]; 572 } 573 DB_Results.setConfigs(this.configNames); 574 DB_Results.setConfigDescriptions(this.configDescriptions); 575 576 // Write builds info 577 length = stream.readInt(); 578 println(" + "+length+" builds"); 579 this.allBuildNames = new String[length]; 580 for (int i = 0; i < length; i++) { 581 this.allBuildNames[i] = stream.readUTF(); 582 } 583 584 // Write scenarios info 585 length = stream.readInt(); 586 println(" + "+length+" components"); 587 this.components = new String[length]; 588 this.allScenarios = new HashMap(); 589 for (int i = 0; i < length; i++) { 590 this.components[i] = stream.readUTF(); 591 int size = stream.readInt(); 592 List scenarios = new ArrayList(size); 593 for (int j=0; j<size; j++) { 594 scenarios.add(new ScenarioResults(stream.readInt(), stream.readUTF(), stream.readUTF())); 595 } 596 this.allScenarios.put(this.components[i], scenarios); 597 } 598 println(" => read from file "+dataFile); //$NON-NLS-1$ 599 } catch (IOException ioe) { 600 println(" !!! "+dataFile+" should be deleted as it contained invalid data !!!"); //$NON-NLS-1$ //$NON-NLS-2$ 601 } finally { 602 try { 603 stream.close(); 604 } catch (IOException e) { 605 // nothing else to do! 606 } 607 } 608} 609 610private int readScenarios(String buildName, SubMonitor subMonitor) throws OperationCanceledException { 611 subMonitor.setWorkRemaining(10); 612 long start = System.currentTimeMillis(); 613 String titleSuffix; 614 if (buildName == null) { 615 titleSuffix = "all database scenarios..."; //$NON-NLS-1$ 616 } else { 617 titleSuffix = "all database scenarios for "+buildName+" build..."; //$NON-NLS-1$ //$NON-NLS-2$ 618 } 619 print(" + get "+titleSuffix); //$NON-NLS-1$ 620 subMonitor.subTask("Get "+titleSuffix); //$NON-NLS-1$ 621 this.allScenarios = DB_Results.queryAllScenarios(this.scenarioPattern, buildName); 622 if (this.allScenarios == null) return -1; 623 int allScenariosSize = 0; 624 List componentsSet = new ArrayList(this.allScenarios.keySet()); 625 Collections.sort(componentsSet); 626 int componentsSize = componentsSet.size(); 627 componentsSet.toArray(this.components = new String[componentsSize]); 628 for (int i=0; i<componentsSize; i++) { 629 String componentName = this.components[i]; 630 List scenarios = (List) this.allScenarios.get(componentName); 631 allScenariosSize += scenarios.size(); 632 } 633 println(" -> "+allScenariosSize+" found in "+(System.currentTimeMillis()-start)+"ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 634 subMonitor.worked(10); 635 if (subMonitor.isCanceled()) throw new OperationCanceledException(); 636 return allScenariosSize; 637} 638 639void reset(File dataDir) { 640 this.allBuildNames = null; 641 this.children = new ArrayList(); 642// this.name = null; 643 this.components = null; 644 this.allScenarios = null; 645 readLocalFile(dataDir); 646} 647 648private void setAllBuildNames() { 649 SortedSet builds = new TreeSet(Util.BUILD_DATE_COMPARATOR); 650 int size = size(); 651 if (size == 0) return; 652 for (int i=0; i<size; i++) { 653 ComponentResults componentResults = (ComponentResults) this.children.get(i); 654 Set names = componentResults.getAllBuildNames(); 655 builds.addAll(names); 656 } 657 int buildsSize = builds.size(); 658 this.allBuildNames = new String[buildsSize]; 659 if (buildsSize > 0) { 660 int n = 0; 661 Iterator buildNames = builds.iterator(); 662 while (buildNames.hasNext()) { 663 String buildName = (String) buildNames.next(); 664 if (this.lastBuildName == null || Util.getBuildDate(buildName).compareTo(Util.getBuildDate(this.lastBuildName)) <= 0) { 665 this.allBuildNames[n++] = buildName; 666 } 667 } 668 if (n < buildsSize) { 669 System.arraycopy(this.allBuildNames, 0, this.allBuildNames = new String[n], 0, n); 670 } 671 int idx = n-1; 672 String lastBuild = this.allBuildNames[idx--]; 673 while (lastBuild.startsWith(DB_Results.getDbBaselinePrefix())) { 674 lastBuild = this.allBuildNames[idx--]; 675 } 676 this.needToUpdateLocalFile = this.name == null || Util.getBuildDate(lastBuild).compareTo(Util.getBuildDate(this.name)) > 0; 677 this.name = lastBuild; 678 if (this.baselineName != null) { 679 String lastBuildDate = Util.getBuildDate(lastBuild); 680 if (Util.getBuildDate(this.baselineName).compareTo(lastBuildDate) > 0) { 681 this.baselineName = DB_Results.getLastBaselineBuild(lastBuildDate); 682 } 683 } 684 } 685} 686 687private void setConfigInfo(String[][] configs) { 688 if (configs == null) return; 689 690 // Store config information 691 int length = configs.length; 692 this.configNames = new String[length]; 693 this.sortedConfigNames = new String[length]; 694 this.configDescriptions = new String[length]; 695 for (int i=0; i<length; i++) { 696 this.configNames[i] = this.sortedConfigNames[i] = configs[i][0]; 697 this.configDescriptions[i] = configs[i][1]; 698 } 699 700 // Sort the config names 701 Arrays.sort(this.sortedConfigNames); 702 length = this.sortedConfigNames.length; 703 this.sortedConfigDescriptions = new String[length]; 704 for (int i=0; i<length; i++) { 705 for (int j=0; j<length; j++) { 706 if (this.sortedConfigNames[i] == this.configNames[j]) { // == is intentional! 707 this.sortedConfigDescriptions[i] = this.configDescriptions[j]; 708 break; 709 } 710 } 711 } 712} 713 714 715/** 716 * Set the name of the baseline used for extracted results 717 * 718 * @param buildName The name of the baseline build 719 */ 720public void setBaselineName(String buildName) { 721 this.baselineName = buildName; 722} 723 724private void setDefaults() { 725 726 // Set builds if none 727 if (size() == 0 && DB_Results.DB_CONNECTION) { 728 this.allBuildNames = DB_Results.getBuilds(); 729 this.components = DB_Results.getComponents(); 730 initConfigs(); 731 } 732 733 // Set name if null 734 if (this.name == null) { 735 setAllBuildNames(); 736 if (this.name == null) { // does not know any build 737 this.name = DB_Results.getLastCurrentBuild(); 738 if (this.dbRequired) { 739 if (this.name == null) { 740 throw new RuntimeException("Cannot find any current build!"); //$NON-NLS-1$ 741 } 742 this.allBuildNames = DB_Results.getBuilds(); 743 this.components = DB_Results.getComponents(); 744 initConfigs(); 745 } 746 if (this.printStream != null) { 747 this.printStream.println(" + no build specified => use last one: "+this.name); //$NON-NLS-1$ 748 } 749 } 750 } 751 752 // Init baseline name if not set 753 if (this.baselineName == null && getName() != null) { 754 String buildDate = Util.getBuildDate(getName()); 755 this.baselineName = DB_Results.getLastBaselineBuild(buildDate); 756 if (this.baselineName == null && this.dbRequired) { 757 throw new RuntimeException("Cannot find any baseline to refer!"); //$NON-NLS-1$ 758 } 759 if (this.printStream != null) { 760 this.printStream.println(" + no baseline specified => use last one: "+this.baselineName); //$NON-NLS-1$ 761 } 762 } 763 764 // Init baseline prefix if not set 765 if (this.baselinePrefix == null && this.baselineName != null) { 766 // Assume that baseline name format is *always* x.y_yyyyMMddhhmm_yyyyMMddhhmm 767 int index = this.baselineName.lastIndexOf('_'); 768 if (index > 0) { 769 this.baselinePrefix = this.baselineName.substring(0, index); 770 } else { 771 this.baselinePrefix = DB_Results.getDbBaselinePrefix(); 772 } 773 } 774 775 // Set scenario pattern default 776 if (this.scenarioPattern == null) { 777 this.scenarioPattern = "%"; //$NON-NLS-1$ 778 } 779 780 // Flush print stream 781 if (this.printStream != null) { 782 this.printStream.println(); 783 this.printStream.flush(); 784 } 785} 786 787public void setLastBuildName(String lastBuildName) { 788 this.lastBuildName = lastBuildName; 789// if (lastBuildName == null) { 790// int idx = this.allBuildNames.length-1; 791// String lastBuild = this.allBuildNames[idx--]; 792// while (this.name.startsWith(DB_Results.getDbBaselinePrefix())) { 793// lastBuild = this.allBuildNames[idx--]; 794// } 795// this.name = lastBuild; 796// } else { 797// this.name = lastBuildName; 798// } 799} 800 801/** 802 * Update a given build information with database contents. 803 * 804 * @param builds The builds to read new data 805 * @param force Force the update from the database, even if the build is 806 * already known. 807 * @param dataDir The directory where data should be stored locally if necessary. 808 * If <code>null</code>, then information changes won't be persisted. 809 * @param monitor The progress monitor 810 * @return All known builds 811 */ 812public String[] updateBuilds(String[] builds, boolean force, File dataDir, IProgressMonitor monitor) { 813 814 // Print title 815 StringBuffer buffer = new StringBuffer("Update data for "); //$NON-NLS-1$ 816 int length = builds == null ? 0 : builds.length; 817 switch (length) { 818 case 0: 819 buffer.append("all builds"); //$NON-NLS-1$ 820 reset(dataDir); 821 break; 822 case 1: 823 buffer.append("one build"); //$NON-NLS-1$ 824 break; 825 default: 826 buffer.append("several builds"); //$NON-NLS-1$ 827 break; 828 } 829 String taskName = buffer.toString(); 830 println(buffer); 831 832 // Create sub-monitor 833 SubMonitor subMonitor = SubMonitor.convert(monitor, 1000*length); 834 subMonitor.setTaskName(taskName); 835 836 // Read 837 for (int i=0; i<length; i++) { 838 read(false, builds[i], null, force, dataDir, taskName, subMonitor.newChild(1000)); 839 } 840 841 // Return new builds list 842 return this.allBuildNames; 843} 844 845/** 846 * Update a given build information with database contents. 847 * 848 * @param buildName The build name to read new data 849 * @param force Force the update from the database, even if the build is 850 * already known. 851 * @param dataDir The directory where data should be stored locally if necessary. 852 * If <code>null</code>, then information changes won't be persisted. 853 * @param monitor The progress monitor 854 * @return All known builds 855 */ 856public String[] updateBuild(String buildName, boolean force, File dataDir, IProgressMonitor monitor) { 857 858 // Print title 859 StringBuffer buffer = new StringBuffer("Update data for "); //$NON-NLS-1$ 860 if (buildName == null) { 861 buffer.append("all builds"); //$NON-NLS-1$ 862 reset(dataDir); 863 } else { 864 buffer.append("one build"); //$NON-NLS-1$ 865 } 866 String taskName = buffer.toString(); 867 println(buffer); 868 869 // Create sub-monitor 870 SubMonitor subMonitor = SubMonitor.convert(monitor, 1000); 871 subMonitor.setTaskName(taskName); 872 873 // Read 874 read(false, buildName, null, force, dataDir, taskName, subMonitor); 875 876 // Refresh name 877 if (buildName != null && !buildName.startsWith(DB_Results.getDbBaselinePrefix())) { 878 this.name = buildName; 879 } 880 881 // Return new list all build names 882 return this.allBuildNames; 883} 884 885/* 886 * Write general information. 887 */ 888void writeData(File dir) { 889 if (!DB_Results.DB_CONNECTION) { 890 // Only write new local file if there's a database connection 891 // otherwise contents may not be complete... 892 return; 893 } 894 if (dir ==null || (!dir.exists() && !dir.mkdirs())) { 895 System.err.println("can't create directory " + dir); //$NON-NLS-1$ 896 return; 897 } 898 File dataFile = new File(dir, "performances.dat"); //$NON-NLS-1$ 899 if (dataFile.exists()) { 900 if (!this.needToUpdateLocalFile) { 901 return; 902 } 903 dataFile.delete(); 904 } 905 try { 906 DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile))); 907 908 // Write build info 909 stream.writeUTF(this.name == null ? DB_Results.getLastCurrentBuild() : this.name); 910 stream.writeUTF(this.baselineName == null ? DB_Results.getLastBaselineBuild(null) : this.baselineName); 911 stream.writeUTF(this.baselinePrefix == null ? "" : this.baselinePrefix); 912 913 // Write configs info 914 int length = this.sortedConfigNames.length; 915 stream.writeInt(length); 916 for (int i = 0; i < length; i++) { 917 stream.writeUTF(this.sortedConfigNames[i]); 918 stream.writeUTF(this.sortedConfigDescriptions[i]); 919 } 920 921 // Write builds info 922 String[] builds = this.allBuildNames == null ? DB_Results.getBuilds() : this.allBuildNames; 923 length = builds.length; 924 stream.writeInt(length); 925 for (int i = 0; i < length; i++) { 926 stream.writeUTF(builds[i]); 927 } 928 929 // Write scenarios info 930 length = this.components.length; 931 stream.writeInt(length); 932 for (int i = 0; i < length; i++) { 933 stream.writeUTF(this.components[i]); 934 List scenarios = (List) this.allScenarios.get(this.components[i]); 935 int size = scenarios.size(); 936 stream.writeInt(size); 937 for (int j=0; j<size; j++) { 938 final ScenarioResults scenarioResults = (ScenarioResults)scenarios.get(j); 939 stream.writeInt(scenarioResults.getId()); 940 stream.writeUTF(scenarioResults.getName()); 941 stream.writeUTF(scenarioResults.getLabel()); 942 } 943 } 944 945 // Close 946 stream.close(); 947 println(" => performance results general data written in file " + dataFile); //$NON-NLS-1$ 948 } catch (FileNotFoundException e) { 949 System.err.println("can't create output file" + dataFile); //$NON-NLS-1$ 950 } catch (IOException e) { 951 e.printStackTrace(); 952 } 953} 954 955} 956