ss: Rename packages to org.eclipse.tracecompass.*
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / viewers / statistics / TmfStatisticsViewer.java
CommitLineData
cfd22ad0 1/*******************************************************************************
87f83123 2 * Copyright (c) 2012, 2014 Ericsson
cfd22ad0
MD
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:
10 * Mathieu Denis <mathieu.denis@polymtl.ca> - Initial API and implementation
89c06060 11 * Alexandre Montplaisir - Port to ITmfStatistics provider
0fcf3b09 12 * Patrick Tasse - Support selection range
cfd22ad0
MD
13 *******************************************************************************/
14
2bdf0193 15package org.eclipse.tracecompass.tmf.ui.viewers.statistics;
cfd22ad0
MD
16
17import java.util.List;
89c06060 18import java.util.Map;
cfd22ad0
MD
19
20import org.eclipse.jface.viewers.TreeViewer;
21import org.eclipse.jface.viewers.TreeViewerColumn;
22import org.eclipse.jface.viewers.Viewer;
23import org.eclipse.jface.viewers.ViewerComparator;
cfd22ad0
MD
24import org.eclipse.swt.SWT;
25import org.eclipse.swt.events.SelectionAdapter;
26import org.eclipse.swt.events.SelectionEvent;
27import org.eclipse.swt.graphics.Color;
28import org.eclipse.swt.graphics.Cursor;
cfd22ad0
MD
29import org.eclipse.swt.widgets.Composite;
30import org.eclipse.swt.widgets.Control;
31import org.eclipse.swt.widgets.Display;
32import org.eclipse.swt.widgets.Event;
33import org.eclipse.swt.widgets.Listener;
e894a508 34import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
2bdf0193
AM
35import org.eclipse.tracecompass.tmf.core.component.TmfComponent;
36import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
37import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
38import org.eclipse.tracecompass.tmf.core.signal.TmfTimeSynchSignal;
39import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
40import org.eclipse.tracecompass.tmf.core.statistics.ITmfStatistics;
41import org.eclipse.tracecompass.tmf.core.statistics.TmfStatisticsEventTypesModule;
42import org.eclipse.tracecompass.tmf.core.statistics.TmfStatisticsModule;
43import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
44import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
45import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
46import org.eclipse.tracecompass.tmf.core.trace.TmfExperiment;
47import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
48import org.eclipse.tracecompass.tmf.ui.TmfUiRefreshHandler;
49import org.eclipse.tracecompass.tmf.ui.viewers.TmfViewer;
50import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfBaseColumnData;
51import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfBaseColumnDataProvider;
52import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfStatisticsFormatter;
53import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfStatisticsTree;
54import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfStatisticsTreeManager;
55import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfStatisticsTreeNode;
56import org.eclipse.tracecompass.tmf.ui.viewers.statistics.model.TmfTreeContentProvider;
cfd22ad0
MD
57
58/**
59 * A basic viewer to display statistics in the statistics view.
60 *
8b60cb37
MD
61 * It is linked to a single ITmfTrace until its disposal.
62 *
cfd22ad0 63 * @author Mathieu Denis
cfd22ad0
MD
64 * @since 2.0
65 */
05627bda 66public class TmfStatisticsViewer extends TmfViewer {
cfd22ad0 67
87f83123
AM
68 /** Timestamp scale used for all statistics (nanosecond) */
69 private static final byte TIME_SCALE = ITmfTimestamp.NANOSECOND_SCALE;
05627bda 70
aae89862
PT
71 /** The delay (in ms) between each update in live-reading mode */
72 private static final long LIVE_UPDATE_DELAY = 1000;
73
87f83123
AM
74 /** The actual tree viewer to display */
75 private TreeViewer fTreeViewer;
05627bda 76
87f83123
AM
77 /** The statistics tree linked to this viewer */
78 private TmfStatisticsTree fStatisticsData;
3c934968 79
87f83123
AM
80 /** Update range synchronization object */
81 private final Object fStatisticsRangeUpdateSyncObj = new Object();
73fbf6be 82
87f83123
AM
83 /** The trace that is displayed by this viewer */
84 private ITmfTrace fTrace;
89c06060 85
87f83123 86 /** Indicates to process all events */
05627bda
MD
87 private boolean fProcessAll;
88
87f83123 89 /** View instance counter (for multiple statistics views) */
cfd22ad0
MD
90 private static int fCountInstance = 0;
91
87f83123 92 /** Number of this instance. Used as an instance ID. */
cfd22ad0
MD
93 private int fInstanceNb;
94
87f83123 95 /** Object to store the cursor while waiting for the trace to load */
cfd22ad0
MD
96 private Cursor fWaitCursor = null;
97
98 /**
05627bda
MD
99 * Counts the number of times waitCursor() has been called. It avoids
100 * removing the waiting cursor, since there may be multiple requests running
101 * at the same time.
102 */
103 private int fWaitCursorCount = 0;
104
87f83123 105 /** Tells to send a time range request when the trace gets updated. */
05627bda
MD
106 private boolean fSendRangeRequest = true;
107
f0c0d2c2
AM
108 /** Reference to the trace manager */
109 private final TmfTraceManager fTraceManager;
110
05627bda
MD
111 /**
112 * Create a basic statistics viewer. To be used in conjunction with
113 * {@link TmfStatisticsViewer#init(Composite, String, ITmfTrace)}
114 *
115 * @param parent
116 * The parent composite that will hold the viewer
117 * @param viewerName
118 * The name that will be assigned to this viewer
119 * @param trace
120 * The trace that is displayed by this viewer
121 * @see TmfComponent
122 */
123 public TmfStatisticsViewer(Composite parent, String viewerName, ITmfTrace trace) {
124 init(parent, viewerName, trace);
f0c0d2c2 125 fTraceManager = TmfTraceManager.getInstance();
05627bda
MD
126 }
127
128 /**
129 * Initialize the statistics viewer.
cfd22ad0
MD
130 *
131 * @param parent
05627bda
MD
132 * The parent component of the viewer.
133 * @param viewerName
134 * The name to give to the viewer.
135 * @param trace
136 * The trace that will be displayed by the viewer.
cfd22ad0 137 */
05627bda
MD
138 public void init(Composite parent, String viewerName, ITmfTrace trace) {
139 super.init(parent, viewerName);
cfd22ad0
MD
140 // Increment a counter to make sure the tree ID is unique.
141 fCountInstance++;
142 fInstanceNb = fCountInstance;
05627bda
MD
143 fTrace = trace;
144
faa38350 145 // The viewer will process all events if he is assigned to an experiment
05627bda
MD
146 fProcessAll = (trace instanceof TmfExperiment);
147
148 initContent(parent);
8b60cb37 149 initInput();
05627bda
MD
150 }
151
05627bda
MD
152 @Override
153 public void dispose() {
154 super.dispose();
155 if (fWaitCursor != null) {
156 fWaitCursor.dispose();
157 }
8b60cb37 158
66792052 159 // Clean the model for this viewer
36033ff0 160 TmfStatisticsTreeManager.removeStatTreeRoot(getTreeID());
05627bda
MD
161 }
162
1c0de632
AM
163 // ------------------------------------------------------------------------
164 // Signal handlers
165 // ------------------------------------------------------------------------
89c06060 166
05627bda 167 /**
faa38350 168 * Handles the signal about new trace range.
05627bda
MD
169 *
170 * @param signal
faa38350 171 * The trace range updated signal
05627bda
MD
172 */
173 @TmfSignalHandler
faa38350
PT
174 public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal) {
175 ITmfTrace trace = signal.getTrace();
05627bda 176 // validate
faa38350 177 if (!isListeningTo(trace)) {
05627bda
MD
178 return;
179 }
180
3c934968
MD
181 synchronized (fStatisticsRangeUpdateSyncObj) {
182 // Sends the time range request only once from this method.
183 if (fSendRangeRequest) {
184 fSendRangeRequest = false;
0fcf3b09
PT
185 ITmfTimestamp begin = fTraceManager.getSelectionBeginTime();
186 ITmfTimestamp end = fTraceManager.getSelectionEndTime();
187 TmfTimeRange timeRange = new TmfTimeRange(begin, end);
188 requestTimeRangeData(trace, timeRange);
3c934968 189 }
05627bda 190 }
faa38350 191 requestData(trace, signal.getRange());
05627bda
MD
192 }
193
0fcf3b09
PT
194 /**
195 * Handles the time synch updated signal. It updates the time range
196 * statistics.
197 *
198 * @param signal
199 * Contains the information about the new selected time range.
4b121c48 200 * @since 2.1
0fcf3b09
PT
201 */
202 @TmfSignalHandler
203 public void timeSynchUpdated(TmfTimeSynchSignal signal) {
faa38350
PT
204 if (fTrace == null) {
205 return;
206 }
0fcf3b09
PT
207 ITmfTimestamp begin = signal.getBeginTime();
208 ITmfTimestamp end = signal.getEndTime();
209 TmfTimeRange timeRange = new TmfTimeRange(begin, end);
210 requestTimeRangeData(fTrace, timeRange);
05627bda
MD
211 }
212
1c0de632
AM
213 // ------------------------------------------------------------------------
214 // Class methods
215 // ------------------------------------------------------------------------
216
05627bda
MD
217 /*
218 * Returns the primary control associated with this viewer.
219 *
220 * @return the SWT control which displays this viewer's content
221 */
222 @Override
223 public Control getControl() {
224 return fTreeViewer.getControl();
225 }
226
227 /**
228 * Get the input of the viewer.
229 *
230 * @return an object representing the input of the statistics viewer.
231 */
232 public Object getInput() {
233 return fTreeViewer.getInput();
234 }
235
05627bda
MD
236 /**
237 * This method can be overridden to implement another way of representing
238 * the statistics data and to retrieve the information for display.
239 *
240 * @return a TmfStatisticsData object.
241 */
36033ff0 242 public TmfStatisticsTree getStatisticData() {
05627bda 243 if (fStatisticsData == null) {
36033ff0 244 fStatisticsData = new TmfStatisticsTree();
05627bda
MD
245 }
246 return fStatisticsData;
247 }
248
249 /**
250 * Returns a unique ID based on name to be associated with the statistics
251 * tree for this viewer. For a same name, it will always return the same ID.
252 *
253 * @return a unique statistics tree ID.
254 */
255 public String getTreeID() {
256 return getName() + fInstanceNb;
257 }
258
259 @Override
260 public void refresh() {
261 final Control viewerControl = getControl();
262 // Ignore update if disposed
263 if (viewerControl.isDisposed()) {
264 return;
265 }
266
65fc212e 267 TmfUiRefreshHandler.getInstance().queueUpdate(this, new Runnable() {
05627bda
MD
268 @Override
269 public void run() {
270 if (!viewerControl.isDisposed()) {
271 fTreeViewer.refresh();
272 }
273 }
274 });
275 }
276
3c934968
MD
277 /**
278 * Will force a request on the partial event count if one is needed.
279 */
280 public void sendPartialRequestOnNextUpdate() {
281 synchronized (fStatisticsRangeUpdateSyncObj) {
282 fSendRangeRequest = true;
283 }
284 }
285
05627bda
MD
286 /**
287 * Focus on the statistics tree of the viewer
288 */
289 public void setFocus() {
290 fTreeViewer.getTree().setFocus();
291 }
292
05627bda
MD
293 /**
294 * Cancels the request if it is not already completed
295 *
296 * @param request
297 * The request to be canceled
c4767854 298 * @since 3.0
05627bda 299 */
fd3f1eff 300 protected void cancelOngoingRequest(ITmfEventRequest request) {
05627bda
MD
301 if (request != null && !request.isCompleted()) {
302 request.cancel();
303 }
304 }
305
306 /**
307 * This method can be overridden to change the representation of the data in
308 * the columns.
309 *
b3a26928
AM
310 * @return An object of type {@link TmfBaseColumnDataProvider}.
311 * @since 3.0
05627bda 312 */
b3a26928 313 protected TmfBaseColumnDataProvider getColumnDataProvider() {
05627bda
MD
314 return new TmfBaseColumnDataProvider();
315 }
cfd22ad0 316
05627bda
MD
317 /**
318 * Initialize the content that will be drawn in this viewer
319 *
320 * @param parent
321 * The parent of the control to create
322 */
323 protected void initContent(Composite parent) {
cfd22ad0 324 final List<TmfBaseColumnData> columnDataList = getColumnDataProvider().getColumnData();
cfd22ad0
MD
325
326 fTreeViewer = new TreeViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
327 fTreeViewer.setContentProvider(new TmfTreeContentProvider());
328 fTreeViewer.getTree().setHeaderVisible(true);
329 fTreeViewer.setUseHashlookup(true);
330
331 // Creates the columns defined by the column data provider
332 for (final TmfBaseColumnData columnData : columnDataList) {
333 final TreeViewerColumn treeColumn = new TreeViewerColumn(fTreeViewer, columnData.getAlignment());
334 treeColumn.getColumn().setText(columnData.getHeader());
335 treeColumn.getColumn().setWidth(columnData.getWidth());
336 treeColumn.getColumn().setToolTipText(columnData.getTooltip());
337
df2b3dbb
VP
338 // If is dummy column
339 if (columnData == columnDataList.get(TmfBaseColumnDataProvider.StatsColumn.DUMMY.getIndex())) {
340 treeColumn.getColumn().setResizable(false);
341 }
342
343 // A comparator is defined.
344 if (columnData.getComparator() != null) {
cfd22ad0
MD
345 // Adds a listener on the columns header for sorting purpose.
346 treeColumn.getColumn().addSelectionListener(new SelectionAdapter() {
347
348 private ViewerComparator reverseComparator;
349
350 @Override
351 public void widgetSelected(SelectionEvent e) {
352 // Initializes the reverse comparator once.
353 if (reverseComparator == null) {
354 reverseComparator = new ViewerComparator() {
355 @Override
356 public int compare(Viewer viewer, Object e1, Object e2) {
357 return -1 * columnData.getComparator().compare(viewer, e1, e2);
358 }
359 };
360 }
361
362 if (fTreeViewer.getTree().getSortDirection() == SWT.UP
363 || fTreeViewer.getTree().getSortColumn() != treeColumn.getColumn()) {
364 /*
df2b3dbb
VP
365 * Puts the descendant order if the old order was up
366 * or if the selected column has changed.
cfd22ad0
MD
367 */
368 fTreeViewer.setComparator(columnData.getComparator());
369 fTreeViewer.getTree().setSortDirection(SWT.DOWN);
370 } else {
371 /*
372 * Puts the ascendant ordering if the selected
373 * column hasn't changed.
374 */
375 fTreeViewer.setComparator(reverseComparator);
376 fTreeViewer.getTree().setSortDirection(SWT.UP);
377 }
378 fTreeViewer.getTree().setSortColumn(treeColumn.getColumn());
379 }
380 });
381 }
382 treeColumn.setLabelProvider(columnData.getLabelProvider());
383 }
384
df2b3dbb 385 // Handler that will draw the percentages and the bar charts.
cfd22ad0
MD
386 fTreeViewer.getTree().addListener(SWT.EraseItem, new Listener() {
387 @Override
388 public void handleEvent(Event event) {
389 if (columnDataList.get(event.index).getPercentageProvider() != null) {
df2b3dbb 390
cfd22ad0
MD
391 TmfStatisticsTreeNode node = (TmfStatisticsTreeNode) event.item.getData();
392
df2b3dbb
VP
393 // If node is hidden, exit immediately.
394 if (TmfBaseColumnDataProvider.HIDDEN_FOLDER_LEVELS.contains(node.getName())) {
cfd22ad0
MD
395 return;
396 }
397
df2b3dbb
VP
398 // Otherwise, get percentage and draw bar and text if applicable.
399 double percentage = columnDataList.get(event.index).getPercentageProvider().getPercentage(node);
400
401 // The item is selected.
402 if ((event.detail & SWT.SELECTED) > 0) {
403 // Draws our own background to avoid overwriting the bar.
cfd22ad0
MD
404 event.gc.fillRectangle(event.x, event.y, event.width, event.height);
405 event.detail &= ~SWT.SELECTED;
406 }
407
df2b3dbb
VP
408 // Drawing the percentage text
409 // if events are present in top node
410 // and the current node is not the top node
411 // and if is total or partial events column.
412 // If not, exit the method.
413 if (!((event.index == TmfBaseColumnDataProvider.StatsColumn.TOTAL.getIndex() || event.index == TmfBaseColumnDataProvider.StatsColumn.PARTIAL.getIndex())
414 && node != node.getTop())) {
415 return;
416 }
417
418 long eventValue = event.index == TmfBaseColumnDataProvider.StatsColumn.TOTAL.getIndex() ?
419 node.getTop().getValues().getTotal() : node.getTop().getValues().getPartial();
420
421 if (eventValue != 0) {
422
423 int oldAlpha = event.gc.getAlpha();
424 Color oldForeground = event.gc.getForeground();
425 Color oldBackground = event.gc.getBackground();
426
427 // Bar to draw
428 if (percentage != 0) {
429 /*
430 * Draws a transparent gradient rectangle from the
431 * color of foreground and background.
432 */
433 int barWidth = (int) ((fTreeViewer.getTree().getColumn(event.index).getWidth() - 8) * percentage);
434 event.gc.setAlpha(64);
435 event.gc.setForeground(event.item.getDisplay().getSystemColor(SWT.COLOR_BLUE));
436 event.gc.setBackground(event.item.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
437 event.gc.fillGradientRectangle(event.x, event.y, barWidth, event.height, true);
438 event.gc.drawRectangle(event.x, event.y, barWidth, event.height);
439
440 // Restore old values
441 event.gc.setBackground(oldBackground);
442 event.gc.setAlpha(oldAlpha);
443 event.detail &= ~SWT.BACKGROUND;
444
445 }
446
447 String percentageText = TmfStatisticsFormatter.toPercentageText(percentage);
448 String absoluteNumberText = TmfStatisticsFormatter.toColumnData(node, TmfBaseColumnDataProvider.StatsColumn.getColumn(event.index));
449
450 if (event.width > event.gc.stringExtent(percentageText).x + event.gc.stringExtent(absoluteNumberText).x) {
451 int textHeight = event.gc.stringExtent(percentageText).y;
452 event.gc.setForeground(event.item.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
453 event.gc.drawText(percentageText, event.x, event.y + (event.height - textHeight) / 2, true);
454 }
455
456 // Restores old values
457 event.gc.setForeground(oldForeground);
458
459 }
cfd22ad0
MD
460 }
461 }
df2b3dbb 462
cfd22ad0
MD
463 });
464
465 // Initializes the comparator parameters
466 fTreeViewer.setComparator(columnDataList.get(0).getComparator());
467 fTreeViewer.getTree().setSortColumn(fTreeViewer.getTree().getColumn(0));
468 fTreeViewer.getTree().setSortDirection(SWT.DOWN);
469 }
470
8b60cb37
MD
471 /**
472 * Initializes the input for the tree viewer.
8b60cb37
MD
473 */
474 protected void initInput() {
475 String treeID = getTreeID();
faa38350 476 TmfStatisticsTreeNode statisticsTreeNode;
36033ff0 477 if (TmfStatisticsTreeManager.containsTreeRoot(treeID)) {
faa38350
PT
478 // The statistics root is already present
479 statisticsTreeNode = TmfStatisticsTreeManager.getStatTreeRoot(treeID);
8b60cb37
MD
480
481 // Checks if the trace is already in the statistics tree.
faa38350 482 int numNodeTraces = statisticsTreeNode.getNbChildren();
8b60cb37 483
b9a5bf8f 484 ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
fe0c44c4 485 int numTraces = traces.length;
8b60cb37
MD
486
487 if (numTraces == numNodeTraces) {
488 boolean same = true;
489 /*
490 * Checks if the experiment contains the same traces as when
491 * previously selected.
492 */
493 for (int i = 0; i < numTraces; i++) {
fe0c44c4 494 String traceName = traces[i].getName();
faa38350 495 if (!statisticsTreeNode.containsChild(traceName)) {
8b60cb37
MD
496 same = false;
497 break;
498 }
499 }
500
501 if (same) {
502 // No need to reload data, all traces are already loaded
faa38350 503 fTreeViewer.setInput(statisticsTreeNode);
8b60cb37
MD
504 return;
505 }
506 // Clears the old content to start over
faa38350 507 statisticsTreeNode.reset();
8b60cb37
MD
508 }
509 } else {
510 // Creates a new tree
faa38350 511 statisticsTreeNode = TmfStatisticsTreeManager.addStatsTreeRoot(treeID, getStatisticData());
8b60cb37
MD
512 }
513
514 // Sets the input to a clean data model
faa38350 515 fTreeViewer.setInput(statisticsTreeNode);
8b60cb37
MD
516 }
517
cfd22ad0 518 /**
faa38350 519 * Tells if the viewer is listening to a trace.
cfd22ad0 520 *
1c0de632 521 * @param trace
05627bda
MD
522 * The trace that the viewer may be listening
523 * @return true if the viewer is listening to the trace, false otherwise
cfd22ad0 524 */
1c0de632
AM
525 protected boolean isListeningTo(ITmfTrace trace) {
526 if (fProcessAll || trace == fTrace) {
05627bda 527 return true;
cfd22ad0 528 }
05627bda 529 return false;
cfd22ad0
MD
530 }
531
532 /**
faa38350 533 * Called when an trace request has been completed successfully.
cfd22ad0 534 *
05627bda
MD
535 * @param global
536 * Tells if the request is a global or time range (partial)
537 * request.
cfd22ad0 538 */
05627bda
MD
539 protected void modelComplete(boolean global) {
540 refresh();
541 waitCursor(false);
cfd22ad0
MD
542 }
543
544 /**
faa38350 545 * Called when an trace request has failed or has been cancelled.
cfd22ad0 546 *
05627bda
MD
547 * @param isGlobalRequest
548 * Tells if the request is a global or time range (partial)
549 * request.
cfd22ad0 550 */
05627bda 551 protected void modelIncomplete(boolean isGlobalRequest) {
df2b3dbb 552 if (isGlobalRequest) { // Clean the global statistics
05627bda 553 /*
763f4972
MD
554 * No need to reset the global number of events, since the index of
555 * the last requested event is known.
05627bda 556 */
df2b3dbb 557 } else { // Clean the partial statistics
05627bda
MD
558 resetTimeRangeValue();
559 }
560 refresh();
561 waitCursor(false);
cfd22ad0
MD
562 }
563
564 /**
faa38350 565 * Sends the request to the trace for the whole trace
cfd22ad0 566 *
faa38350
PT
567 * @param trace
568 * The trace used to send the request
8b260d9f 569 * @param timeRange
faa38350 570 * The range to request to the trace
cfd22ad0 571 */
faa38350
PT
572 protected void requestData(final ITmfTrace trace, final TmfTimeRange timeRange) {
573 buildStatisticsTree(trace, timeRange, true);
cfd22ad0
MD
574 }
575
576 /**
faa38350 577 * Sends the time range request from the trace
cfd22ad0 578 *
faa38350
PT
579 * @param trace
580 * The trace used to send the request
8b260d9f 581 * @param timeRange
faa38350 582 * The range to request to the trace
cfd22ad0 583 */
faa38350 584 protected void requestTimeRangeData(final ITmfTrace trace, final TmfTimeRange timeRange) {
faa38350 585 buildStatisticsTree(trace, timeRange, false);
89c06060
AM
586 }
587
588 /**
df2b3dbb
VP
589 * Requests all the data of the trace to the state system which contains
590 * information about the statistics.
89c06060 591 *
df2b3dbb
VP
592 * Since the viewer may be listening to multiple traces, it may receive an
593 * experiment rather than a single trace. The filtering is done with the
89c06060
AM
594 * method {@link #isListeningTo(String trace)}.
595 *
faa38350
PT
596 * @param trace
597 * The trace for which a request must be done
89c06060
AM
598 * @param timeRange
599 * The time range that will be requested to the state system
600 * @param isGlobal
601 * Tells if the request is for the global event count or the
602 * partial one.
603 */
d6b46913 604 private void buildStatisticsTree(final ITmfTrace trace, final TmfTimeRange timeRange, final boolean isGlobal) {
36033ff0
AM
605 final TmfStatisticsTreeNode statTree = TmfStatisticsTreeManager.getStatTreeRoot(getTreeID());
606 final TmfStatisticsTree statsData = TmfStatisticsTreeManager.getStatTree(getTreeID());
89c06060
AM
607 if (statsData == null) {
608 return;
609 }
610
611 synchronized (statsData) {
612 if (isGlobal) {
613 statTree.resetGlobalValue();
614 } else {
615 statTree.resetTimeRangeValue();
616 }
617
b9a5bf8f 618 for (final ITmfTrace aTrace : TmfTraceManager.getTraceSet(trace)) {
faa38350 619 if (!isListeningTo(aTrace)) {
89c06060
AM
620 continue;
621 }
622
8192f2c6
AM
623 /* Retrieve the statistics object */
624 final TmfStatisticsModule statsMod = aTrace.getAnalysisModuleOfClass(TmfStatisticsModule.class, TmfStatisticsModule.ID);
625 if (statsMod == null) {
626 /* No statistics module available for this trace */
627 continue;
628 }
89c06060 629
d6b46913
AM
630 /* Run the potentially long queries in a separate thread */
631 Thread statsThread = new Thread("Statistics update") { //$NON-NLS-1$
632 @Override
633 public void run() {
55954069
AM
634 /* Wait until the analysis is ready to be queried */
635 statsMod.waitForInitialization();
d6b46913
AM
636 ITmfStatistics stats = statsMod.getStatistics();
637 if (stats == null) {
638 /* It should have worked, but didn't */
55954069 639 throw new IllegalStateException();
d6b46913
AM
640 }
641
642 /*
643 * The generic statistics are stored in nanoseconds, so
644 * we must make sure the time range is scaled correctly.
645 */
646 long start = timeRange.getStartTime().normalize(0, TIME_SCALE).getValue();
647 long end = timeRange.getEndTime().normalize(0, TIME_SCALE).getValue();
648
55954069
AM
649 /*
650 * Wait on the state system object we are going to query.
651 *
652 * TODO Eventually this could be exposed through the
653 * TmfStateSystemAnalysisModule directly.
654 */
655 ITmfStateSystem ss = statsMod.getStateSystem(TmfStatisticsEventTypesModule.ID);
656 if (ss == null) {
df2b3dbb
VP
657 /*
658 * It should be instantiated after the
659 * statsMod.waitForInitialization() above.
660 */
55954069
AM
661 throw new IllegalStateException();
662 }
663
664 /*
665 * Periodically update the statistics while they are
df2b3dbb
VP
666 * being built (or, if the back-end is already
667 * completely built, it will skip over the while() immediately.
55954069 668 */
aae89862 669 while (!ss.waitUntilBuilt(LIVE_UPDATE_DELAY)) {
55954069 670 Map<String, Long> map = stats.getEventTypesInRange(start, end);
d97964e3 671 updateStats(aTrace, isGlobal, map);
55954069
AM
672 }
673 /* Query one last time for the final values */
d6b46913 674 Map<String, Long> map = stats.getEventTypesInRange(start, end);
d97964e3 675 updateStats(aTrace, isGlobal, map);
d6b46913
AM
676 }
677 };
678 statsThread.start();
89c06060 679 }
89c06060 680 }
cfd22ad0
MD
681 }
682
d97964e3
BH
683 /*
684 * Update statistics for a given trace
d6b46913 685 */
d97964e3 686 private void updateStats(ITmfTrace trace, boolean isGlobal, Map<String, Long> eventsPerType) {
d6b46913
AM
687
688 final TmfStatisticsTree statsData = TmfStatisticsTreeManager.getStatTree(getTreeID());
55954069 689 if (statsData == null) {
df2b3dbb 690 /* The stat tree has been disposed, abort mission. */
55954069
AM
691 return;
692 }
693
d6b46913 694 Map<String, Long> map = eventsPerType;
d97964e3 695 String name = trace.getName();
d6b46913 696
df2b3dbb 697
d6b46913
AM
698 /*
699 * "Global", "partial", "total", etc., it's all very confusing...
700 *
701 * The base view shows the total count for the trace and for
702 * each even types, organized in columns like this:
703 *
704 * | Global | Time range |
705 * trace name | A | B |
706 * Event Type | | |
707 * <event 1> | C | D |
708 * <event 2> | ... | ... |
709 * ... | | |
710 *
711 * Here, we called the cells like this:
712 * A : GlobalTotal
713 * B : TimeRangeTotal
714 * C : GlobalTypeCount(s)
715 * D : TimeRangeTypeCount(s)
716 */
717
718 /* Fill in an the event counts (either cells C or D) */
719 for (Map.Entry<String, Long> entry : map.entrySet()) {
720 statsData.setTypeCount(name, entry.getKey(), isGlobal, entry.getValue());
721 }
722
723 /*
724 * Calculate the totals (cell A or B, depending if isGlobal). We will
725 * use the results of the previous request instead of sending another
726 * one.
727 */
728 long globalTotal = 0;
729 for (long val : map.values()) {
730 globalTotal += val;
731 }
732 statsData.setTotal(name, isGlobal, globalTotal);
733
734 modelComplete(isGlobal);
735 }
736
cfd22ad0 737 /**
05627bda 738 * Resets the number of events within the time range
cfd22ad0 739 */
05627bda 740 protected void resetTimeRangeValue() {
36033ff0 741 TmfStatisticsTreeNode treeModelRoot = TmfStatisticsTreeManager.getStatTreeRoot(getTreeID());
05627bda
MD
742 if (treeModelRoot != null && treeModelRoot.hasChildren()) {
743 treeModelRoot.resetTimeRangeValue();
744 }
cfd22ad0
MD
745 }
746
747 /**
df2b3dbb
VP
748 * When the trace is loading the cursor will be different so the user knows
749 * that the processing is not finished yet.
05627bda
MD
750 *
751 * Calls to this method are stacked.
cfd22ad0 752 *
05627bda 753 * @param waitRequested
cfd22ad0 754 * Indicates if we need to show the waiting cursor, or the
05627bda 755 * default one.
cfd22ad0 756 */
05627bda 757 protected void waitCursor(final boolean waitRequested) {
cfd22ad0
MD
758 if ((fTreeViewer == null) || (fTreeViewer.getTree().isDisposed())) {
759 return;
760 }
761
05627bda 762 boolean needsUpdate = false;
cfd22ad0 763 Display display = fTreeViewer.getControl().getDisplay();
05627bda
MD
764 if (waitRequested) {
765 fWaitCursorCount++;
766 if (fWaitCursor == null) { // The cursor hasn't been initialized yet
767 fWaitCursor = new Cursor(display, SWT.CURSOR_WAIT);
768 }
769 if (fWaitCursorCount == 1) { // The cursor is not in waiting mode
770 needsUpdate = true;
771 }
772 } else {
773 if (fWaitCursorCount > 0) { // The cursor is in waiting mode
774 fWaitCursorCount--;
775 if (fWaitCursorCount == 0) { // No more reason to wait
776 // Put back the default cursor
777 needsUpdate = true;
778 }
779 }
cfd22ad0
MD
780 }
781
05627bda
MD
782 if (needsUpdate) {
783 // Performs the updates on the UI thread
784 display.asyncExec(new Runnable() {
785 @Override
786 public void run() {
787 if ((fTreeViewer != null)
788 && (!fTreeViewer.getTree().isDisposed())) {
789 Cursor cursor = null; // indicates default
790 if (waitRequested) {
791 cursor = fWaitCursor;
792 }
793 fTreeViewer.getControl().setCursor(cursor);
cfd22ad0 794 }
cfd22ad0 795 }
05627bda
MD
796 });
797 }
cfd22ad0 798 }
cfd22ad0 799}
This page took 0.092095 seconds and 5 git commands to generate.