[Bug292967] Second part of request coalescing + unit tests + minor fixes.
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng.ui / src / org / eclipse / linuxtools / lttng / ui / views / statistics / StatisticsView.java
CommitLineData
6e512b93
ASL
1/*******************************************************************************
2 * Copyright (c) 2009 Ericsson
3 *
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
8 *
9 * Contributors:
dfaf8391
FC
10 * Yann N. Dauphin (dhaemon@gmail.com) - Implementation
11 * Francois Chouinard (fchouinard@gmail.com) - Initial API
6e512b93
ASL
12 *******************************************************************************/
13
14package org.eclipse.linuxtools.lttng.ui.views.statistics;
15
dfaf8391
FC
16import java.text.DecimalFormat;
17import java.util.Arrays;
18import java.util.HashSet;
19import java.util.Set;
20
21import org.eclipse.jface.viewers.ColumnLabelProvider;
22import org.eclipse.jface.viewers.ITreeContentProvider;
23import org.eclipse.jface.viewers.TreeViewer;
24import org.eclipse.jface.viewers.TreeViewerColumn;
25import org.eclipse.jface.viewers.Viewer;
26import org.eclipse.jface.viewers.ViewerComparator;
27import org.eclipse.linuxtools.lttng.state.IStateDataRequestListener;
28import org.eclipse.linuxtools.lttng.state.RequestCompletedSignal;
29import org.eclipse.linuxtools.lttng.state.RequestStartedSignal;
30import org.eclipse.linuxtools.lttng.state.evProcessor.EventProcessorProxy;
31import org.eclipse.linuxtools.lttng.state.experiment.StateExperimentManager;
32import org.eclipse.linuxtools.lttng.state.experiment.StateManagerFactory;
33import org.eclipse.linuxtools.lttng.ui.views.statistics.evProcessor.StatsEventCountHandlerFactory;
34import org.eclipse.linuxtools.lttng.ui.views.statistics.evProcessor.StatsTimeCountHandlerFactory;
35import org.eclipse.linuxtools.lttng.ui.views.statistics.model.StatisticsTreeFactory;
36import org.eclipse.linuxtools.lttng.ui.views.statistics.model.StatisticsTreeNode;
37import org.eclipse.linuxtools.tmf.signal.TmfSignalHandler;
38import org.eclipse.linuxtools.tmf.ui.views.TmfView;
39import org.eclipse.swt.SWT;
40import org.eclipse.swt.events.SelectionAdapter;
41import org.eclipse.swt.events.SelectionEvent;
42import org.eclipse.swt.graphics.Color;
43import org.eclipse.swt.graphics.Image;
44import org.eclipse.swt.layout.FillLayout;
6e512b93 45import org.eclipse.swt.widgets.Composite;
dfaf8391
FC
46import org.eclipse.swt.widgets.Event;
47import org.eclipse.swt.widgets.Listener;
48import org.eclipse.ui.ISharedImages;
49import org.eclipse.ui.PlatformUI;
6e512b93
ASL
50
51/**
52 * <b><u>StatisticsView</u></b>
53 * <p>
dfaf8391
FC
54 * The Statistics View displays statistics for traces.
55 *
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.
6e512b93 60 */
fc6ccf6f 61public class StatisticsView extends TmfView implements IStateDataRequestListener {
dfaf8391
FC
62
63 public static final String ID = "org.eclipse.linuxtools.lttng.ui.views.statistics";
64
65 private TreeViewer treeViewer;
66
67 // Table column names
68 private final String LEVEL_COLUMN = "Level";
69 private final String EVENTS_COUNT_COLUMN = "Number of Events";
70 private final String CPU_TIME_COLUMN = "CPU Time";
71 private final String CUMULATIVE_CPU_TIME_COLUMN = "Cumulative CPU Time";
72 private final String ELAPSED_TIME_COLUMN = "Elapsed Time";
73
74 // Table column tooltips
75 private final String LEVEL_COLUMN_TIP = "Level at which statistics apply.";
76 private final String EVENTS_COUNT_COLUMN_TIP = "Total amount of events that are tied to given resource.";
77 private final String CPU_TIME_COLUMN_TIP = "Total amount of time the CPU was used excluding wait times(I/O, etc.) at that level.";
78 private final String CUMULATIVE_CPU_TIME_COLUMN_TIP = "Total amount of time between the first and last event excluding wait times in a level.";
79 private final String ELAPSED_TIME_COLUMN_TIP = "Total amount of time the CPU was used including wait times(I/O, etc.) at that level.";
6e512b93 80
dfaf8391
FC
81 // Level for which statistics should not be displayed.
82 private Set<String> folderLevels = new HashSet<String>(Arrays
83 .asList(new String[] { "Event Types", "Modes", "Submodes", "CPUs",
84 "Processes", "Functions" }));
6e512b93 85
dfaf8391
FC
86 // Levels for which sub-levels should not contain time-related statistics.
87 private Set<String> levelsWithEmptyTime = new HashSet<String>(Arrays
88 .asList(new String[] { "Event Types" }));
89
90 private DecimalFormat decimalFormat = new DecimalFormat("0.#########");
91
92 // Used to draw bar charts in columns.
93 private interface ColumnPercentageProvider {
94 public double getPercentage(StatisticsTreeNode node);
95 }
96
97 /**
98 * Contains all the information necessary to build a column of the table.
99 */
100 private class ColumnData {
101 // Name of the column.
102 public final String header;
103 // Width of the column.
104 public final int width;
105 // Alignment of the column.
106 public final int alignment;
107 // Tooltip of the column.
108 public final String tooltip;
109 // Adapts a StatisticsTreeNode into the content of it's corresponding
110 // cell for that column.
111 public final ColumnLabelProvider labelProvider;
112 // Used to sort elements of this column. Can be null.
113 public final ViewerComparator comparator;
114 // Used to draw bar charts in this column. Can be null.
115 public final ColumnPercentageProvider percentageProvider;
116
117 public ColumnData(String h, int w, int a, String t,
118 ColumnLabelProvider l, ViewerComparator c,
119 ColumnPercentageProvider p) {
120 header = h;
121 width = w;
122 alignment = a;
123 tooltip = t;
124 labelProvider = l;
125 comparator = c;
126 percentageProvider = p;
127 }
128 };
129
130 // List that will be used to create the table.
131 private ColumnData[] columnDataList = new ColumnData[] {
132 new ColumnData(LEVEL_COLUMN, 200, SWT.LEFT, LEVEL_COLUMN_TIP,
133 new ColumnLabelProvider() {
134 @Override
135 public String getText(Object element) {
136 return ((StatisticsTreeNode) element).getKey();
137 }
138
139 @Override
140 public Image getImage(Object element) {
141 StatisticsTreeNode node = (StatisticsTreeNode) element;
142 if (folderLevels.contains(node.getKey())) {
143 return PlatformUI.getWorkbench()
144 .getSharedImages().getImage(
145 ISharedImages.IMG_OBJ_FOLDER);
146 } else {
147 return PlatformUI.getWorkbench()
148 .getSharedImages().getImage(
149 ISharedImages.IMG_OBJ_ELEMENT);
150 }
151 }
152 }, new ViewerComparator() {
153 @Override
154 public int compare(Viewer viewer, Object e1, Object e2) {
155 StatisticsTreeNode n1 = (StatisticsTreeNode) e1;
156 StatisticsTreeNode n2 = (StatisticsTreeNode) e2;
157
158 return n1.getKey().compareTo(n2.getKey());
159 }
160 }, null),
161 new ColumnData(EVENTS_COUNT_COLUMN, 125, SWT.LEFT,
162 EVENTS_COUNT_COLUMN_TIP, new ColumnLabelProvider() {
163 @Override
164 public String getText(Object element) {
165 StatisticsTreeNode node = (StatisticsTreeNode) element;
166 if (!folderLevels.contains(node.getKey())) {
167 return Long.toString(node.getValue().nbEvents);
168 } else {
169 return "";
170 }
171 }
172 }, new ViewerComparator() {
173 @Override
174 public int compare(Viewer viewer, Object e1, Object e2) {
175 StatisticsTreeNode n1 = (StatisticsTreeNode) e1;
176 StatisticsTreeNode n2 = (StatisticsTreeNode) e2;
177
178 return (int) (n1.getValue().nbEvents - n2
179 .getValue().nbEvents);
180 }
181 }, new ColumnPercentageProvider() {
182 public double getPercentage(StatisticsTreeNode node) {
183 StatisticsTreeNode parent = node;
184 do {
185 parent = parent.getParent();
186 } while (parent != null
187 && parent.getValue().nbEvents == 0);
188
189 if (parent == null) {
190 return 0;
191 } else {
192 return (double) node.getValue().nbEvents
193 / parent.getValue().nbEvents;
194 }
195 }
196 }),
197 new ColumnData(CPU_TIME_COLUMN, 125, SWT.LEFT, CPU_TIME_COLUMN_TIP,
198 new ColumnLabelProvider() {
199 @Override
200 public String getText(Object element) {
201 StatisticsTreeNode node = (StatisticsTreeNode) element;
202
203 if (folderLevels.contains(node.getKey())) {
204 return "";
205 } else if (node.getParent() != null
206 && levelsWithEmptyTime.contains(node
207 .getParent().getKey())) {
208 return "";
209 } else {
210 return decimalFormat
211 .format(node.getValue().cpuTime
212 / Math.pow(10, 9));
213 }
214 }
215 }, null, null),
216 new ColumnData(CUMULATIVE_CPU_TIME_COLUMN, 155, SWT.LEFT,
217 CUMULATIVE_CPU_TIME_COLUMN_TIP, new ColumnLabelProvider() {
218 @Override
219 public String getText(Object element) {
220 StatisticsTreeNode node = (StatisticsTreeNode) element;
221 if (folderLevels.contains(node.getKey())) {
222 return "";
223 } else if (node.getParent() != null
224 && levelsWithEmptyTime.contains(node
225 .getParent().getKey())) {
226 return "";
227 } else {
228 return decimalFormat
229 .format(node.getValue().cumulativeCpuTime
230 / Math.pow(10, 9));
231 }
232 }
233 }, null, null),
234 new ColumnData(ELAPSED_TIME_COLUMN, 100, SWT.LEFT,
235 ELAPSED_TIME_COLUMN_TIP, new ColumnLabelProvider() {
236 @Override
237 public String getText(Object element) {
238 StatisticsTreeNode node = (StatisticsTreeNode) element;
239 if (folderLevels.contains(node.getKey())) {
240 return "";
241 } else if (node.getParent() != null
242 && levelsWithEmptyTime.contains(node
243 .getParent().getKey())) {
244 return "";
245 } else {
246 return decimalFormat
247 .format(node.getValue().elapsedTime
248 / Math.pow(10, 9));
249 }
250 }
251 }, null, null) };
252
253 /**
254 * Adapter TreeViewers can use to interact with StatisticsTreeNode objects.
6e512b93 255 *
dfaf8391 256 * @see org.eclipse.jface.viewers.ITreeContentProvider
6e512b93 257 */
dfaf8391
FC
258 class TreeContentProvider implements ITreeContentProvider {
259 /*
260 * (non-Javadoc)
261 *
262 * @see
263 * org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang
264 * .Object)
265 */
266 public Object[] getChildren(Object parentElement) {
267 return ((StatisticsTreeNode) parentElement).getChildren().toArray();
268 }
269
270 /*
271 * (non-Javadoc)
272 *
273 * @see
274 * org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang
275 * .Object)
276 */
277 public Object getParent(Object element) {
278 return ((StatisticsTreeNode) element).getParent();
279 }
280
281 /*
282 * (non-Javadoc)
283 *
284 * @see
285 * org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang
286 * .Object)
287 */
288 public boolean hasChildren(Object element) {
289 return ((StatisticsTreeNode) element).hasChildren();
290 }
291
292 /*
293 * (non-Javadoc)
294 *
295 * @see
296 * org.eclipse.jface.viewers.IStructuredContentProvider#getElements(
297 * java.lang.Object)
298 */
299 public Object[] getElements(Object inputElement) {
300 return getChildren(inputElement);
301 }
302
303 /*
304 * (non-Javadoc)
305 *
306 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
307 */
308 public void dispose() {
309 }
310
311 /*
312 * (non-Javadoc)
313 *
314 * @see
315 * org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse
316 * .jface.viewers.Viewer, java.lang.Object, java.lang.Object)
317 */
318 // @Override
319 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
320 }
6e512b93
ASL
321 }
322
fc6ccf6f 323 public StatisticsView(String viewName) {
951d134a
FC
324 super(viewName);
325 }
326
327 public StatisticsView() {
328 this("StatisticsView");
fc6ccf6f
FC
329 }
330
dfaf8391
FC
331 /*
332 * (non-Javadoc)
333 *
334 * @see
335 * org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets
336 * .Composite)
6e512b93
ASL
337 */
338 @Override
339 public void createPartControl(Composite parent) {
dfaf8391
FC
340 EventProcessorProxy.getInstance().addEventProcessorFactory(
341 StatsTimeCountHandlerFactory.getInstance());
342 EventProcessorProxy.getInstance().addEventProcessorFactory(
343 StatsEventCountHandlerFactory.getInstance());
344
345 parent.setLayout(new FillLayout());
346
347 treeViewer = new TreeViewer(parent, SWT.BORDER | SWT.H_SCROLL
348 | SWT.V_SCROLL);
349 treeViewer.setContentProvider(new TreeContentProvider());
350 treeViewer.getTree().setHeaderVisible(true);
351 treeViewer.setUseHashlookup(true);
352
353 for (final ColumnData columnData : columnDataList) {
354 final TreeViewerColumn treeColumn = new TreeViewerColumn(
355 treeViewer, columnData.alignment);
356 treeColumn.getColumn().setText(columnData.header);
357 treeColumn.getColumn().setWidth(columnData.width);
358 treeColumn.getColumn().setToolTipText(columnData.tooltip);
359 if (columnData.comparator != null) {
360 treeColumn.getColumn().addSelectionListener(
361 new SelectionAdapter() {
362 @Override
363 public void widgetSelected(SelectionEvent e) {
364 if (treeViewer.getTree().getSortDirection() == SWT.UP
365 || treeViewer.getTree().getSortColumn() != treeColumn
366 .getColumn()) {
367 treeViewer
368 .setComparator(columnData.comparator);
369 treeViewer.getTree().setSortDirection(
370 SWT.DOWN);
371 } else {
372 treeViewer
373 .setComparator(new ViewerComparator() {
374 @Override
375 public int compare(
376 Viewer viewer,
377 Object e1, Object e2) {
378 return -1
379 * columnData.comparator
380 .compare(
381 viewer,
382 e1,
383 e2);
384 }
385 });
386 treeViewer.getTree().setSortDirection(
387 SWT.UP);
388 }
389 treeViewer.getTree().setSortColumn(
390 treeColumn.getColumn());
391 }
392 });
393 }
394 treeColumn.setLabelProvider(columnData.labelProvider);
395 }
396
397 // Handler that will draw the bar charts.
398 treeViewer.getTree().addListener(SWT.EraseItem, new Listener() {
399 // @Override
400 public void handleEvent(Event event) {
401 if (columnDataList[event.index].percentageProvider != null) {
402 StatisticsTreeNode node = (StatisticsTreeNode) event.item
403 .getData();
404
405 double percentage = columnDataList[event.index].percentageProvider
406 .getPercentage(node);
407 if (percentage == 0) {
408 return;
409 }
410
411 if ((event.detail & SWT.SELECTED) > 0) {
412 Color oldForeground = event.gc.getForeground();
413 event.gc.setForeground(event.item.getDisplay()
414 .getSystemColor(SWT.COLOR_LIST_SELECTION));
415 event.gc.fillRectangle(event.x, event.y, event.width,
416 event.height);
417 event.gc.setForeground(oldForeground);
418 event.detail &= ~SWT.SELECTED;
419 }
420
421 int barWidth = (int) ((treeViewer.getTree().getColumn(1)
422 .getWidth() - 8) * percentage);
423 int oldAlpha = event.gc.getAlpha();
424 Color oldForeground = event.gc.getForeground();
425 Color oldBackground = event.gc.getBackground();
426 event.gc.setAlpha(64);
427 event.gc.setForeground(event.item.getDisplay()
428 .getSystemColor(SWT.COLOR_BLUE));
429 event.gc.setBackground(event.item.getDisplay()
430 .getSystemColor(SWT.COLOR_LIST_BACKGROUND));
431 event.gc.fillGradientRectangle(event.x, event.y, barWidth,
432 event.height, true);
433 event.gc.drawRectangle(event.x, event.y, barWidth,
434 event.height);
435 event.gc.setForeground(oldForeground);
436 event.gc.setBackground(oldBackground);
437 event.gc.setAlpha(oldAlpha);
438 event.detail &= ~SWT.BACKGROUND;
439 }
440 }
441 });
442
443 treeViewer.setComparator(columnDataList[0].comparator);
444 treeViewer.getTree().setSortColumn(treeViewer.getTree().getColumn(0));
445 treeViewer.getTree().setSortDirection(SWT.DOWN);
446
447 treeViewer.setInput(StatisticsTreeFactory
448 .getStatisticsTree("Experiment"));
449
450 // Read current data if any available
451 StateExperimentManager experimentManger = StateManagerFactory
452 .getExperimentManager();
453 experimentManger.readExperiment("statisticsView", this);
454
455 }
456 @Override
457 public void dispose() {
458 super.dispose();
459 EventProcessorProxy.getInstance().removeEventProcessorFactory(
460 StatsTimeCountHandlerFactory.getInstance());
461 EventProcessorProxy.getInstance().removeEventProcessorFactory(
462 StatsEventCountHandlerFactory.getInstance());
6e512b93 463
6e512b93
ASL
464 }
465
dfaf8391
FC
466 /*
467 * (non-Javadoc)
468 *
6e512b93
ASL
469 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
470 */
471 @Override
472 public void setFocus() {
dfaf8391
FC
473 treeViewer.getTree().setFocus();
474 }
475
476 @TmfSignalHandler
477 public void processingStarted(RequestStartedSignal request) {
478 // Nothing to do for the time being
6e512b93 479
6e512b93
ASL
480 }
481
dfaf8391
FC
482 @TmfSignalHandler
483 public void processingCompleted(RequestCompletedSignal signal) {
484 treeViewer.getTree().getDisplay().asyncExec(new Runnable() {
485 // @Override
486 public void run() {
487 treeViewer.refresh();
488 }
489 });
490 }
6e512b93 491}
This page took 0.045615 seconds and 5 git commands to generate.