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 public void handleData() {
351 TmfEvent
[] result
= getData();
353 TmfEvent evt
= (result
.length
> 0) ? result
[0] : null;
355 LttngSyntheticEvent synEvent
= (LttngSyntheticEvent
) evt
;
357 SequenceInd indicator
= synEvent
.getSynType();
358 if (indicator
== SequenceInd
.BEFORE
359 || indicator
== SequenceInd
.AFTER
) {
360 processor
.process(evt
, synEvent
.getTraceModel());
361 } else if (indicator
== SequenceInd
.STARTREQ
) {
362 handleRequestStarted();
363 } else if (indicator
== SequenceInd
.ENDREQ
) {
364 processor
.process(evt
, synEvent
.getTraceModel());
365 // handleCompleted();
368 if (indicator
== SequenceInd
.BEFORE
) {
370 if (fCount
!= 0 && fCount
% INPUT_CHANGED_REFRESH
== 0) {
371 // send partial update
372 modelInputChanged(this, false);
374 if (TraceDebug
.isDEBUG()) {
375 frunningTimeStamp
= evt
.getTimestamp();
376 TraceDebug
.debug("handled: " + fCount
+ " sequence: " + synEvent
.getSynType());
384 public void handleRequestStarted() {
388 public void handleCompleted() {
389 super.handleCompleted();
391 // Data is not complete and should be handled as such
392 if (isFailed() || isCancelled()) {
393 modelIncomplete(this);
396 if (TraceDebug
.isDEBUG()) {
397 if (frunningTimeStamp
!= null) {
398 TraceDebug
.debug("Last event time stamp: "
399 + frunningTimeStamp
.getValue());
405 // obtain singleton core provider
406 LttngSyntheticEventProvider provider
= LttngCoreProviderFactory
409 // send the request to TMF
410 request
.startRequestInd(provider
);
411 request
.setclearDataInd(clearingData
);
416 * Returns an initial smaller window to allow the user to select the area of
419 * @param experimentTRange
422 protected TmfTimeRange
getInitTRange(TmfTimeRange experimentTRange
) {
423 TmfTimestamp expStartTime
= experimentTRange
.getStartTime();
424 TmfTimestamp expEndTime
= experimentTRange
.getEndTime();
425 TmfTimestamp initialEndOfWindow
= new LttngTimestamp(expStartTime
427 + INITIAL_WINDOW_OFFSET
);
428 if (initialEndOfWindow
.compareTo(expEndTime
, false) < 0) {
429 return new TmfTimeRange(expStartTime
, initialEndOfWindow
);
432 // The original size of the experiment is smaller than proposed adjusted
434 return experimentTRange
;
438 * Request the Time Analysis widget to enable or disable the wait cursor
439 * e.g. data request in progress or data request completed
443 protected void waitCursor(final boolean waitInd
) {
444 if (tsfviewer
!= null) {
445 Display display
= tsfviewer
.getControl().getDisplay();
447 // Perform the updates on the UI thread
448 display
.asyncExec(new Runnable() {
450 tsfviewer
.waitCursor(waitInd
);
457 * View preparation to override the current local information
460 * - new total time range e.g. Experiment level
461 * @param clearAllData
463 protected void ModelUpdatePrep(TmfTimeRange timeRange
, boolean clearAllData
) {
464 ItemContainer
<?
> itemContainer
= getItemContainer();
466 // start fresh e.g. new experiment selected
467 itemContainer
.clearItems();
469 // clear children but keep processes
470 itemContainer
.clearChildren();
473 // Obtain the current resource array
474 ITmfTimeAnalysisEntry
[] itemArr
= itemContainer
.readItems();
476 // clean up data and boundaries
477 displayModel(itemArr
, -1, -1, false, -1, -1, null);
479 ParamsUpdater updater
= getParamsUpdater();
480 if (updater
!= null) {
482 updater
.setEventsDiscarded(0);
484 // Update new visible time range if available
485 if (timeRange
!= null) {
486 updater
.update(timeRange
.getStartTime().getValue(), timeRange
.getEndTime().getValue());
492 * Initialize the model and view before reloading items
494 * @param boundaryRange
495 * @param visibleRange
498 protected void ModelUpdateInit(TmfTimeRange boundaryRange
, TmfTimeRange visibleRange
, Object source
) {
499 // Update the view boundaries
500 if (boundaryRange
!= null) {
501 ItemContainer
<?
> itemContainer
= getItemContainer();
502 if (itemContainer
!= null) {
503 itemContainer
.clearItems();
504 // Obtain the current process array
505 ITmfTimeAnalysisEntry
[] itemArr
= itemContainer
.readItems();
507 long startTime
= boundaryRange
.getStartTime().getValue();
508 long endTime
= boundaryRange
.getEndTime().getValue();
510 // Update the view part
511 displayModel(itemArr
, startTime
, endTime
, true, visibleRange
.getStartTime().getValue(), visibleRange
512 .getEndTime().getValue(), source
);
516 // update the view filtering parameters
517 if (visibleRange
!= null) {
518 ParamsUpdater updater
= getParamsUpdater();
519 if (updater
!= null) {
521 updater
.setEventsDiscarded(0);
522 // Update new visible time range if available
523 updater
.update(visibleRange
.getStartTime().getValue(), visibleRange
.getEndTime().getValue());
529 * Actions taken by the view to refresh its widget(s) with the updated data
534 * true: yes, false: partial update
536 protected void modelInputChanged(ILttngSyntEventRequest request
, boolean complete
) {
537 long experimentStartTime
= -1;
538 long experimentEndTime
= -1;
539 TmfTimeRange experimentTimeRange
= request
.getExperimentTimeRange();
540 if (experimentTimeRange
!= null) {
541 experimentStartTime
= experimentTimeRange
.getStartTime().getValue();
542 experimentEndTime
= experimentTimeRange
.getEndTime().getValue();
545 // Obtain the current resource list
546 ITmfTimeAnalysisEntry
[] itemArr
= getItemContainer().readItems();
548 if (itemArr
!= null) {
549 // Sort the array by pid
550 Arrays
.sort(itemArr
);
552 // Update the view part
553 displayModel(itemArr
, experimentStartTime
, experimentEndTime
, false, request
.getRange().getStartTime()
554 .getValue(), request
.getRange().getEndTime().getValue(), request
.getSource());
558 // reselect to original time
559 ParamsUpdater paramUpdater
= ResourceModelFactory
.getParamsUpdater();
560 if (paramUpdater
!= null && tsfviewer
!= null) {
561 final Long selTime
= paramUpdater
.getSelectedTime();
562 if (selTime
!= null) {
563 TraceDebug
.debug("View: " + getName() + "\n\t\tRestoring the selected time to: " + selTime
);
564 Display display
= tsfviewer
.getControl().getDisplay();
565 display
.asyncExec(new Runnable() {
567 tsfviewer
.setSelectedTime(selTime
, false, this);
572 if (TraceDebug
.isDEBUG()) {
574 Long count
= request
.getSynEventCount();
575 for (int pos
= 0; pos
< itemArr
.length
; pos
++) {
576 eventCount
+= itemArr
[pos
].getTraceEvents().size();
579 int discarded
= getParamsUpdater().getEventsDiscarded();
580 int discardedOutofOrder
= paramUpdater
.getEventsDiscardedWrongOrder();
581 TmfTimeRange range
= request
.getRange();
582 StringBuilder sb
= new StringBuilder("View: " + getName() + ", Events handled: " + count
583 + ", Events loaded in view: " + eventCount
+ ", Number of events discarded: " + discarded
584 + "\n\tNumber of events discarded with start time earlier than next good time: "
585 + discardedOutofOrder
);
587 sb
.append("\n\t\tRequested Time Range: " + range
.getStartTime() + "-" + range
.getEndTime());
588 sb
.append("\n\t\tExperiment Time Range: " + experimentStartTime
+ "-" + experimentEndTime
);
589 TraceDebug
.debug(sb
.toString());
597 // * Obtains the remainder fraction on unit Seconds of the entered value in
598 // * nanoseconds. e.g. input: 1241207054171080214 ns The number of seconds
600 // * be obtain by removing the last 9 digits: 1241207054 the fractional
601 // * portion of seconds, expressed in ns is: 171080214
606 // protected String formatNs(long v) {
607 // StringBuffer str = new StringBuffer();
608 // boolean neg = v < 0;
614 // String strVal = String.valueOf(v);
615 // if (v < 1000000000) {
619 // // Extract the last nine digits (e.g. fraction of a S expressed in ns
620 // return strVal.substring(strVal.length() - 9);
624 * The request was stopped, the data is incomplete
628 protected abstract void modelIncomplete(ILttngSyntEventRequest request
);
631 * Returns the Event processor instance related to a specific view
635 protected abstract ITransEventProcessor
getEventProcessor();
638 * To be overridden by some sub-classes although may not be needed in some
639 * e.g. statistics view
642 * @param startBoundTime
643 * @param endBoundTime
644 * @param updateTimeBounds
645 * - Time bounds updated needed e.g. if a new Experiment or trace
647 * @param startVisibleWindow
648 * @param endVisibleWindow
651 protected abstract void displayModel(final ITmfTimeAnalysisEntry
[] items
, final long startBoundTime
,
652 final long endBoundTime
, final boolean updateTimeBounds
, final long startVisibleWindow
,
653 final long endVisibleWindow
, final Object source
);
656 * To be overridden by some sub-classes although may not be needed in some
657 * e.g. statistics view
661 protected abstract ParamsUpdater
getParamsUpdater();
664 * Returns the model's item container
668 protected abstract ItemContainer
<?
> getItemContainer();