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
351 public void handleData() {
352 TmfEvent
[] result
= getData();
354 TmfEvent evt
= (result
.length
> 0) ? result
[0] : null;
356 LttngSyntheticEvent synEvent
= (LttngSyntheticEvent
) evt
;
358 SequenceInd indicator
= synEvent
.getSynType();
359 if (indicator
== SequenceInd
.BEFORE
360 || indicator
== SequenceInd
.AFTER
) {
361 processor
.process(evt
, synEvent
.getTraceModel());
362 } else if (indicator
== SequenceInd
.STARTREQ
) {
363 handleRequestStarted();
364 } else if (indicator
== SequenceInd
.ENDREQ
) {
365 processor
.process(evt
, synEvent
.getTraceModel());
366 // handleCompleted();
369 if (indicator
== SequenceInd
.BEFORE
) {
371 if (fCount
!= 0 && fCount
% INPUT_CHANGED_REFRESH
== 0) {
372 // send partial update
373 modelInputChanged(this, false);
375 if (TraceDebug
.isDEBUG()) {
376 frunningTimeStamp
= evt
.getTimestamp();
377 TraceDebug
.debug("handled: " + fCount
+ " sequence: " + synEvent
.getSynType());
385 public void handleRequestStarted() {
390 public void handleCompleted() {
391 super.handleCompleted();
393 // Data is not complete and should be handled as such
394 if (isFailed() || isCancelled()) {
395 modelIncomplete(this);
398 if (TraceDebug
.isDEBUG()) {
399 if (frunningTimeStamp
!= null) {
400 TraceDebug
.debug("Last event time stamp: "
401 + frunningTimeStamp
.getValue());
407 // obtain singleton core provider
408 LttngSyntheticEventProvider provider
= LttngCoreProviderFactory
411 // send the request to TMF
412 request
.startRequestInd(provider
);
413 request
.setclearDataInd(clearingData
);
418 * Returns an initial smaller window to allow the user to select the area of
421 * @param experimentTRange
424 protected TmfTimeRange
getInitTRange(TmfTimeRange experimentTRange
) {
425 TmfTimestamp expStartTime
= experimentTRange
.getStartTime();
426 TmfTimestamp expEndTime
= experimentTRange
.getEndTime();
427 TmfTimestamp initialEndOfWindow
= new LttngTimestamp(expStartTime
429 + INITIAL_WINDOW_OFFSET
);
430 if (initialEndOfWindow
.compareTo(expEndTime
, false) < 0) {
431 return new TmfTimeRange(expStartTime
, initialEndOfWindow
);
434 // The original size of the experiment is smaller than proposed adjusted
436 return experimentTRange
;
440 * Request the Time Analysis widget to enable or disable the wait cursor
441 * e.g. data request in progress or data request completed
445 protected void waitCursor(final boolean waitInd
) {
446 if (tsfviewer
!= null) {
447 Display display
= tsfviewer
.getControl().getDisplay();
449 // Perform the updates on the UI thread
450 display
.asyncExec(new Runnable() {
452 tsfviewer
.waitCursor(waitInd
);
459 * View preparation to override the current local information
462 * - new total time range e.g. Experiment level
463 * @param clearAllData
465 protected void ModelUpdatePrep(TmfTimeRange timeRange
, boolean clearAllData
) {
466 ItemContainer
<?
> itemContainer
= getItemContainer();
468 // start fresh e.g. new experiment selected
469 itemContainer
.clearItems();
471 // clear children but keep processes
472 itemContainer
.clearChildren();
475 // Obtain the current resource array
476 ITmfTimeAnalysisEntry
[] itemArr
= itemContainer
.readItems();
478 // clean up data and boundaries
479 displayModel(itemArr
, -1, -1, false, -1, -1, null);
481 ParamsUpdater updater
= getParamsUpdater();
482 if (updater
!= null) {
484 updater
.setEventsDiscarded(0);
486 // Update new visible time range if available
487 if (timeRange
!= null) {
488 updater
.update(timeRange
.getStartTime().getValue(), timeRange
.getEndTime().getValue());
494 * Initialize the model and view before reloading items
496 * @param boundaryRange
497 * @param visibleRange
500 protected void ModelUpdateInit(TmfTimeRange boundaryRange
, TmfTimeRange visibleRange
, Object source
) {
501 // Update the view boundaries
502 if (boundaryRange
!= null) {
503 ItemContainer
<?
> itemContainer
= getItemContainer();
504 if (itemContainer
!= null) {
505 itemContainer
.clearItems();
506 // Obtain the current process array
507 ITmfTimeAnalysisEntry
[] itemArr
= itemContainer
.readItems();
509 long startTime
= boundaryRange
.getStartTime().getValue();
510 long endTime
= boundaryRange
.getEndTime().getValue();
512 // Update the view part
513 displayModel(itemArr
, startTime
, endTime
, true, visibleRange
.getStartTime().getValue(), visibleRange
514 .getEndTime().getValue(), source
);
518 // update the view filtering parameters
519 if (visibleRange
!= null) {
520 ParamsUpdater updater
= getParamsUpdater();
521 if (updater
!= null) {
523 updater
.setEventsDiscarded(0);
524 // Update new visible time range if available
525 updater
.update(visibleRange
.getStartTime().getValue(), visibleRange
.getEndTime().getValue());
531 * Actions taken by the view to refresh its widget(s) with the updated data
536 * true: yes, false: partial update
538 protected void modelInputChanged(ILttngSyntEventRequest request
, boolean complete
) {
539 long experimentStartTime
= -1;
540 long experimentEndTime
= -1;
541 TmfTimeRange experimentTimeRange
= request
.getExperimentTimeRange();
542 if (experimentTimeRange
!= null) {
543 experimentStartTime
= experimentTimeRange
.getStartTime().getValue();
544 experimentEndTime
= experimentTimeRange
.getEndTime().getValue();
547 // Obtain the current resource list
548 ITmfTimeAnalysisEntry
[] itemArr
= getItemContainer().readItems();
550 if (itemArr
!= null) {
551 // Sort the array by pid
552 Arrays
.sort(itemArr
);
554 // Update the view part
555 displayModel(itemArr
, experimentStartTime
, experimentEndTime
, false, request
.getRange().getStartTime()
556 .getValue(), request
.getRange().getEndTime().getValue(), request
.getSource());
560 // reselect to original time
561 ParamsUpdater paramUpdater
= ResourceModelFactory
.getParamsUpdater();
562 if (paramUpdater
!= null && tsfviewer
!= null) {
563 final Long selTime
= paramUpdater
.getSelectedTime();
564 if (selTime
!= null) {
565 TraceDebug
.debug("View: " + getName() + "\n\t\tRestoring the selected time to: " + selTime
);
566 Display display
= tsfviewer
.getControl().getDisplay();
567 display
.asyncExec(new Runnable() {
569 tsfviewer
.setSelectedTime(selTime
, false, this);
574 if (TraceDebug
.isDEBUG()) {
576 Long count
= request
.getSynEventCount();
577 for (int pos
= 0; pos
< itemArr
.length
; pos
++) {
578 eventCount
+= itemArr
[pos
].getTraceEvents().size();
581 int discarded
= getParamsUpdater().getEventsDiscarded();
582 int discardedOutofOrder
= paramUpdater
.getEventsDiscardedWrongOrder();
583 TmfTimeRange range
= request
.getRange();
584 StringBuilder sb
= new StringBuilder("View: " + getName() + ", Events handled: " + count
585 + ", Events loaded in view: " + eventCount
+ ", Number of events discarded: " + discarded
586 + "\n\tNumber of events discarded with start time earlier than next good time: "
587 + discardedOutofOrder
);
589 sb
.append("\n\t\tRequested Time Range: " + range
.getStartTime() + "-" + range
.getEndTime());
590 sb
.append("\n\t\tExperiment Time Range: " + experimentStartTime
+ "-" + experimentEndTime
);
591 TraceDebug
.debug(sb
.toString());
599 // * Obtains the remainder fraction on unit Seconds of the entered value in
600 // * nanoseconds. e.g. input: 1241207054171080214 ns The number of seconds
602 // * be obtain by removing the last 9 digits: 1241207054 the fractional
603 // * portion of seconds, expressed in ns is: 171080214
608 // protected String formatNs(long v) {
609 // StringBuffer str = new StringBuffer();
610 // boolean neg = v < 0;
616 // String strVal = String.valueOf(v);
617 // if (v < 1000000000) {
621 // // Extract the last nine digits (e.g. fraction of a S expressed in ns
622 // return strVal.substring(strVal.length() - 9);
626 * The request was stopped, the data is incomplete
630 protected abstract void modelIncomplete(ILttngSyntEventRequest request
);
633 * Returns the Event processor instance related to a specific view
637 protected abstract ITransEventProcessor
getEventProcessor();
640 * To be overridden by some sub-classes although may not be needed in some
641 * e.g. statistics view
644 * @param startBoundTime
645 * @param endBoundTime
646 * @param updateTimeBounds
647 * - Time bounds updated needed e.g. if a new Experiment or trace
649 * @param startVisibleWindow
650 * @param endVisibleWindow
653 protected abstract void displayModel(final ITmfTimeAnalysisEntry
[] items
, final long startBoundTime
,
654 final long endBoundTime
, final boolean updateTimeBounds
, final long startVisibleWindow
,
655 final long endVisibleWindow
, final Object source
);
658 * To be overridden by some sub-classes although may not be needed in some
659 * e.g. statistics view
663 protected abstract ParamsUpdater
getParamsUpdater();
666 * Returns the model's item container
670 protected abstract ItemContainer
<?
> getItemContainer();