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