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 */
ComponentsView()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 */
createPartControl(Composite parent)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 */
dispose()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 */
fillFiltersDropDown(IMenuManager manager)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
fillLocalPullDown(IMenuManager manager)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 */
filterAdvancedScenarios(boolean fingerprints, boolean updatePreference)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 */
getBoldFont(Font font)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 */
getElements()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 */
getResultsView()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 */
getSiblingView()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 */
makeActions()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 */
preferenceChange(PreferenceChangeEvent event)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
restoreState()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
saveState(IMemento memento)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 */
select(ComponentResultsElement componentResults, String configName, String scenarioName, String buildName)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 */
selectionChanged(SelectionChangedEvent event)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
writeStatus(File writeDir)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 }