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