1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Mathieu Denis <mathieu.denis@polymtl.ca> - Initial API and implementation
11 * Alexandre Montplaisir - Port to ITmfStatistics provider
12 * Patrick Tasse - Support selection range
13 *******************************************************************************/
15 package org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.statistics
;
17 import java
.util
.List
;
20 import org
.eclipse
.jface
.viewers
.TreeViewer
;
21 import org
.eclipse
.jface
.viewers
.TreeViewerColumn
;
22 import org
.eclipse
.jface
.viewers
.Viewer
;
23 import org
.eclipse
.jface
.viewers
.ViewerComparator
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.component
.TmfComponent
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfEventRequest
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfStatsUpdatedSignal
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceRangeUpdatedSignal
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.statistics
.ITmfStatistics
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfExperiment
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfTraceManager
;
37 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.TmfViewer
;
38 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.statistics
.model
.ITmfColumnDataProvider
;
39 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.statistics
.model
.TmfBaseColumnData
;
40 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.statistics
.model
.TmfBaseColumnDataProvider
;
41 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.statistics
.model
.TmfStatisticsTree
;
42 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.statistics
.model
.TmfStatisticsTreeManager
;
43 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.statistics
.model
.TmfStatisticsTreeNode
;
44 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.statistics
.model
.TmfTreeContentProvider
;
45 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.statistics
.TmfStatisticsModule
;
46 import org
.eclipse
.swt
.SWT
;
47 import org
.eclipse
.swt
.events
.SelectionAdapter
;
48 import org
.eclipse
.swt
.events
.SelectionEvent
;
49 import org
.eclipse
.swt
.graphics
.Color
;
50 import org
.eclipse
.swt
.graphics
.Cursor
;
51 import org
.eclipse
.swt
.widgets
.Composite
;
52 import org
.eclipse
.swt
.widgets
.Control
;
53 import org
.eclipse
.swt
.widgets
.Display
;
54 import org
.eclipse
.swt
.widgets
.Event
;
55 import org
.eclipse
.swt
.widgets
.Listener
;
58 * A basic viewer to display statistics in the statistics view.
60 * It is linked to a single ITmfTrace until its disposal.
62 * @author Mathieu Denis
66 public class TmfStatisticsViewer
extends TmfViewer
{
69 * Timestamp scale (nanosecond)
71 public static final byte TIME_SCALE
= ITmfTimestamp
.NANOSECOND_SCALE
;
74 * Default PAGE_SIZE for background requests.
76 protected static final int PAGE_SIZE
= 50000;
81 protected final Long STATS_INPUT_CHANGED_REFRESH
= 5000L;
84 * The actual tree viewer to display
86 protected TreeViewer fTreeViewer
;
89 * The statistics tree linked to this viewer
91 protected TmfStatisticsTree fStatisticsData
;
94 * Update synchronization parameter (used for streaming): Update busy
97 protected boolean fStatisticsUpdateBusy
= false;
100 * Update synchronization parameter (used for streaming): Update pending
103 protected boolean fStatisticsUpdatePending
= false;
106 * Update synchronization parameter (used for streaming): Pending Update
109 protected TmfTimeRange fStatisticsUpdateRange
= null;
112 * Update synchronization object.
114 protected final Object fStatisticsUpdateSyncObj
= new Object();
117 * Update range synchronization object.
119 protected final Object fStatisticsRangeUpdateSyncObj
= new Object();
122 * The trace that is displayed by this viewer
124 protected ITmfTrace fTrace
;
127 * Stores the requested time range.
129 protected TmfTimeRange fRequestedTimerange
;
132 * Indicates to process all events
134 private boolean fProcessAll
;
137 * View instance counter (for multiple statistics views)
139 private static int fCountInstance
= 0;
142 * Number of this instance. Used as an instance ID.
144 private int fInstanceNb
;
147 * Object to store the cursor while waiting for the trace to load
149 private Cursor fWaitCursor
= null;
152 * Counts the number of times waitCursor() has been called. It avoids
153 * removing the waiting cursor, since there may be multiple requests running
156 private int fWaitCursorCount
= 0;
159 * Tells to send a time range request when the trace gets updated.
161 private boolean fSendRangeRequest
= true;
163 /** Reference to the trace manager */
164 private final TmfTraceManager fTraceManager
;
167 * Empty constructor. To be used in conjunction with
168 * {@link TmfStatisticsViewer#init(Composite, String, ITmfTrace)}
170 public TmfStatisticsViewer() {
172 fTraceManager
= TmfTraceManager
.getInstance();
176 * Create a basic statistics viewer. To be used in conjunction with
177 * {@link TmfStatisticsViewer#init(Composite, String, ITmfTrace)}
180 * The parent composite that will hold the viewer
182 * The name that will be assigned to this viewer
184 * The trace that is displayed by this viewer
187 public TmfStatisticsViewer(Composite parent
, String viewerName
, ITmfTrace trace
) {
188 init(parent
, viewerName
, trace
);
189 fTraceManager
= TmfTraceManager
.getInstance();
193 * Initialize the statistics viewer.
196 * The parent component of the viewer.
198 * The name to give to the viewer.
200 * The trace that will be displayed by the viewer.
202 public void init(Composite parent
, String viewerName
, ITmfTrace trace
) {
203 super.init(parent
, viewerName
);
204 // Increment a counter to make sure the tree ID is unique.
206 fInstanceNb
= fCountInstance
;
209 // The viewer will process all events if he is assigned to an experiment
210 fProcessAll
= (trace
instanceof TmfExperiment
);
217 public void dispose() {
219 if (fWaitCursor
!= null) {
220 fWaitCursor
.dispose();
223 // Clean the model for this viewer
224 TmfStatisticsTreeManager
.removeStatTreeRoot(getTreeID());
227 // ------------------------------------------------------------------------
229 // ------------------------------------------------------------------------
232 * Handles the signal about new trace range.
235 * The trace range updated signal
238 public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal
) {
239 ITmfTrace trace
= signal
.getTrace();
241 if (!isListeningTo(trace
)) {
245 synchronized (fStatisticsRangeUpdateSyncObj
) {
246 // Sends the time range request only once from this method.
247 if (fSendRangeRequest
) {
248 fSendRangeRequest
= false;
249 ITmfTimestamp begin
= fTraceManager
.getSelectionBeginTime();
250 ITmfTimestamp end
= fTraceManager
.getSelectionEndTime();
251 TmfTimeRange timeRange
= new TmfTimeRange(begin
, end
);
252 requestTimeRangeData(trace
, timeRange
);
255 requestData(trace
, signal
.getRange());
259 * Handles the time range updated signal. It updates the time range
263 * Contains the information about the new selected time range.
265 * As of 2.1, use {@link #timeSynchUpdated(TmfTimeSynchSignal)}
269 public void timeRangeUpdated(TmfRangeSynchSignal signal
) {
273 * Handles the time synch updated signal. It updates the time range
277 * Contains the information about the new selected time range.
281 public void timeSynchUpdated(TmfTimeSynchSignal signal
) {
282 if (fTrace
== null) {
285 ITmfTimestamp begin
= signal
.getBeginTime();
286 ITmfTimestamp end
= signal
.getEndTime();
287 TmfTimeRange timeRange
= new TmfTimeRange(begin
, end
);
288 requestTimeRangeData(fTrace
, timeRange
);
292 * Whenever a trace's statistics back-end finishes computing the statistics
293 * for a given interval, it will send the StatsUpdated signal. This method
294 * will receive this signal and update the statistics view accordingly.
297 * The signal that is received
300 public void statsUpdated(TmfStatsUpdatedSignal sig
) {
301 /* Only handle this signal if it's about the trace we represent. */
302 if (!isListeningTo(sig
.getTrace())) {
306 final TmfStatisticsTree statsData
= TmfStatisticsTreeManager
.getStatTree(getTreeID());
307 Map
<String
, Long
> map
= sig
.getEventsPerType();
308 String name
= sig
.getTrace().getName();
309 boolean isGlobal
= sig
.isGlobal();
312 * "Global", "partial", "total", etc., it's all very confusing...
314 * The base view shows the total count for the trace and for
315 * each even types, organized in columns like this:
317 * | Global | Time range |
318 * trace name | A | B |
320 * <event 1> | C | D |
321 * <event 2> | ... | ... |
324 * Here, we called the cells like this:
327 * C : GlobalTypeCount(s)
328 * D : TimeRangeTypeCount(s)
331 /* Fill in an the event counts (either cells C or D) */
332 for (Map
.Entry
<String
, Long
> entry
: map
.entrySet()) {
333 statsData
.setTypeCount(name
, entry
.getKey(), isGlobal
, entry
.getValue());
337 * Calculate the totals (cell A or B, depending if isGlobal). We will
338 * use the results of the previous request instead of sending another
341 long globalTotal
= 0;
342 for (long val
: map
.values()) {
345 statsData
.setTotal(name
, isGlobal
, globalTotal
);
347 modelComplete(isGlobal
);
350 // ------------------------------------------------------------------------
352 // ------------------------------------------------------------------------
355 * Returns the primary control associated with this viewer.
357 * @return the SWT control which displays this viewer's content
360 public Control
getControl() {
361 return fTreeViewer
.getControl();
365 * Get the input of the viewer.
367 * @return an object representing the input of the statistics viewer.
369 public Object
getInput() {
370 return fTreeViewer
.getInput();
374 * Return the size of the request when performing background request.
376 * @return the block size for background request.
378 public int getPageSize() {
383 * Return the number of events to receive before a refresh of the viewer is
386 * @return the input refresh rate
388 public long getRefreshRate() {
389 return STATS_INPUT_CHANGED_REFRESH
;
393 * This method can be overridden to implement another way of representing
394 * the statistics data and to retrieve the information for display.
396 * @return a TmfStatisticsData object.
398 public TmfStatisticsTree
getStatisticData() {
399 if (fStatisticsData
== null) {
400 fStatisticsData
= new TmfStatisticsTree();
402 return fStatisticsData
;
406 * Returns a unique ID based on name to be associated with the statistics
407 * tree for this viewer. For a same name, it will always return the same ID.
409 * @return a unique statistics tree ID.
411 public String
getTreeID() {
412 return getName() + fInstanceNb
;
416 public void refresh() {
417 final Control viewerControl
= getControl();
418 // Ignore update if disposed
419 if (viewerControl
.isDisposed()) {
423 viewerControl
.getDisplay().asyncExec(new Runnable() {
426 if (!viewerControl
.isDisposed()) {
427 fTreeViewer
.refresh();
434 * Will force a request on the partial event count if one is needed.
436 public void sendPartialRequestOnNextUpdate() {
437 synchronized (fStatisticsRangeUpdateSyncObj
) {
438 fSendRangeRequest
= true;
443 * Focus on the statistics tree of the viewer
445 public void setFocus() {
446 fTreeViewer
.getTree().setFocus();
450 * Cancels the request if it is not already completed
453 * The request to be canceled
456 protected void cancelOngoingRequest(ITmfEventRequest request
) {
457 if (request
!= null && !request
.isCompleted()) {
463 * This method can be overridden to change the representation of the data in
466 * @return an object implementing ITmfBaseColumnDataProvider.
468 protected ITmfColumnDataProvider
getColumnDataProvider() {
469 return new TmfBaseColumnDataProvider();
473 * Initialize the content that will be drawn in this viewer
476 * The parent of the control to create
478 protected void initContent(Composite parent
) {
479 final List
<TmfBaseColumnData
> columnDataList
= getColumnDataProvider().getColumnData();
481 fTreeViewer
= new TreeViewer(parent
, SWT
.BORDER
| SWT
.H_SCROLL
| SWT
.V_SCROLL
);
482 fTreeViewer
.setContentProvider(new TmfTreeContentProvider());
483 fTreeViewer
.getTree().setHeaderVisible(true);
484 fTreeViewer
.setUseHashlookup(true);
486 // Creates the columns defined by the column data provider
487 for (final TmfBaseColumnData columnData
: columnDataList
) {
488 final TreeViewerColumn treeColumn
= new TreeViewerColumn(fTreeViewer
, columnData
.getAlignment());
489 treeColumn
.getColumn().setText(columnData
.getHeader());
490 treeColumn
.getColumn().setWidth(columnData
.getWidth());
491 treeColumn
.getColumn().setToolTipText(columnData
.getTooltip());
493 if (columnData
.getComparator() != null) { // A comparator is defined.
494 // Adds a listener on the columns header for sorting purpose.
495 treeColumn
.getColumn().addSelectionListener(new SelectionAdapter() {
497 private ViewerComparator reverseComparator
;
500 public void widgetSelected(SelectionEvent e
) {
501 // Initializes the reverse comparator once.
502 if (reverseComparator
== null) {
503 reverseComparator
= new ViewerComparator() {
505 public int compare(Viewer viewer
, Object e1
, Object e2
) {
506 return -1 * columnData
.getComparator().compare(viewer
, e1
, e2
);
511 if (fTreeViewer
.getTree().getSortDirection() == SWT
.UP
512 || fTreeViewer
.getTree().getSortColumn() != treeColumn
.getColumn()) {
514 * Puts the descendant order if the old order was
515 * up or if the selected column has changed.
517 fTreeViewer
.setComparator(columnData
.getComparator());
518 fTreeViewer
.getTree().setSortDirection(SWT
.DOWN
);
521 * Puts the ascendant ordering if the selected
522 * column hasn't changed.
524 fTreeViewer
.setComparator(reverseComparator
);
525 fTreeViewer
.getTree().setSortDirection(SWT
.UP
);
527 fTreeViewer
.getTree().setSortColumn(treeColumn
.getColumn());
531 treeColumn
.setLabelProvider(columnData
.getLabelProvider());
534 // Handler that will draw the bar charts.
535 fTreeViewer
.getTree().addListener(SWT
.EraseItem
, new Listener() {
537 public void handleEvent(Event event
) {
538 if (columnDataList
.get(event
.index
).getPercentageProvider() != null) {
539 TmfStatisticsTreeNode node
= (TmfStatisticsTreeNode
) event
.item
.getData();
541 double percentage
= columnDataList
.get(event
.index
).getPercentageProvider().getPercentage(node
);
542 if (percentage
== 0) { // No bar to draw
546 if ((event
.detail
& SWT
.SELECTED
) > 0) { // The item is selected.
547 // Draws our own background to avoid overwritten the bar.
548 event
.gc
.fillRectangle(event
.x
, event
.y
, event
.width
, event
.height
);
549 event
.detail
&= ~SWT
.SELECTED
;
552 int barWidth
= (int) ((fTreeViewer
.getTree().getColumn(event
.index
).getWidth() - 8) * percentage
);
553 int oldAlpha
= event
.gc
.getAlpha();
554 Color oldForeground
= event
.gc
.getForeground();
555 Color oldBackground
= event
.gc
.getBackground();
557 * Draws a transparent gradient rectangle from the color of
558 * foreground and background.
560 event
.gc
.setAlpha(64);
561 event
.gc
.setForeground(event
.item
.getDisplay().getSystemColor(SWT
.COLOR_BLUE
));
562 event
.gc
.setBackground(event
.item
.getDisplay().getSystemColor(SWT
.COLOR_LIST_BACKGROUND
));
563 event
.gc
.fillGradientRectangle(event
.x
, event
.y
, barWidth
, event
.height
, true);
564 event
.gc
.drawRectangle(event
.x
, event
.y
, barWidth
, event
.height
);
565 // Restores old values
566 event
.gc
.setForeground(oldForeground
);
567 event
.gc
.setBackground(oldBackground
);
568 event
.gc
.setAlpha(oldAlpha
);
569 event
.detail
&= ~SWT
.BACKGROUND
;
574 // Initializes the comparator parameters
575 fTreeViewer
.setComparator(columnDataList
.get(0).getComparator());
576 fTreeViewer
.getTree().setSortColumn(fTreeViewer
.getTree().getColumn(0));
577 fTreeViewer
.getTree().setSortDirection(SWT
.DOWN
);
581 * Initializes the input for the tree viewer.
583 protected void initInput() {
584 String treeID
= getTreeID();
585 TmfStatisticsTreeNode statisticsTreeNode
;
586 if (TmfStatisticsTreeManager
.containsTreeRoot(treeID
)) {
587 // The statistics root is already present
588 statisticsTreeNode
= TmfStatisticsTreeManager
.getStatTreeRoot(treeID
);
590 // Checks if the trace is already in the statistics tree.
591 int numNodeTraces
= statisticsTreeNode
.getNbChildren();
593 ITmfTrace
[] traces
= TmfTraceManager
.getTraceSet(fTrace
);
594 int numTraces
= traces
.length
;
596 if (numTraces
== numNodeTraces
) {
599 * Checks if the experiment contains the same traces as when
600 * previously selected.
602 for (int i
= 0; i
< numTraces
; i
++) {
603 String traceName
= traces
[i
].getName();
604 if (!statisticsTreeNode
.containsChild(traceName
)) {
611 // No need to reload data, all traces are already loaded
612 fTreeViewer
.setInput(statisticsTreeNode
);
615 // Clears the old content to start over
616 statisticsTreeNode
.reset();
619 // Creates a new tree
620 statisticsTreeNode
= TmfStatisticsTreeManager
.addStatsTreeRoot(treeID
, getStatisticData());
623 // Sets the input to a clean data model
624 fTreeViewer
.setInput(statisticsTreeNode
);
625 resetUpdateSynchronization();
629 * Tells if the viewer is listening to a trace.
632 * The trace that the viewer may be listening
633 * @return true if the viewer is listening to the trace, false otherwise
635 protected boolean isListeningTo(ITmfTrace trace
) {
636 if (fProcessAll
|| trace
== fTrace
) {
643 * Called when an trace request has been completed successfully.
646 * Tells if the request is a global or time range (partial)
649 protected void modelComplete(boolean global
) {
658 * Called when an trace request has failed or has been cancelled.
660 * @param isGlobalRequest
661 * Tells if the request is a global or time range (partial)
664 protected void modelIncomplete(boolean isGlobalRequest
) {
665 if (isGlobalRequest
) { // Clean the global statistics
667 * No need to reset the global number of events, since the index of
668 * the last requested event is known.
670 resetUpdateSynchronization();
672 } else { // Clean the partial statistics
673 resetTimeRangeValue();
680 * Sends the request to the trace for the whole trace
683 * The trace used to send the request
685 * The range to request to the trace
687 protected void requestData(final ITmfTrace trace
, final TmfTimeRange timeRange
) {
688 buildStatisticsTree(trace
, timeRange
, true);
692 * Sends the time range request from the trace
695 * The trace used to send the request
697 * The range to request to the trace
699 protected void requestTimeRangeData(final ITmfTrace trace
, final TmfTimeRange timeRange
) {
700 fRequestedTimerange
= timeRange
;
701 buildStatisticsTree(trace
, timeRange
, false);
705 * Requests all the data of the trace to the state system which
706 * contains information about the statistics.
708 * Since the viewer may be listening to multiple traces, it may receive
709 * an experiment rather than a single trace. The filtering is done with the
710 * method {@link #isListeningTo(String trace)}.
713 * The trace for which a request must be done
715 * The time range that will be requested to the state system
717 * Tells if the request is for the global event count or the
720 private void buildStatisticsTree(final ITmfTrace trace
, TmfTimeRange timeRange
, boolean isGlobal
) {
721 final TmfStatisticsTreeNode statTree
= TmfStatisticsTreeManager
.getStatTreeRoot(getTreeID());
722 final TmfStatisticsTree statsData
= TmfStatisticsTreeManager
.getStatTree(getTreeID());
723 if (statsData
== null) {
727 synchronized (statsData
) {
729 statTree
.resetGlobalValue();
731 statTree
.resetTimeRangeValue();
734 for (final ITmfTrace aTrace
: TmfTraceManager
.getTraceSet(trace
)) {
735 if (!isListeningTo(aTrace
)) {
739 /* Retrieve the statistics object */
740 final TmfStatisticsModule statsMod
= aTrace
.getAnalysisModuleOfClass(TmfStatisticsModule
.class, TmfStatisticsModule
.ID
);
741 if (statsMod
== null) {
742 /* No statistics module available for this trace */
745 final ITmfStatistics stats
= statsMod
.getStatistics();
748 * The statistics provider for this trace is not accessible
749 * (yet?). Try the next one.
754 /* The generic statistics are stored in nanoseconds, so we must make
755 * sure the time range is scaled correctly. */
756 long start
= timeRange
.getStartTime().normalize(0, TIME_SCALE
).getValue();
757 long end
= timeRange
.getEndTime().normalize(0, TIME_SCALE
).getValue();
760 * Send a request to update the statistics view. The result will
761 * be sent through a {@link TmfStatsUpdatedSignal}, and will be
762 * processed by the signal handler.
764 stats
.updateStats(isGlobal
, start
, end
);
770 * Resets the number of events within the time range
772 protected void resetTimeRangeValue() {
773 TmfStatisticsTreeNode treeModelRoot
= TmfStatisticsTreeManager
.getStatTreeRoot(getTreeID());
774 if (treeModelRoot
!= null && treeModelRoot
.hasChildren()) {
775 treeModelRoot
.resetTimeRangeValue();
780 * When the trace is loading the cursor will be different so the user
781 * knows that the processing is not finished yet.
783 * Calls to this method are stacked.
785 * @param waitRequested
786 * Indicates if we need to show the waiting cursor, or the
789 protected void waitCursor(final boolean waitRequested
) {
790 if ((fTreeViewer
== null) || (fTreeViewer
.getTree().isDisposed())) {
794 boolean needsUpdate
= false;
795 Display display
= fTreeViewer
.getControl().getDisplay();
798 if (fWaitCursor
== null) { // The cursor hasn't been initialized yet
799 fWaitCursor
= new Cursor(display
, SWT
.CURSOR_WAIT
);
801 if (fWaitCursorCount
== 1) { // The cursor is not in waiting mode
805 if (fWaitCursorCount
> 0) { // The cursor is in waiting mode
807 if (fWaitCursorCount
== 0) { // No more reason to wait
808 // Put back the default cursor
815 // Performs the updates on the UI thread
816 display
.asyncExec(new Runnable() {
819 if ((fTreeViewer
!= null)
820 && (!fTreeViewer
.getTree().isDisposed())) {
821 Cursor cursor
= null; // indicates default
823 cursor
= fWaitCursor
;
825 fTreeViewer
.getControl().setCursor(cursor
);
832 // ------------------------------------------------------------------------
833 // Methods reserved for the streaming functionality
834 // ------------------------------------------------------------------------
837 * Resets update synchronization information
839 protected void resetUpdateSynchronization() {
840 synchronized (fStatisticsUpdateSyncObj
) {
841 fStatisticsUpdateBusy
= false;
842 fStatisticsUpdatePending
= false;
843 fStatisticsUpdateRange
= null;
848 * Checks if statistics update is ongoing. If it is ongoing, the new time
849 * range is stored as pending
853 * @return true if statistic update is ongoing else false
855 protected boolean checkUpdateBusy(TmfTimeRange timeRange
) {
856 synchronized (fStatisticsUpdateSyncObj
) {
857 if (fStatisticsUpdateBusy
) {
858 fStatisticsUpdatePending
= true;
859 if (fStatisticsUpdateRange
== null
860 || timeRange
.getEndTime().compareTo(fStatisticsUpdateRange
.getEndTime()) > 0) {
861 fStatisticsUpdateRange
= timeRange
;
865 fStatisticsUpdateBusy
= true;
871 * Sends pending request (if any)
873 protected void sendPendingUpdate() {
874 synchronized (fStatisticsUpdateSyncObj
) {
875 fStatisticsUpdateBusy
= false;
876 if (fStatisticsUpdatePending
) {
877 fStatisticsUpdatePending
= false;
878 requestData(fTrace
, fStatisticsUpdateRange
);
879 fStatisticsUpdateRange
= null;