1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 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 * Alvaro Sanchez-Leon (alvsan09@gmail.com) - Initial API and implementation
11 *******************************************************************************/
12 package org
.eclipse
.linuxtools
.lttng
.ui
.views
.common
;
14 import java
.util
.Arrays
;
16 import org
.eclipse
.linuxtools
.lttng
.control
.LttngCoreProviderFactory
;
17 import org
.eclipse
.linuxtools
.lttng
.control
.LttngSyntheticEventProvider
;
18 import org
.eclipse
.linuxtools
.lttng
.event
.LttngSyntheticEvent
;
19 import org
.eclipse
.linuxtools
.lttng
.event
.LttngSyntheticEvent
.SequenceInd
;
20 import org
.eclipse
.linuxtools
.lttng
.event
.LttngTimestamp
;
21 import org
.eclipse
.linuxtools
.lttng
.request
.ILttngSyntEventRequest
;
22 import org
.eclipse
.linuxtools
.lttng
.request
.IRequestStatusListener
;
23 import org
.eclipse
.linuxtools
.lttng
.request
.LttngSyntEventRequest
;
24 import org
.eclipse
.linuxtools
.lttng
.request
.RequestCompletedSignal
;
25 import org
.eclipse
.linuxtools
.lttng
.request
.RequestStartedSignal
;
26 import org
.eclipse
.linuxtools
.lttng
.state
.evProcessor
.ITransEventProcessor
;
27 import org
.eclipse
.linuxtools
.lttng
.ui
.TraceDebug
;
28 import org
.eclipse
.linuxtools
.lttng
.ui
.model
.trange
.ItemContainer
;
29 import org
.eclipse
.linuxtools
.lttng
.ui
.views
.resources
.model
.ResourceModelFactory
;
30 import org
.eclipse
.linuxtools
.tmf
.event
.TmfEvent
;
31 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
32 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
33 import org
.eclipse
.linuxtools
.tmf
.experiment
.TmfExperiment
;
34 import org
.eclipse
.linuxtools
.tmf
.request
.TmfDataRequest
;
35 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfRangeSynchSignal
;
36 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfSignalHandler
;
37 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfSignalManager
;
38 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfTimeSynchSignal
;
39 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.ITimeAnalysisViewer
;
40 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.TmfTimeScaleSelectionEvent
;
41 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.TmfTimeSelectionEvent
;
42 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.model
.ITmfTimeAnalysisEntry
;
43 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
44 import org
.eclipse
.swt
.widgets
.Display
;
48 * Abstract class used as a base for views handling specific time range data
52 * The class handles a single element queue of data requests, i.e. request can
53 * be triggered from different sources e.g. opening a file as well as a new
54 * selected time window
60 public abstract class AbsTimeUpdateView
extends TmfView
implements
61 IRequestStatusListener
{
63 // ========================================================================
65 // ========================================================================
67 * One second in nanoseconds
69 private static final long INITIAL_WINDOW_OFFSET
= 1000000000L; /*
73 // private static final long INITIAL_WINDOW_OFFSET = 100000000L; /* 100 ms
76 * Number of events before a GUI refresh
78 private static final Long INPUT_CHANGED_REFRESH
= 3000L;
79 private static final long DEFAULT_OFFSET
= 0L;
80 private static final int DEFAULT_CHUNK
= 1;
82 protected boolean synch
= true; // time synchronisation, used to be an
84 protected ITimeAnalysisViewer tsfviewer
= null;
86 // ========================================================================
88 // ========================================================================
89 public AbsTimeUpdateView(String viewID
) {
91 // freqState = UiCommonFactory.getQueue(this);
94 // ========================================================================
96 // ========================================================================
100 * @seeorg.eclipse.linuxtools.lttng.state.IStateDataRequestListener#
101 * processingStarted(org.eclipse.linuxtools.lttng.state.StateDataRequest)
104 public synchronized void processingStarted(RequestStartedSignal signal
) {
105 LttngSyntEventRequest request
= signal
.getRequest();
106 if (request
!= null) {
107 // update queue with the id of the current request.
108 // freqState.requestStarted(request);
110 // if there was no new request then this one is still on
111 // prepare for the reception of new data
114 // no new time range for zoom orders
115 TmfTimeRange trange
= null;
116 // Time Range will be used to filter out events which are
117 // not visible in one pixel
118 trange
= request
.getRange();
120 // indicate if the data model needs to be cleared e.g. a new
121 // experiment is being selected
122 boolean clearData
= request
.isclearDataInd();
123 // Indicate if current data needs to be cleared and if so
124 // specify the new experiment time range that applies
125 ModelUpdatePrep(trange
, clearData
);
132 * @seeorg.eclipse.linuxtools.lttng.state.IStateDataRequestListener#
133 * processingCompleted(org.eclipse.linuxtools.lttng.state.StateDataRequest)
136 public void processingCompleted(RequestCompletedSignal signal
) {
137 ILttngSyntEventRequest request
= signal
.getRequest();
139 if (request
== null) {
143 // Update wait cursor
146 // No data refresh actions for cancelled requests.
147 if (request
.isCancelled() || request
.isFailed()) {
148 if (TraceDebug
.isDEBUG()) {
149 TmfTimeRange trange
= request
.getRange();
150 if (request
.isCancelled()) {
151 TraceDebug
.debug("Request cancelled "
152 + trange
.getStartTime() + "-" + trange
.getEndTime()
153 + " Handled Events: " + request
.getSynEventCount()
154 + " " + request
.toString(), 15);
155 } else if (request
.isFailed()) {
156 TraceDebug
.debug("Request Failed " + trange
.getStartTime()
157 + "-" + trange
.getEndTime() + " Handled Events: "
158 + request
.getSynEventCount() + " "
159 + request
.toString());
165 modelInputChanged(request
, true);
170 * Registers as listener of time selection from other views
174 public void synchToTime(TmfTimeSynchSignal signal
) {
176 Object source
= signal
.getSource();
177 if (signal
!= null && source
!= null && source
!= this) {
178 // Internal value is expected in nano seconds.
179 long selectedTime
= signal
.getCurrentTime().getValue();
180 if (tsfviewer
!= null) {
181 tsfviewer
.setSelectedTime(selectedTime
, true, source
);
188 * Process the reception of time window adjustment in this view if the
189 * source of the update is not this view.
192 * @param clearingData
194 public void synchToTimeRange(TmfRangeSynchSignal signal
, boolean clearingData
) {
196 Object source
= signal
.getSource();
197 if (signal
!= null && source
!= null && source
!= this) {
198 // Internal value is expected in nano seconds.
199 TmfTimeRange trange
= signal
.getCurrentRange();
200 TmfExperiment
<?
> experiment
= TmfExperiment
.getCurrentExperiment();
201 if (experiment
== null) {
202 TraceDebug
.debug("Current selected experiment is null");
206 // Clearing of process data is configurable
207 dataRequest(trange
, experiment
.getTimeRange(), clearingData
);
213 * Trigger time synchronisation to other views this method shall be called
214 * when a check has been performed to note that an actual change of time has
215 * been performed vs a pure re-selection of the same time
220 protected void synchTimeNotification(long time
, Object source
) {
221 // if synchronisation selected
223 // Notify other views
224 TmfSignalManager
.dispatchSignal(new TmfTimeSynchSignal(source
, new LttngTimestamp(time
)));
229 * Common implementation of ITmfTimeSelectionListener, not used by all the
230 * views extending this abstract class
234 protected void tsfTmProcessSelEvent(TmfTimeSelectionEvent event
) {
235 Object source
= event
.getSource();
236 if (source
== null) {
240 ParamsUpdater paramUpdater
= getParamsUpdater();
241 Long savedSelTime
= paramUpdater
.getSelectedTime();
243 long selTimens
= event
.getSelectedTime();
245 // make sure the new selected time is different than saved before
247 if (savedSelTime
== null || savedSelTime
!= selTimens
) {
248 // Notify listener views.
249 synchTimeNotification(selTimens
, source
);
251 // Update the parameter updater to save the selected time
252 paramUpdater
.setSelectedTime(selTimens
);
254 if (TraceDebug
.isDEBUG()) {
255 TraceDebug
.debug("Selected Time: " + new LttngTimestamp(selTimens
) + "\n\t\t" + getName());
261 * Common implementation of ITmfTimeScaleSelectionListener, not used by all
262 * the views extending this abstract class
266 protected synchronized void tsfTmProcessTimeScaleEvent(TmfTimeScaleSelectionEvent event
) {
267 // source needed to keep track of source values
268 Object source
= event
.getSource();
270 if (source
!= null) {
271 // Update the parameter updater before carrying out a read request
272 ParamsUpdater paramUpdater
= getParamsUpdater();
273 boolean newParams
= paramUpdater
.processTimeScaleEvent(event
);
276 // Read the updated time window
277 TmfTimeRange trange
= paramUpdater
.getTrange();
278 if (trange
!= null) {
280 // Notify listener views. to perform data requests
281 // upon this notification
282 synchTimeRangeNotification(trange
, paramUpdater
.getSelectedTime(), source
);
289 * Inform registered listeners about the new time range
292 * @param selectedTime
295 protected void synchTimeRangeNotification(TmfTimeRange trange
, Long selectedTime
, Object source
) {
296 // if synchronisation selected
298 // Notify other views
299 TmfSignalManager
.dispatchSignal(new TmfRangeSynchSignal(source
, trange
, new LttngTimestamp(selectedTime
)));
304 * @param zoomedTRange
305 * @param experimentTRange
307 public void dataRequest(TmfTimeRange zoomedTRange
,
308 TmfTimeRange experimentTRange
, boolean clearingData
) {
310 // timeRange is the Experiment time range
311 boolean sent
= processDataRequest(zoomedTRange
, experimentTRange
, clearingData
);
319 * send data request directly e.g. doesn't use a queue
321 * @param requestTrange
323 * @param experimentTRange
327 private boolean processDataRequest(TmfTimeRange requestTrange
,
328 TmfTimeRange experimentTRange
, boolean clearingData
) {
330 if (requestTrange
== null || experimentTRange
== null) {
331 TraceDebug
.debug("Invalid input");
335 LttngSyntEventRequest request
= new LttngSyntEventRequest(
336 requestTrange
, DEFAULT_OFFSET
, TmfDataRequest
.ALL_DATA
,
337 DEFAULT_CHUNK
, this, experimentTRange
, getEventProcessor()) {
339 Long fCount
= getSynEventCount();
340 ITransEventProcessor processor
= getProcessor();
341 TmfTimestamp frunningTimeStamp
;
347 * org.eclipse.linuxtools.lttng.request.LttngSyntEventRequest#handleData
350 int handleDataCount
= 0;
351 int handleDataValidCount
= 0;
353 public void handleData() {
354 TmfEvent
[] result
= getData();
356 TmfEvent evt
= (result
.length
> 0) ? result
[0] : null;
359 handleDataValidCount
++;
360 LttngSyntheticEvent synEvent
= (LttngSyntheticEvent
) evt
;
362 SequenceInd indicator
= synEvent
.getSynType();
363 if (indicator
== SequenceInd
.BEFORE
364 || indicator
== SequenceInd
.AFTER
) {
365 processor
.process(evt
, synEvent
.getTraceModel());
366 } else if (indicator
== SequenceInd
.STARTREQ
) {
367 handleRequestStarted();
368 } else if (indicator
== SequenceInd
.ENDREQ
) {
369 processor
.process(evt
, synEvent
.getTraceModel());
370 // handleCompleted();
373 if (indicator
== SequenceInd
.BEFORE
) {
375 if (fCount
!= 0 && fCount
% INPUT_CHANGED_REFRESH
== 0) {
376 // send partial update
377 modelInputChanged(this, false);
379 if (TraceDebug
.isDEBUG()) {
380 frunningTimeStamp
= evt
.getTimestamp();
381 TraceDebug
.debug("handled: " + fCount
+ " sequence: " + synEvent
.getSynType());
389 public void handleRequestStarted() {
395 if (TraceDebug
.isDEBUG()) {
396 TraceDebug
.debug("AbsTimeUpdateView: Received=" + handleDataCount
+ ", Valid=" + handleDataCount
+ ", fCount=" + fCount
);
402 public void handleCompleted() {
403 super.handleCompleted();
405 // Data is not complete and should be handled as such
406 if (isFailed() || isCancelled()) {
407 modelIncomplete(this);
410 if (TraceDebug
.isDEBUG()) {
411 if (frunningTimeStamp
!= null) {
412 TraceDebug
.debug("Last event time stamp: "
413 + frunningTimeStamp
.getValue());
419 // obtain singleton core provider
420 LttngSyntheticEventProvider provider
= LttngCoreProviderFactory
423 // send the request to TMF
424 request
.startRequestInd(provider
);
425 request
.setclearDataInd(clearingData
);
430 * Returns an initial smaller window to allow the user to select the area of
433 * @param experimentTRange
436 protected TmfTimeRange
getInitTRange(TmfTimeRange experimentTRange
) {
437 TmfTimestamp expStartTime
= experimentTRange
.getStartTime();
438 TmfTimestamp expEndTime
= experimentTRange
.getEndTime();
439 TmfTimestamp initialEndOfWindow
= new LttngTimestamp(expStartTime
441 + INITIAL_WINDOW_OFFSET
);
442 if (initialEndOfWindow
.compareTo(expEndTime
, false) < 0) {
443 return new TmfTimeRange(expStartTime
, initialEndOfWindow
);
446 // The original size of the experiment is smaller than proposed adjusted
448 return experimentTRange
;
452 * Request the Time Analysis widget to enable or disable the wait cursor
453 * e.g. data request in progress or data request completed
457 protected void waitCursor(final boolean waitInd
) {
458 if (tsfviewer
!= null) {
459 Display display
= tsfviewer
.getControl().getDisplay();
461 // Perform the updates on the UI thread
462 display
.asyncExec(new Runnable() {
464 tsfviewer
.waitCursor(waitInd
);
471 * View preparation to override the current local information
474 * - new total time range e.g. Experiment level
475 * @param clearAllData
477 protected void ModelUpdatePrep(TmfTimeRange timeRange
, boolean clearAllData
) {
478 ItemContainer
<?
> itemContainer
= getItemContainer();
480 // start fresh e.g. new experiment selected
481 itemContainer
.clearItems();
483 // clear children but keep processes
484 itemContainer
.clearChildren();
487 // Obtain the current resource array
488 ITmfTimeAnalysisEntry
[] itemArr
= itemContainer
.readItems();
490 // clean up data and boundaries
491 displayModel(itemArr
, -1, -1, false, -1, -1, null);
493 ParamsUpdater updater
= getParamsUpdater();
494 if (updater
!= null) {
496 updater
.setEventsDiscarded(0);
498 // Update new visible time range if available
499 if (timeRange
!= null) {
500 updater
.update(timeRange
.getStartTime().getValue(), timeRange
.getEndTime().getValue());
506 * Initialize the model and view before reloading items
508 * @param boundaryRange
509 * @param visibleRange
512 protected void ModelUpdateInit(TmfTimeRange boundaryRange
, TmfTimeRange visibleRange
, Object source
) {
513 // Update the view boundaries
514 if (boundaryRange
!= null) {
515 ItemContainer
<?
> itemContainer
= getItemContainer();
516 if (itemContainer
!= null) {
517 itemContainer
.clearItems();
518 // Obtain the current process array
519 ITmfTimeAnalysisEntry
[] itemArr
= itemContainer
.readItems();
521 long startTime
= boundaryRange
.getStartTime().getValue();
522 long endTime
= boundaryRange
.getEndTime().getValue();
524 // Update the view part
525 displayModel(itemArr
, startTime
, endTime
, true, visibleRange
.getStartTime().getValue(), visibleRange
526 .getEndTime().getValue(), source
);
530 // update the view filtering parameters
531 if (visibleRange
!= null) {
532 ParamsUpdater updater
= getParamsUpdater();
533 if (updater
!= null) {
535 updater
.setEventsDiscarded(0);
536 // Update new visible time range if available
537 updater
.update(visibleRange
.getStartTime().getValue(), visibleRange
.getEndTime().getValue());
543 * Actions taken by the view to refresh its widget(s) with the updated data
548 * true: yes, false: partial update
550 protected void modelInputChanged(ILttngSyntEventRequest request
, boolean complete
) {
551 long experimentStartTime
= -1;
552 long experimentEndTime
= -1;
553 TmfTimeRange experimentTimeRange
= request
.getExperimentTimeRange();
554 if (experimentTimeRange
!= null) {
555 experimentStartTime
= experimentTimeRange
.getStartTime().getValue();
556 experimentEndTime
= experimentTimeRange
.getEndTime().getValue();
559 // Obtain the current resource list
560 ITmfTimeAnalysisEntry
[] itemArr
= getItemContainer().readItems();
562 if (itemArr
!= null) {
563 // Sort the array by pid
564 Arrays
.sort(itemArr
);
566 // Update the view part
567 displayModel(itemArr
, experimentStartTime
, experimentEndTime
, false, request
.getRange().getStartTime()
568 .getValue(), request
.getRange().getEndTime().getValue(), request
.getSource());
572 // reselect to original time
573 ParamsUpdater paramUpdater
= ResourceModelFactory
.getParamsUpdater();
574 if (paramUpdater
!= null && tsfviewer
!= null) {
575 final Long selTime
= paramUpdater
.getSelectedTime();
576 if (selTime
!= null) {
577 TraceDebug
.debug("View: " + getName() + "\n\t\tRestoring the selected time to: " + selTime
);
578 Display display
= tsfviewer
.getControl().getDisplay();
579 display
.asyncExec(new Runnable() {
581 tsfviewer
.setSelectedTime(selTime
, false, this);
586 if (TraceDebug
.isDEBUG()) {
588 Long count
= request
.getSynEventCount();
589 for (int pos
= 0; pos
< itemArr
.length
; pos
++) {
590 eventCount
+= itemArr
[pos
].getTraceEvents().size();
593 int discarded
= getParamsUpdater().getEventsDiscarded();
594 int discardedOutofOrder
= paramUpdater
.getEventsDiscardedWrongOrder();
595 TmfTimeRange range
= request
.getRange();
596 StringBuilder sb
= new StringBuilder("View: " + getName() + ", Events handled: " + count
597 + ", Events loaded in view: " + eventCount
+ ", Number of events discarded: " + discarded
598 + "\n\tNumber of events discarded with start time earlier than next good time: "
599 + discardedOutofOrder
);
601 sb
.append("\n\t\tRequested Time Range: " + range
.getStartTime() + "-" + range
.getEndTime());
602 sb
.append("\n\t\tExperiment Time Range: " + experimentStartTime
+ "-" + experimentEndTime
);
603 TraceDebug
.debug(sb
.toString());
611 // * Obtains the remainder fraction on unit Seconds of the entered value in
612 // * nanoseconds. e.g. input: 1241207054171080214 ns The number of seconds
614 // * be obtain by removing the last 9 digits: 1241207054 the fractional
615 // * portion of seconds, expressed in ns is: 171080214
620 // protected String formatNs(long v) {
621 // StringBuffer str = new StringBuffer();
622 // boolean neg = v < 0;
628 // String strVal = String.valueOf(v);
629 // if (v < 1000000000) {
633 // // Extract the last nine digits (e.g. fraction of a S expressed in ns
634 // return strVal.substring(strVal.length() - 9);
638 * The request was stopped, the data is incomplete
642 protected abstract void modelIncomplete(ILttngSyntEventRequest request
);
645 * Returns the Event processor instance related to a specific view
649 protected abstract ITransEventProcessor
getEventProcessor();
652 * To be overridden by some sub-classes although may not be needed in some
653 * e.g. statistics view
656 * @param startBoundTime
657 * @param endBoundTime
658 * @param updateTimeBounds
659 * - Time bounds updated needed e.g. if a new Experiment or trace
661 * @param startVisibleWindow
662 * @param endVisibleWindow
665 protected abstract void displayModel(final ITmfTimeAnalysisEntry
[] items
, final long startBoundTime
,
666 final long endBoundTime
, final boolean updateTimeBounds
, final long startVisibleWindow
,
667 final long endVisibleWindow
, final Object source
);
670 * To be overridden by some sub-classes although may not be needed in some
671 * e.g. statistics view
675 protected abstract ParamsUpdater
getParamsUpdater();
678 * Returns the model's item container
682 protected abstract ItemContainer
<?
> getItemContainer();