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.ui; 12 13 import java.io.BufferedOutputStream; 14 import java.io.DataOutputStream; 15 import java.io.File; 16 import java.io.FileNotFoundException; 17 import java.io.FileOutputStream; 18 import java.io.IOException; 19 import java.util.HashSet; 20 import java.util.Iterator; 21 import java.util.Set; 22 23 import org.eclipse.core.runtime.preferences.InstanceScope; 24 import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; 25 import org.eclipse.jface.action.Action; 26 import org.eclipse.jface.action.IAction; 27 import org.eclipse.jface.action.IMenuManager; 28 import org.eclipse.jface.action.Separator; 29 import org.eclipse.jface.dialogs.MessageDialog; 30 import org.eclipse.jface.resource.JFaceResources; 31 import org.eclipse.jface.viewers.AbstractTreeViewer; 32 import org.eclipse.jface.viewers.ISelectionChangedListener; 33 import org.eclipse.jface.viewers.SelectionChangedEvent; 34 import org.eclipse.jface.viewers.StructuredSelection; 35 import org.eclipse.jface.viewers.TreeViewer; 36 import org.eclipse.jface.viewers.Viewer; 37 import org.eclipse.jface.viewers.ViewerFilter; 38 import org.eclipse.jface.viewers.ViewerSorter; 39 import org.eclipse.swt.SWT; 40 import org.eclipse.swt.graphics.Font; 41 import org.eclipse.swt.graphics.FontData; 42 import org.eclipse.swt.widgets.Composite; 43 import org.eclipse.swt.widgets.Display; 44 import org.eclipse.test.internal.performance.results.model.BuildResultsElement; 45 import org.eclipse.test.internal.performance.results.model.ComponentResultsElement; 46 import org.eclipse.test.internal.performance.results.model.ConfigResultsElement; 47 import org.eclipse.test.internal.performance.results.model.ResultsElement; 48 import org.eclipse.test.internal.performance.results.model.ScenarioResultsElement; 49 import org.eclipse.test.internal.performance.results.utils.IPerformancesConstants; 50 import org.eclipse.test.internal.performance.results.utils.Util; 51 import org.eclipse.ui.IMemento; 52 import org.eclipse.ui.PlatformUI; 53 import org.eclipse.ui.model.WorkbenchContentProvider; 54 import org.eclipse.ui.model.WorkbenchLabelProvider; 55 56 /** 57 * View to see the performance results of all the components in a hierarchical tree. 58 * <p> 59 * A component defines several performance scenarios which are run on several 60 * machines (aka config). All builds results are stored onto each configuration 61 * and 2 dimensions have been stored for each result: the "Elapsed Process Time" 62 * and the "CPU Time". 63 * </p><p> 64 * There's only one available action from this view: read the local data files. This 65 * populates the hierarchy with the numbers stored in these files. 66 * </p><p> 67 * There's also the possibility to filter the results: 68 * <ul> 69 * <li>Filter for builds: 70 * <ul> 71 * <li>Filter baselines: hide the baselines (starting with R-3.x)</li> 72 * <li>Filter nightly: hide the nightly builds (starting with 'N')</li> 73 * <li>Filter non-important builds: hide all non-important builds, which means non-milestone builds and those after the last milestone</li> 74 * </ul> 75 * </li> 76 * </li>Filter for scenarios: 77 * <ul> 78 * <li>Filter non-fingerprints: hide the scenarios which are not in the fingerprints</li> 79 * </ul> 80 * </li> 81 * </ul> 82 * </p> 83 * @see ComponentResultsView 84 */ 85 public class ComponentsView extends PerformancesView { 86 87 // Viewer filters 88 final static ViewerFilter FILTER_ADVANCED_SCENARIOS = new ViewerFilter() { 89 public boolean select(Viewer v, Object parentElement, Object element) { 90 if (element instanceof ScenarioResultsElement) { 91 ScenarioResultsElement scenarioElement = (ScenarioResultsElement) element; 92 return scenarioElement.hasSummary(); 93 } 94 return true; 95 } 96 }; 97 98 // Views 99 PerformancesView buildsView; 100 ComponentResultsView componentResultsView = null; 101 102 // Internal 103 Set expandedComponents = new HashSet(); 104 File resultsDir = null; 105 106 // Actions 107 Action filterAdvancedScenarios; 108 Action writeStatus; 109 110 // SWT resources 111 Font boldFont; 112 113 // Write Status 114 static int WRITE_STATUS; 115 116 /** 117 * Default constructor. 118 */ 119 public ComponentsView() { 120 // this.onlyFingerprintsImageDescriptor = ImageDescriptor.createFromFile(getClass(), "filter_ps.gif"); 121 super(); 122 123 // Get preferences 124 this.preferences = new InstanceScope().getNode(IPerformancesConstants.PLUGIN_ID); 125 126 // Init status 127 WRITE_STATUS = this.preferences.getInt(IPerformancesConstants.PRE_WRITE_STATUS, IPerformancesConstants.DEFAULT_WRITE_STATUS); 128 129 } 130 131 /* 132 * (non-Javadoc) 133 * @see org.eclipse.test.internal.performance.results.ui.PerformancesView#createPartControl(org.eclipse.swt.widgets.Composite) 134 */ 135 public void createPartControl(Composite parent) { 136 super.createPartControl(parent); 137 138 // Create the viewer 139 this.viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); 140 141 // Set the content provider: first level is components list 142 WorkbenchContentProvider contentProvider = new WorkbenchContentProvider() { 143 public Object[] getElements(Object o) { 144 return ComponentsView.this.getElements(); 145 } 146 }; 147 this.viewer.setContentProvider(contentProvider); 148 149 // Set the label provider 150 WorkbenchLabelProvider labelProvider = new WorkbenchLabelProvider() { 151 152 protected String decorateText(String input, Object element) { 153 String text = super.decorateText(input, element); 154 if (element instanceof BuildResultsElement) { 155 BuildResultsElement buildElement = (BuildResultsElement) element; 156 if (buildElement.isMilestone()) { 157 text = Util.getMilestoneName(buildElement.getName()) + " - "+text; 158 } 159 } 160 return text; 161 } 162 163 // When all scenarios are displayed, then set fingerprints one in bold. 164 public Font getFont(Object element) { 165 Font font = super.getFont(element); 166 if (element instanceof ScenarioResultsElement) { 167 // Action fingerprints = ComponentsView.this.filterNonFingerprints; 168 // if (fingerprints != null && !fingerprints.isChecked()) { 169 boolean fingerprints = ComponentsView.this.preferences.getBoolean(IPerformancesConstants.PRE_FILTER_ADVANCED_SCENARIOS, IPerformancesConstants.DEFAULT_FILTER_ADVANCED_SCENARIOS); 170 if (!fingerprints) { 171 ScenarioResultsElement scenarioElement = (ScenarioResultsElement) element; 172 if (scenarioElement.hasSummary()) { 173 return getBoldFont(font); 174 } 175 } 176 } 177 if (element instanceof BuildResultsElement) { 178 BuildResultsElement buildElement = (BuildResultsElement) element; 179 if (Util.isMilestone(buildElement.getName())) { 180 return getBoldFont(font); 181 } 182 } 183 return font; 184 } 185 }; 186 this.viewer.setLabelProvider(labelProvider); 187 188 // Set the children sorter 189 ViewerSorter nameSorter = new ViewerSorter() { 190 191 // Sort children using specific comparison (see the implementation 192 // of the #compareTo(Object) in the ResultsElement hierarchy 193 public int compare(Viewer view, Object e1, Object e2) { 194 // Config and Build results are sorted in reverse order 195 if (e1 instanceof BuildResultsElement) { 196 ResultsElement element = (ResultsElement) e2; 197 return element.compareTo(e1); 198 } 199 if (e1 instanceof ResultsElement) { 200 ResultsElement element = (ResultsElement) e1; 201 return element.compareTo(e2); 202 } 203 return super.compare(view, e1, e2); 204 } 205 }; 206 this.viewer.setSorter(nameSorter); 207 208 // Add results view as listener to viewer selection changes 209 Display.getDefault().asyncExec(new Runnable() { 210 public void run() { 211 ISelectionChangedListener listener = getResultsView(); 212 if (listener != null) { 213 ComponentsView.this.viewer.addSelectionChangedListener(listener); 214 } 215 } 216 }); 217 218 // Finalize viewer initialization 219 PlatformUI.getWorkbench().getHelpSystem().setHelp(this.viewer.getControl(), "org.eclipse.test.performance.ui.components"); 220 finalizeViewerCreation(); 221 } 222 223 /* 224 * (non-Javadoc) 225 * @see org.eclipse.ui.part.WorkbenchPart#dispose() 226 */ 227 public void dispose() { 228 if (this.boldFont != null) { 229 this.boldFont.dispose(); 230 } 231 // JFaceResources.getResources().destroyImage(this.onlyFingerprintsImageDescriptor); 232 super.dispose(); 233 } 234 235 /* 236 * (non-Javadoc) 237 * @see org.eclipse.test.internal.performance.results.ui.PerformancesView#fillLocalPullDown(org.eclipse.jface.action.IMenuManager) 238 */ 239 void fillFiltersDropDown(IMenuManager manager) { 240 super.fillFiltersDropDown(manager); 241 manager.add(this.filterOldBuilds); 242 manager.add(this.filterLastBuilds); 243 manager.add(new Separator()); 244 manager.add(this.filterAdvancedScenarios); 245 } 246 247 void fillLocalPullDown(IMenuManager manager) { 248 super.fillLocalPullDown(manager); 249 manager.add(new Separator()); 250 manager.add(this.writeStatus); 251 } 252 253 /* 254 * Filter non fingerprints scenarios action run. 255 */ 256 void filterAdvancedScenarios(boolean fingerprints, boolean updatePreference) { 257 this.results.setFingerprints(fingerprints); 258 if (fingerprints) { 259 this.viewFilters.add(FILTER_ADVANCED_SCENARIOS); 260 } else { 261 this.viewFilters.remove(FILTER_ADVANCED_SCENARIOS); 262 } 263 this.preferences.putBoolean(IPerformancesConstants.PRE_FILTER_ADVANCED_SCENARIOS, fingerprints); 264 updateFilters(); 265 } 266 267 /* 268 * Returns the bold font. 269 */ 270 Font getBoldFont(Font font) { 271 if (this.boldFont == null) { 272 FontData[] fontData = (font==null ? JFaceResources.getDefaultFont() : font).getFontData(); 273 FontData boldFontData = new FontData(fontData[0].getName(), fontData[0].getHeight(), SWT.BOLD); 274 this.boldFont = new Font(this.display, boldFontData); 275 } 276 return this.boldFont; 277 } 278 279 /* 280 * Get all the components from the model. 281 */ 282 Object[] getElements() { 283 if (this.results == null) { 284 initResults(); 285 if (this.filterAdvancedScenarios != null) { 286 this.results.setFingerprints(this.filterAdvancedScenarios.isChecked()); 287 } 288 } 289 return this.results.getElements(); 290 } 291 292 /* 293 * Return the components results view. 294 */ 295 ComponentResultsView getResultsView() { 296 if (this.componentResultsView == null) { 297 this.componentResultsView = (ComponentResultsView) getWorkbenchView("org.eclipse.test.internal.performance.results.ui.ComponentsResultsView"); 298 } 299 return this.componentResultsView; 300 } 301 302 /* 303 * Return the builds view. 304 */ 305 PerformancesView getSiblingView() { 306 if (this.buildsView == null) { 307 this.buildsView = (PerformancesView) getWorkbenchView("org.eclipse.test.internal.performance.results.ui.BuildsView"); 308 } 309 return this.buildsView; 310 } 311 312 /* 313 * (non-Javadoc) 314 * @see org.eclipse.test.internal.performance.results.ui.PerformancesView#makeActions() 315 */ 316 void makeActions() { 317 318 super.makeActions(); 319 320 // Filter non-fingerprints action 321 this.filterAdvancedScenarios = new Action("Advanced &Scenarios", IAction.AS_CHECK_BOX) { 322 public void run() { 323 filterAdvancedScenarios(isChecked(), true/*update preference*/); 324 } 325 }; 326 this.filterAdvancedScenarios.setChecked(true); 327 this.filterAdvancedScenarios.setToolTipText("Filter advanced scenarios (i.e. not fingerprint ones)"); 328 329 // Write status 330 this.writeStatus = new Action("Write status") { 331 public void run() { 332 333 // Get write directory 334 String filter = (ComponentsView.this.resultsDir == null) ? null : ComponentsView.this.resultsDir.getPath(); 335 final File writeDir = changeDir(filter, "Select a directory to write the status"); 336 if (writeDir != null) { 337 writeStatus(writeDir); 338 } 339 } 340 }; 341 this.writeStatus.setEnabled(true); 342 this.writeStatus.setToolTipText("Write component status to a file"); 343 344 // Set filters default 345 this.filterBaselineBuilds.setChecked(true); 346 this.filterNightlyBuilds.setChecked(false); 347 } 348 349 /* (non-Javadoc) 350 * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent) 351 */ 352 public void preferenceChange(PreferenceChangeEvent event) { 353 String propertyName = event.getKey(); 354 Object newValue = event.getNewValue(); 355 356 // Filter non-fingerprints change 357 if (propertyName.equals(IPerformancesConstants.PRE_FILTER_ADVANCED_SCENARIOS)) { 358 boolean checked = newValue == null ? IPerformancesConstants.DEFAULT_FILTER_ADVANCED_SCENARIOS : "true".equals(newValue); 359 filterAdvancedScenarios(checked, false/*do not update preference*/); 360 this.filterAdvancedScenarios.setChecked(checked); 361 } 362 363 // Filter non-milestone change 364 if (propertyName.equals(IPerformancesConstants.PRE_FILTER_OLD_BUILDS)) { 365 boolean checked = newValue == null ? IPerformancesConstants.DEFAULT_FILTER_OLD_BUILDS : "true".equals(newValue); 366 filterOldBuilds(checked, false/*do not update preference*/); 367 this.filterOldBuilds.setChecked(checked); 368 } 369 370 // Write status 371 if (propertyName.equals(IPerformancesConstants.PRE_WRITE_STATUS)) { 372 WRITE_STATUS = newValue == null ? IPerformancesConstants.DEFAULT_WRITE_STATUS : Integer.parseInt((String)newValue); 373 } 374 375 super.preferenceChange(event); 376 } 377 378 void restoreState() { 379 super.restoreState(); 380 381 // Filter baselines action default 382 if (this.viewState == null) { 383 this.filterBaselineBuilds.setChecked(true); 384 this.viewFilters.add(FILTER_BASELINE_BUILDS); 385 } else { 386 String dir = this.viewState.getString(IPerformancesConstants.PRE_WRITE_RESULTS_DIR); 387 if (dir != null) { 388 this.resultsDir = new File(dir); 389 } 390 } 391 392 // Filter non fingerprints action state 393 boolean checked = this.preferences.getBoolean(IPerformancesConstants.PRE_FILTER_ADVANCED_SCENARIOS, IPerformancesConstants.DEFAULT_FILTER_ADVANCED_SCENARIOS); 394 this.filterAdvancedScenarios.setChecked(checked); 395 if (checked) { 396 this.viewFilters.add(FILTER_ADVANCED_SCENARIOS); 397 } 398 } 399 400 public void saveState(IMemento memento) { 401 if (this.resultsDir != null) { 402 memento.putString(IPerformancesConstants.PRE_WRITE_RESULTS_DIR, this.resultsDir.getPath()); 403 } 404 super.saveState(memento); 405 } 406 407 /** 408 * Select a results element in the tree. 409 */ 410 public void select(ComponentResultsElement componentResults, String configName, String scenarioName, String buildName) { 411 412 // Collapse previous expanded components except the requested one 413 // TODO (frederic) also collapse expanded components children elements 414 this.expandedComponents.remove(componentResults); 415 Iterator iterator = this.expandedComponents.iterator(); 416 while (iterator.hasNext()) { 417 this.viewer.collapseToLevel(iterator.next(), AbstractTreeViewer.ALL_LEVELS); 418 } 419 this.expandedComponents.clear(); 420 421 // Set the tree selection 422 ScenarioResultsElement scenarioResultsElement = (ScenarioResultsElement) componentResults.getResultsElement(scenarioName); 423 if (scenarioResultsElement != null) { 424 ConfigResultsElement configResultsElement = (ConfigResultsElement) scenarioResultsElement.getResultsElement(configName); 425 if (configResultsElement != null) { 426 BuildResultsElement buildResultsElement = (BuildResultsElement) configResultsElement.getResultsElement(buildName); 427 if (buildResultsElement != null) { 428 this.viewer.setSelection(new StructuredSelection(buildResultsElement), true); 429 this.setFocus(); 430 } 431 } 432 } 433 } 434 435 /* 436 * (non-Javadoc) 437 * @see org.eclipse.test.internal.performance.results.ui.PerformancesView#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) 438 */ 439 public void selectionChanged(SelectionChangedEvent event) { 440 super.selectionChanged(event); 441 ResultsElement eventResultsElement = (ResultsElement) ((StructuredSelection)event.getSelection()).getFirstElement(); 442 if (eventResultsElement != null) { 443 ResultsElement eventComponentElement = eventResultsElement; 444 if (!(eventComponentElement instanceof ComponentResultsElement)) { 445 while (!(eventComponentElement instanceof ComponentResultsElement)) { 446 eventComponentElement = (ResultsElement) eventComponentElement.getParent(null); 447 } 448 this.expandedComponents.add(eventComponentElement); 449 } 450 } 451 } 452 453 protected void writeStatus(File writeDir) { 454 this.resultsDir = writeDir; 455 if (this.filterAdvancedScenarios.isChecked()) { 456 writeDir = new File(writeDir, "fingerprints"); 457 } else { 458 writeDir = new File(writeDir, "all"); 459 } 460 writeDir.mkdir(); 461 if ((WRITE_STATUS & IPerformancesConstants.STATUS_VALUES) != 0) { 462 writeDir = new File(writeDir, "values"); 463 } 464 int buildsNumber = WRITE_STATUS & IPerformancesConstants.STATUS_BUILDS_NUMBER_MASK; 465 if (buildsNumber > 1) { 466 writeDir = new File(writeDir, Integer.toString(buildsNumber)); 467 } 468 writeDir.mkdirs(); 469 String prefix = this.results.getName(); 470 File resultsFile = new File(writeDir, prefix+".log"); 471 File exclusionDir = new File(writeDir, "excluded"); 472 exclusionDir.mkdir(); 473 File exclusionFile = new File(exclusionDir, prefix+".log"); 474 if (resultsFile.exists()) { 475 int i=0; 476 File saveDir = new File(writeDir, "save"); 477 saveDir.mkdir(); 478 while (true) { 479 String newFileName = prefix+"_"; 480 if (i<10) newFileName += "0"; 481 newFileName += i; 482 File renamedFile = new File(saveDir, newFileName+".log"); 483 if (resultsFile.renameTo(renamedFile)) { 484 File renamedExclusionFile = new File(exclusionDir, newFileName+".log"); 485 exclusionFile.renameTo(renamedExclusionFile); 486 break; 487 } 488 i++; 489 } 490 } 491 492 // Write status 493 StringBuffer excluded = this.results.writeStatus(resultsFile, WRITE_STATUS); 494 if (excluded == null) { 495 MessageDialog.openWarning(this.shell, getTitleToolTip(), "The component is not read, hence no results can be written!"); 496 } 497 498 // Write exclusion file 499 try { 500 DataOutputStream stream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(exclusionFile))); 501 try { 502 stream.write(excluded.toString().getBytes()); 503 } 504 finally { 505 stream.close(); 506 } 507 } catch (FileNotFoundException e) { 508 System.err.println("Can't create exclusion file"+exclusionFile); //$NON-NLS-1$ 509 } catch (IOException e) { 510 e.printStackTrace(); 511 } 512 } 513 }