1 /*******************************************************************************
2 * Copyright (c) 2009 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Yann N. Dauphin (dhaemon@gmail.com) - Implementation
11 * Francois Chouinard (fchouinard@gmail.com) - Initial API
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.lttng
.ui
.views
.statistics
;
16 import java
.text
.DecimalFormat
;
17 import java
.util
.Arrays
;
18 import java
.util
.HashSet
;
21 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
22 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
23 import org
.eclipse
.jface
.viewers
.TreeViewer
;
24 import org
.eclipse
.jface
.viewers
.TreeViewerColumn
;
25 import org
.eclipse
.jface
.viewers
.Viewer
;
26 import org
.eclipse
.jface
.viewers
.ViewerComparator
;
27 import org
.eclipse
.linuxtools
.lttng
.state
.IStateDataRequestListener
;
28 import org
.eclipse
.linuxtools
.lttng
.state
.RequestCompletedSignal
;
29 import org
.eclipse
.linuxtools
.lttng
.state
.RequestStartedSignal
;
30 import org
.eclipse
.linuxtools
.lttng
.state
.evProcessor
.EventProcessorProxy
;
31 import org
.eclipse
.linuxtools
.lttng
.state
.experiment
.StateExperimentManager
;
32 import org
.eclipse
.linuxtools
.lttng
.state
.experiment
.StateManagerFactory
;
33 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.statistics
.evProcessor
.StatsEventCountHandlerFactory
;
34 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.statistics
.evProcessor
.StatsTimeCountHandlerFactory
;
35 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.statistics
.model
.StatisticsTreeFactory
;
36 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.statistics
.model
.StatisticsTreeNode
;
37 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfSignalHandler
;
38 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
39 import org
.eclipse
.swt
.SWT
;
40 import org
.eclipse
.swt
.events
.SelectionAdapter
;
41 import org
.eclipse
.swt
.events
.SelectionEvent
;
42 import org
.eclipse
.swt
.graphics
.Color
;
43 import org
.eclipse
.swt
.graphics
.Image
;
44 import org
.eclipse
.swt
.layout
.FillLayout
;
45 import org
.eclipse
.swt
.widgets
.Composite
;
46 import org
.eclipse
.swt
.widgets
.Event
;
47 import org
.eclipse
.swt
.widgets
.Listener
;
48 import org
.eclipse
.ui
.ISharedImages
;
49 import org
.eclipse
.ui
.PlatformUI
;
52 * <b><u>StatisticsView</u></b>
54 * The Statistics View displays statistics for traces.
56 * It is implemented according to the MVC pattern. - The model is a
57 * StatisticsTreeNode built by the State Manager. - The view is built with a
58 * TreeViewer. - The controller that keeps model and view synchronised is an
59 * observer of the model.
61 public class StatisticsView
extends TmfView
implements
62 IStateDataRequestListener
{
64 public static final String ID
= "org.eclipse.linuxtools.lttng.ui.views.statistics";
66 private TreeViewer treeViewer
;
69 private final String LEVEL_COLUMN
= "Level";
70 private final String EVENTS_COUNT_COLUMN
= "Number of Events";
71 private final String CPU_TIME_COLUMN
= "CPU Time";
72 private final String CUMULATIVE_CPU_TIME_COLUMN
= "Cumulative CPU Time";
73 private final String ELAPSED_TIME_COLUMN
= "Elapsed Time";
75 // Table column tooltips
76 private final String LEVEL_COLUMN_TIP
= "Level at which statistics apply.";
77 private final String EVENTS_COUNT_COLUMN_TIP
= "Total amount of events that are tied to given resource.";
78 private final String CPU_TIME_COLUMN_TIP
= "Total amount of time the CPU was used excluding wait times(I/O, etc.) at that level.";
79 private final String CUMULATIVE_CPU_TIME_COLUMN_TIP
= "Total amount of time between the first and last event excluding wait times in a level.";
80 private final String ELAPSED_TIME_COLUMN_TIP
= "Total amount of time the CPU was used including wait times(I/O, etc.) at that level.";
82 // Level for which statistics should not be displayed.
83 private Set
<String
> folderLevels
= new HashSet
<String
>(Arrays
84 .asList(new String
[] { "Event Types", "Modes", "Submodes", "CPUs",
85 "Processes", "Functions" }));
87 // Levels for which sub-levels should not contain time-related statistics.
88 private Set
<String
> levelsWithEmptyTime
= new HashSet
<String
>(Arrays
89 .asList(new String
[] { "Event Types" }));
91 private DecimalFormat decimalFormat
= new DecimalFormat("0.#########");
93 // Used to draw bar charts in columns.
94 private interface ColumnPercentageProvider
{
95 public double getPercentage(StatisticsTreeNode node
);
99 * Contains all the information necessary to build a column of the table.
101 private class ColumnData
{
102 // Name of the column.
103 public final String header
;
104 // Width of the column.
105 public final int width
;
106 // Alignment of the column.
107 public final int alignment
;
108 // Tooltip of the column.
109 public final String tooltip
;
110 // Adapts a StatisticsTreeNode into the content of it's corresponding
111 // cell for that column.
112 public final ColumnLabelProvider labelProvider
;
113 // Used to sort elements of this column. Can be null.
114 public final ViewerComparator comparator
;
115 // Used to draw bar charts in this column. Can be null.
116 public final ColumnPercentageProvider percentageProvider
;
118 public ColumnData(String h
, int w
, int a
, String t
,
119 ColumnLabelProvider l
, ViewerComparator c
,
120 ColumnPercentageProvider p
) {
127 percentageProvider
= p
;
131 // List that will be used to create the table.
132 private ColumnData
[] columnDataList
= new ColumnData
[] {
133 new ColumnData(LEVEL_COLUMN
, 200, SWT
.LEFT
, LEVEL_COLUMN_TIP
,
134 new ColumnLabelProvider() {
136 public String
getText(Object element
) {
137 return ((StatisticsTreeNode
) element
).getKey();
141 public Image
getImage(Object element
) {
142 StatisticsTreeNode node
= (StatisticsTreeNode
) element
;
143 if (folderLevels
.contains(node
.getKey())) {
144 return PlatformUI
.getWorkbench()
145 .getSharedImages().getImage(
146 ISharedImages
.IMG_OBJ_FOLDER
);
148 return PlatformUI
.getWorkbench()
149 .getSharedImages().getImage(
150 ISharedImages
.IMG_OBJ_ELEMENT
);
153 }, new ViewerComparator() {
155 public int compare(Viewer viewer
, Object e1
, Object e2
) {
156 StatisticsTreeNode n1
= (StatisticsTreeNode
) e1
;
157 StatisticsTreeNode n2
= (StatisticsTreeNode
) e2
;
159 return n1
.getKey().compareTo(n2
.getKey());
162 new ColumnData(EVENTS_COUNT_COLUMN
, 125, SWT
.LEFT
,
163 EVENTS_COUNT_COLUMN_TIP
, new ColumnLabelProvider() {
165 public String
getText(Object element
) {
166 StatisticsTreeNode node
= (StatisticsTreeNode
) element
;
167 if (!folderLevels
.contains(node
.getKey())) {
168 return Long
.toString(node
.getValue().nbEvents
);
173 }, new ViewerComparator() {
175 public int compare(Viewer viewer
, Object e1
, Object e2
) {
176 StatisticsTreeNode n1
= (StatisticsTreeNode
) e1
;
177 StatisticsTreeNode n2
= (StatisticsTreeNode
) e2
;
179 return (int) (n1
.getValue().nbEvents
- n2
180 .getValue().nbEvents
);
182 }, new ColumnPercentageProvider() {
183 public double getPercentage(StatisticsTreeNode node
) {
184 StatisticsTreeNode parent
= node
;
186 parent
= parent
.getParent();
187 } while (parent
!= null
188 && parent
.getValue().nbEvents
== 0);
190 if (parent
== null) {
193 return (double) node
.getValue().nbEvents
194 / parent
.getValue().nbEvents
;
198 new ColumnData(CPU_TIME_COLUMN
, 125, SWT
.LEFT
, CPU_TIME_COLUMN_TIP
,
199 new ColumnLabelProvider() {
201 public String
getText(Object element
) {
202 StatisticsTreeNode node
= (StatisticsTreeNode
) element
;
204 if (folderLevels
.contains(node
.getKey())) {
206 } else if (node
.getParent() != null
207 && levelsWithEmptyTime
.contains(node
208 .getParent().getKey())) {
212 .format(node
.getValue().cpuTime
217 new ColumnData(CUMULATIVE_CPU_TIME_COLUMN
, 155, SWT
.LEFT
,
218 CUMULATIVE_CPU_TIME_COLUMN_TIP
, new ColumnLabelProvider() {
220 public String
getText(Object element
) {
221 StatisticsTreeNode node
= (StatisticsTreeNode
) element
;
222 if (folderLevels
.contains(node
.getKey())) {
224 } else if (node
.getParent() != null
225 && levelsWithEmptyTime
.contains(node
226 .getParent().getKey())) {
230 .format(node
.getValue().cumulativeCpuTime
235 new ColumnData(ELAPSED_TIME_COLUMN
, 100, SWT
.LEFT
,
236 ELAPSED_TIME_COLUMN_TIP
, new ColumnLabelProvider() {
238 public String
getText(Object element
) {
239 StatisticsTreeNode node
= (StatisticsTreeNode
) element
;
240 if (folderLevels
.contains(node
.getKey())) {
242 } else if (node
.getParent() != null
243 && levelsWithEmptyTime
.contains(node
244 .getParent().getKey())) {
248 .format(node
.getValue().elapsedTime
255 * Adapter TreeViewers can use to interact with StatisticsTreeNode objects.
257 * @see org.eclipse.jface.viewers.ITreeContentProvider
259 class TreeContentProvider
implements ITreeContentProvider
{
264 * org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang
267 public Object
[] getChildren(Object parentElement
) {
268 return ((StatisticsTreeNode
) parentElement
).getChildren().toArray();
275 * org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang
278 public Object
getParent(Object element
) {
279 return ((StatisticsTreeNode
) element
).getParent();
286 * org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang
289 public boolean hasChildren(Object element
) {
290 return ((StatisticsTreeNode
) element
).hasChildren();
297 * org.eclipse.jface.viewers.IStructuredContentProvider#getElements(
300 public Object
[] getElements(Object inputElement
) {
301 return getChildren(inputElement
);
307 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
309 public void dispose() {
316 * org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse
317 * .jface.viewers.Viewer, java.lang.Object, java.lang.Object)
320 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
328 * org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets
332 public void createPartControl(Composite parent
) {
333 EventProcessorProxy
.getInstance().addEventProcessorFactory(
334 StatsTimeCountHandlerFactory
.getInstance());
335 EventProcessorProxy
.getInstance().addEventProcessorFactory(
336 StatsEventCountHandlerFactory
.getInstance());
338 parent
.setLayout(new FillLayout());
340 treeViewer
= new TreeViewer(parent
, SWT
.BORDER
| SWT
.H_SCROLL
342 treeViewer
.setContentProvider(new TreeContentProvider());
343 treeViewer
.getTree().setHeaderVisible(true);
344 treeViewer
.setUseHashlookup(true);
346 for (final ColumnData columnData
: columnDataList
) {
347 final TreeViewerColumn treeColumn
= new TreeViewerColumn(
348 treeViewer
, columnData
.alignment
);
349 treeColumn
.getColumn().setText(columnData
.header
);
350 treeColumn
.getColumn().setWidth(columnData
.width
);
351 treeColumn
.getColumn().setToolTipText(columnData
.tooltip
);
352 if (columnData
.comparator
!= null) {
353 treeColumn
.getColumn().addSelectionListener(
354 new SelectionAdapter() {
356 public void widgetSelected(SelectionEvent e
) {
357 if (treeViewer
.getTree().getSortDirection() == SWT
.UP
358 || treeViewer
.getTree().getSortColumn() != treeColumn
361 .setComparator(columnData
.comparator
);
362 treeViewer
.getTree().setSortDirection(
366 .setComparator(new ViewerComparator() {
370 Object e1
, Object e2
) {
372 * columnData
.comparator
379 treeViewer
.getTree().setSortDirection(
382 treeViewer
.getTree().setSortColumn(
383 treeColumn
.getColumn());
387 treeColumn
.setLabelProvider(columnData
.labelProvider
);
390 // Handler that will draw the bar charts.
391 treeViewer
.getTree().addListener(SWT
.EraseItem
, new Listener() {
393 public void handleEvent(Event event
) {
394 if (columnDataList
[event
.index
].percentageProvider
!= null) {
395 StatisticsTreeNode node
= (StatisticsTreeNode
) event
.item
398 double percentage
= columnDataList
[event
.index
].percentageProvider
399 .getPercentage(node
);
400 if (percentage
== 0) {
404 if ((event
.detail
& SWT
.SELECTED
) > 0) {
405 Color oldForeground
= event
.gc
.getForeground();
406 event
.gc
.setForeground(event
.item
.getDisplay()
407 .getSystemColor(SWT
.COLOR_LIST_SELECTION
));
408 event
.gc
.fillRectangle(event
.x
, event
.y
, event
.width
,
410 event
.gc
.setForeground(oldForeground
);
411 event
.detail
&= ~SWT
.SELECTED
;
414 int barWidth
= (int) ((treeViewer
.getTree().getColumn(1)
415 .getWidth() - 8) * percentage
);
416 int oldAlpha
= event
.gc
.getAlpha();
417 Color oldForeground
= event
.gc
.getForeground();
418 Color oldBackground
= event
.gc
.getBackground();
419 event
.gc
.setAlpha(64);
420 event
.gc
.setForeground(event
.item
.getDisplay()
421 .getSystemColor(SWT
.COLOR_BLUE
));
422 event
.gc
.setBackground(event
.item
.getDisplay()
423 .getSystemColor(SWT
.COLOR_LIST_BACKGROUND
));
424 event
.gc
.fillGradientRectangle(event
.x
, event
.y
, barWidth
,
426 event
.gc
.drawRectangle(event
.x
, event
.y
, barWidth
,
428 event
.gc
.setForeground(oldForeground
);
429 event
.gc
.setBackground(oldBackground
);
430 event
.gc
.setAlpha(oldAlpha
);
431 event
.detail
&= ~SWT
.BACKGROUND
;
436 treeViewer
.setComparator(columnDataList
[0].comparator
);
437 treeViewer
.getTree().setSortColumn(treeViewer
.getTree().getColumn(0));
438 treeViewer
.getTree().setSortDirection(SWT
.DOWN
);
440 treeViewer
.setInput(StatisticsTreeFactory
441 .getStatisticsTree("Experiment"));
443 // Read current data if any available
444 StateExperimentManager experimentManger
= StateManagerFactory
445 .getExperimentManager();
446 experimentManger
.readExperiment("statisticsView", this);
450 public void dispose() {
452 EventProcessorProxy
.getInstance().removeEventProcessorFactory(
453 StatsTimeCountHandlerFactory
.getInstance());
454 EventProcessorProxy
.getInstance().removeEventProcessorFactory(
455 StatsEventCountHandlerFactory
.getInstance());
462 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
465 public void setFocus() {
466 treeViewer
.getTree().setFocus();
470 public void processingStarted(RequestStartedSignal request
) {
471 // Nothing to do for the time being
476 public void processingCompleted(RequestCompletedSignal signal
) {
477 treeViewer
.getTree().getDisplay().asyncExec(new Runnable() {
480 treeViewer
.refresh();