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
.LttngTimestamp
;
20 import org
.eclipse
.linuxtools
.lttng
.request
.ILttngSyntEventRequest
;
21 import org
.eclipse
.linuxtools
.lttng
.request
.IRequestStatusListener
;
22 import org
.eclipse
.linuxtools
.lttng
.request
.LttngSyntEventRequest
;
23 import org
.eclipse
.linuxtools
.lttng
.request
.RequestCompletedSignal
;
24 import org
.eclipse
.linuxtools
.lttng
.request
.RequestStartedSignal
;
25 import org
.eclipse
.linuxtools
.lttng
.state
.evProcessor
.ITransEventProcessor
;
26 import org
.eclipse
.linuxtools
.lttng
.ui
.TraceDebug
;
27 import org
.eclipse
.linuxtools
.lttng
.ui
.model
.trange
.ItemContainer
;
28 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
29 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
30 import org
.eclipse
.linuxtools
.tmf
.experiment
.TmfExperiment
;
31 import org
.eclipse
.linuxtools
.tmf
.request
.ITmfDataRequest
.ExecutionType
;
32 import org
.eclipse
.linuxtools
.tmf
.request
.TmfDataRequest
;
33 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfRangeSynchSignal
;
34 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfSignalHandler
;
35 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfSignalManager
;
36 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfTimeSynchSignal
;
37 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.ITimeAnalysisViewer
;
38 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.TmfTimeScaleSelectionEvent
;
39 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.TmfTimeSelectionEvent
;
40 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.model
.ITmfTimeAnalysisEntry
;
41 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
42 import org
.eclipse
.swt
.widgets
.Display
;
46 * Abstract class used as a base for views handling specific time range data
50 * The class handles a single element queue of data requests, i.e. request can
51 * be triggered from different sources e.g. opening a file as well as a new
52 * selected time window
58 public abstract class AbsTimeUpdateView
extends TmfView
implements IRequestStatusListener
{
60 // ========================================================================
62 // ========================================================================
64 // private static final long INITIAL_WINDOW_OFFSET = (1L * 1 * 1000 * 1000); // .001sec
65 // private static final long INITIAL_WINDOW_OFFSET = (1L * 10 * 1000 * 1000); // .01sec
66 private static final long INITIAL_WINDOW_OFFSET
= (1L * 100 * 1000 * 1000); // .1sec
67 // private static final long INITIAL_WINDOW_OFFSET = (1L * 1000 * 1000 * 1000); // 1sec
70 * Number of events before a GUI refresh
72 protected static final Long INPUT_CHANGED_REFRESH
= 20000L;
73 private static final long DEFAULT_OFFSET
= 0L;
74 private static final int DEFAULT_CHUNK
= 1;
76 protected boolean synch
= true; // time synchronization, used to be an option
77 protected ITimeAnalysisViewer tsfviewer
= null;
79 private LttngSyntEventRequest fCurrentRequest
= null;
81 protected LttngSyntheticEventProvider fProvider
= LttngCoreProviderFactory
.getEventProvider(getProviderId());
83 // ========================================================================
85 // ========================================================================
86 public AbsTimeUpdateView(String viewID
) {
88 // freqState = UiCommonFactory.getQueue(this);
91 // ========================================================================
93 // ========================================================================
96 * Returns the number of events after which the relevant display will
101 protected Long
getInputChangedRefresh() {
102 return INPUT_CHANGED_REFRESH
;
108 * @seeorg.eclipse.linuxtools.lttng.state.IStateDataRequestListener#
109 * processingStarted(org.eclipse.linuxtools.lttng.state.StateDataRequest)
113 public synchronized void processingStarted(RequestStartedSignal signal
) {
114 LttngSyntEventRequest request
= signal
.getRequest();
115 if (request
!= null) {
116 // update queue with the id of the current request.
117 // freqState.requestStarted(request);
119 // if there was no new request then this one is still on
120 // prepare for the reception of new data
123 // no new time range for zoom orders
124 TmfTimeRange trange
= null;
125 // Time Range will be used to filter out events which are
126 // not visible in one pixel
127 trange
= request
.getRange();
129 // indicate if the data model needs to be cleared e.g. a new
130 // experiment is being selected
131 boolean clearData
= request
.isclearDataInd();
132 // Indicate if current data needs to be cleared and if so
133 // specify the new experiment time range that applies
134 ModelUpdatePrep(trange
, clearData
);
141 * @seeorg.eclipse.linuxtools.lttng.state.IStateDataRequestListener#
142 * processingCompleted(org.eclipse.linuxtools.lttng.state.StateDataRequest)
146 public void processingCompleted(RequestCompletedSignal signal
) {
147 ILttngSyntEventRequest request
= signal
.getRequest();
149 if (request
== null) {
153 // Update wait cursor
156 // No data refresh actions for cancelled requests.
157 if (request
.isCancelled() || request
.isFailed()) {
158 if (TraceDebug
.isDEBUG()) {
159 TmfTimeRange trange
= request
.getRange();
160 if (request
.isCancelled()) {
161 TraceDebug
.debug("Request cancelled "
162 + trange
.getStartTime() + "-" + trange
.getEndTime()
163 + " Handled Events: " + request
.getSynEventCount()
164 + " " + request
.toString(), 15);
165 } else if (request
.isFailed()) {
166 TraceDebug
.debug("Request Failed " + trange
.getStartTime()
167 + "-" + trange
.getEndTime() + " Handled Events: "
168 + request
.getSynEventCount() + " "
169 + request
.toString());
175 modelInputChanged(request
, true);
180 * Registers as listener of time selection from other views
184 public void synchToTime(TmfTimeSynchSignal signal
) {
186 Object source
= signal
.getSource();
187 if (signal
!= null && source
!= null && source
!= this) {
188 // Internal value is expected in nano seconds.
189 long selectedTime
= signal
.getCurrentTime().getValue();
190 if (tsfviewer
!= null) {
191 tsfviewer
.setSelectedTime(selectedTime
, true, source
);
198 * Process the reception of time window adjustment in this view if the
199 * source of the update is not this view.
202 * @param clearingData
204 public void synchToTimeRange(TmfRangeSynchSignal signal
, boolean clearingData
) {
206 Object source
= signal
.getSource();
207 if (signal
!= null && source
!= null && source
!= this) {
208 // Internal value is expected in nano seconds.
209 TmfTimeRange trange
= signal
.getCurrentRange();
210 TmfExperiment
<?
> experiment
= TmfExperiment
.getCurrentExperiment();
211 if (experiment
== null) {
212 TraceDebug
.debug("Current selected experiment is null");
216 // Clearing of process data is configurable
217 dataRequest(trange
, experiment
.getTimeRange(), clearingData
, ExecutionType
.FOREGROUND
);
223 * Trigger time synchronisation to other views this method shall be called
224 * when a check has been performed to note that an actual change of time has
225 * been performed vs a pure re-selection of the same time
230 protected void synchTimeNotification(long time
, Object source
) {
231 // if synchronisation selected
233 // Notify other views
234 TmfSignalManager
.dispatchSignal(new TmfTimeSynchSignal(source
, new LttngTimestamp(time
)));
239 * Common implementation of ITmfTimeSelectionListener, not used by all the
240 * views extending this abstract class
244 protected void tsfTmProcessSelEvent(TmfTimeSelectionEvent event
) {
245 Object source
= event
.getSource();
246 if (source
== null) {
250 ParamsUpdater paramUpdater
= getParamsUpdater();
251 Long savedSelTime
= paramUpdater
.getSelectedTime();
253 long selTimens
= event
.getSelectedTime();
255 // make sure the new selected time is different than saved before
257 if (savedSelTime
== null || savedSelTime
!= selTimens
) {
258 // Notify listener views.
259 synchTimeNotification(selTimens
, source
);
261 // Update the parameter updater to save the selected time
262 paramUpdater
.setSelectedTime(selTimens
);
264 if (TraceDebug
.isDEBUG()) {
265 TraceDebug
.debug("Selected Time: " + new LttngTimestamp(selTimens
) + "\n\t\t" + getName());
271 * Common implementation of ITmfTimeScaleSelectionListener, not used by all
272 * the views extending this abstract class
276 protected void tsfTmProcessTimeScaleEvent(TmfTimeScaleSelectionEvent event
) {
277 // source needed to keep track of source values
278 Object source
= event
.getSource();
280 boolean newParams
= false;
281 TmfTimeRange trange
= null;
282 Long selectedTime
= null;
284 // update all information and get relevant data
285 synchronized (this) {
286 if (source
!= null) {
287 // Update the parameter updater before carrying out a read request
288 ParamsUpdater paramUpdater
= getParamsUpdater();
289 newParams
= paramUpdater
.processTimeScaleEvent(event
);
292 // Read the updated time window
293 trange
= paramUpdater
.getTrange();
294 if (trange
!= null) {
295 selectedTime
= paramUpdater
.getSelectedTime();
301 // Check for selectedTime is sufficient since it is only set if
302 // newParams is true and trange is not null
303 if (selectedTime
!= null) {
304 // Notify listener views. to perform data requests
305 // upon this notification
307 // Note that this has to be done outside the synchronized statement
308 // because otherwise we could end-up in a deadlock if a ongoing
309 // request needs to be canceled.
310 synchTimeRangeNotification(trange
, selectedTime
, source
);
315 * Inform registered listeners about the new time range
318 * @param selectedTime
321 protected void synchTimeRangeNotification(TmfTimeRange trange
, Long selectedTime
, Object source
) {
322 // if synchronisation selected
324 // Notify other views
325 TmfSignalManager
.dispatchSignal(new TmfRangeSynchSignal(source
, trange
, new LttngTimestamp(selectedTime
)));
330 * @param zoomedTRange
331 * @param experimentTRange
334 public void dataRequest(TmfTimeRange zoomedTRange
,
335 TmfTimeRange experimentTRange
, boolean clearingData
, ExecutionType execType
) {
337 // timeRange is the Experiment time range
338 boolean sent
= processDataRequest(zoomedTRange
, experimentTRange
, clearingData
, execType
);
346 // * @param zoomedTRange
347 // * @param experimentTRange
350 // public void dataRequest(TmfTimeRange zoomedTRange,
351 // TmfTimeRange experimentTRange, boolean clearingData) {
353 // // timeRange is the Experiment time range
354 // boolean sent = processDataRequest(zoomedTRange, experimentTRange, clearingData);
362 * send data request directly e.g. doesn't use a queue
364 * @param requestTrange
366 * @param experimentTRange
371 private boolean processDataRequest(TmfTimeRange requestTrange
,
372 TmfTimeRange experimentTRange
, boolean clearingData
, ExecutionType execType
) {
374 if (requestTrange
== null || experimentTRange
== null) {
375 TraceDebug
.debug("Invalid input");
379 // Cancel the currently executing request before starting a new one
380 fProvider
.conditionallyCancelRequests();
382 fCurrentRequest
= new LttngSyntEventRequest(
383 requestTrange
, DEFAULT_OFFSET
, TmfDataRequest
.ALL_DATA
,
384 DEFAULT_CHUNK
, this, experimentTRange
, getEventProcessor(),
385 TmfExperiment
.getCurrentExperiment().getName(), execType
) {
387 Long fCount
= getSynEventCount();
388 ITransEventProcessor processor
= getProcessor();
389 TmfTimestamp frunningTimeStamp
;
395 * org.eclipse.linuxtools.lttng.request.LttngSyntEventRequest#handleData
398 //// int handleDataCount = 0;
399 //// int handleDataValidCount = 0;
401 // public void handleData() {
402 // LttngSyntheticEvent[] result = getData();
404 // TmfEvent evt = (result.length > 0) ? result[0] : null;
405 //// handleDataCount++;
408 public void handleData(LttngSyntheticEvent event
) {
409 super.handleData(event
);
411 // handleDataValidCount++;
412 LttngSyntheticEvent synEvent
= (LttngSyntheticEvent
) event
;
414 switch (synEvent
.getSynType()) {
417 handleRequestStarted();
422 processor
.process(event
, synEvent
.getTraceModel());
424 if ((fCount
!= 0) && (fCount
% getInputChangedRefresh() == 0)) {
425 // send partial update
426 modelInputChanged(this, false);
428 if (TraceDebug
.isDEBUG()) {
429 frunningTimeStamp
= event
.getTimestamp();
430 TraceDebug
.debug("handled: " + fCount
+ " sequence: " + synEvent
.getSynType());
439 processor
.process(event
, synEvent
.getTraceModel());
450 public void handleRequestStarted() {
456 // if (TraceDebug.isDEBUG()) {
457 // TraceDebug.debug("AbsTimeUpdateView: Received=" + handleDataCount + ", Valid=" + handleDataCount + ", fCount=" + fCount);
463 public void handleCompleted() {
464 super.handleCompleted();
466 // Data is not complete and should be handled as such
467 if (isFailed() || isCancelled()) {
468 modelIncomplete(this);
471 if (TraceDebug
.isDEBUG()) {
472 if (frunningTimeStamp
!= null) {
473 TraceDebug
.debug("Last event time stamp: "
474 + frunningTimeStamp
.getValue());
480 // send the request to TMF
481 fCurrentRequest
.startRequestInd(fProvider
);
482 fCurrentRequest
.setclearDataInd(clearingData
);
487 * Returns an initial smaller window to allow the user to select the area of
490 * @param experimentTRange
493 protected TmfTimeRange
getInitTRange(TmfTimeRange experimentTRange
) {
494 TmfTimestamp expStartTime
= experimentTRange
.getStartTime();
495 TmfTimestamp expEndTime
= experimentTRange
.getEndTime();
496 TmfTimestamp initialEndOfWindow
= new LttngTimestamp(expStartTime
498 + INITIAL_WINDOW_OFFSET
);
499 if (initialEndOfWindow
.compareTo(expEndTime
, false) < 0) {
500 return new TmfTimeRange(expStartTime
, initialEndOfWindow
);
503 // The original size of the experiment is smaller than proposed adjusted
505 return experimentTRange
;
509 * Request the Time Analysis widget to enable or disable the wait cursor
510 * e.g. data request in progress or data request completed
514 protected void waitCursor(final boolean waitInd
) {
515 if ((tsfviewer
!= null) && (!tsfviewer
.getControl().isDisposed())) {
516 Display display
= tsfviewer
.getControl().getDisplay();
518 // Perform the updates on the UI thread
519 display
.asyncExec(new Runnable() {
522 if ((tsfviewer
!= null) && (!tsfviewer
.getControl().isDisposed())) {
523 tsfviewer
.waitCursor(waitInd
);
531 * View preparation to override the current local information
534 * - new total time range e.g. Experiment level
535 * @param clearAllData
537 protected void ModelUpdatePrep(TmfTimeRange timeRange
, boolean clearAllData
) {
538 ItemContainer
<?
> itemContainer
= getItemContainer();
540 // start fresh e.g. new experiment selected
541 itemContainer
.clearItems();
543 // clear children but keep processes
544 itemContainer
.clearChildren();
547 // Obtain the current resource array
548 ITmfTimeAnalysisEntry
[] itemArr
= itemContainer
.readItems();
550 // clean up data and boundaries
551 displayModel(itemArr
, -1, -1, false, -1, -1, null);
553 ParamsUpdater updater
= getParamsUpdater();
554 if (updater
!= null) {
556 updater
.setEventsDiscarded(0);
558 // Update new visible time range if available
559 if (timeRange
!= null) {
560 updater
.update(timeRange
.getStartTime().getValue(), timeRange
.getEndTime().getValue());
566 * Initialize the model and view before reloading items
568 * @param boundaryRange
569 * @param visibleRange
572 protected void ModelUpdateInit(TmfTimeRange boundaryRange
, TmfTimeRange visibleRange
, Object source
) {
573 // Update the view boundaries
574 if (boundaryRange
!= null) {
575 ItemContainer
<?
> itemContainer
= getItemContainer();
576 if (itemContainer
!= null) {
577 itemContainer
.clearItems();
578 // Obtain the current process array
579 ITmfTimeAnalysisEntry
[] itemArr
= itemContainer
.readItems();
581 long startTime
= boundaryRange
.getStartTime().getValue();
582 long endTime
= boundaryRange
.getEndTime().getValue();
584 // Update the view part
585 displayModel(itemArr
, startTime
, endTime
, true, visibleRange
.getStartTime().getValue(), visibleRange
586 .getEndTime().getValue(), source
);
590 // update the view filtering parameters
591 if (visibleRange
!= null) {
592 ParamsUpdater updater
= getParamsUpdater();
593 if (updater
!= null) {
595 updater
.setEventsDiscarded(0);
596 // Update new visible time range if available
597 updater
.update(visibleRange
.getStartTime().getValue(), visibleRange
.getEndTime().getValue());
603 * Actions taken by the view to refresh its widget(s) with the updated data
608 * true: yes, false: partial update
610 protected void modelInputChanged(ILttngSyntEventRequest request
, boolean complete
) {
611 long experimentStartTime
= -1;
612 long experimentEndTime
= -1;
613 TmfTimeRange experimentTimeRange
= request
.getExperimentTimeRange();
614 if (experimentTimeRange
!= null) {
615 experimentStartTime
= experimentTimeRange
.getStartTime().getValue();
616 experimentEndTime
= experimentTimeRange
.getEndTime().getValue();
619 // Obtain the current resource list
620 ITmfTimeAnalysisEntry
[] itemArr
= getItemContainer().readItems();
622 if (itemArr
!= null) {
623 // Sort the array by pid
624 Arrays
.sort(itemArr
);
626 // Update the view part
627 displayModel(itemArr
, experimentStartTime
, experimentEndTime
, false, request
.getRange().getStartTime()
628 .getValue(), request
.getRange().getEndTime().getValue(), request
.getSource());
632 // reselect to original time
633 ParamsUpdater paramUpdater
= getParamsUpdater();
634 if ((paramUpdater
!= null) && (tsfviewer
!= null) && (!tsfviewer
.getControl().isDisposed())) {
635 final Long selTime
= paramUpdater
.getSelectedTime();
636 if (selTime
!= null) {
637 TraceDebug
.debug("View: " + getName() + "\n\t\tRestoring the selected time to: " + selTime
);
638 Display display
= tsfviewer
.getControl().getDisplay();
639 display
.asyncExec(new Runnable() {
642 if ((tsfviewer
!= null) && (!tsfviewer
.getControl().isDisposed())) {
643 tsfviewer
.setSelectedTime(selTime
, false, this);
649 // System.out.println(System.currentTimeMillis() + ": AbsTimeUpdate (" + getName() + ") completed");
651 if (TraceDebug
.isDEBUG()) {
653 Long count
= request
.getSynEventCount();
654 for (int pos
= 0; pos
< itemArr
.length
; pos
++) {
655 eventCount
+= itemArr
[pos
].getTraceEvents().size();
658 int discarded
= paramUpdater
.getEventsDiscarded();
659 int discardedOutofOrder
= paramUpdater
.getEventsDiscardedWrongOrder();
660 int discardedOutofViewRange
= paramUpdater
.getEventsDiscardedOutOfViewRange();
661 int dicardedNotVisible
= paramUpdater
.getEventsDiscardedNotVisible();
663 TmfTimeRange range
= request
.getRange();
664 StringBuilder sb
= new StringBuilder("View: " + getName() + ", Events handled: " + count
665 + ", Events loaded in view: " + eventCount
+ ", Number of events discarded: " + discarded
666 + "\n\tNumber of events discarded with start time earlier than next good time: "
667 + discardedOutofOrder
+ "\n\tDiscarded Not visible: " + dicardedNotVisible
668 + "\n\tDiscarded out of view Range: " + discardedOutofViewRange
);
670 sb
.append("\n\t\tRequested Time Range: " + range
.getStartTime() + "-" + range
.getEndTime());
671 sb
.append("\n\t\tExperiment Time Range: " + experimentStartTime
+ "-" + experimentEndTime
);
672 TraceDebug
.debug(sb
.toString());
680 // * Obtains the remainder fraction on unit Seconds of the entered value in
681 // * nanoseconds. e.g. input: 1241207054171080214 ns The number of seconds
683 // * be obtain by removing the last 9 digits: 1241207054 the fractional
684 // * portion of seconds, expressed in ns is: 171080214
689 // protected String formatNs(long v) {
690 // StringBuffer str = new StringBuffer();
691 // boolean neg = v < 0;
697 // String strVal = String.valueOf(v);
698 // if (v < 1000000000) {
702 // // Extract the last nine digits (e.g. fraction of a S expressed in ns
703 // return strVal.substring(strVal.length() - 9);
707 * The request was stopped, the data is incomplete
711 protected abstract void modelIncomplete(ILttngSyntEventRequest request
);
714 * Returns the Event processor instance related to a specific view
718 protected abstract ITransEventProcessor
getEventProcessor();
721 * To be overridden by some sub-classes although may not be needed in some
722 * e.g. statistics view
725 * @param startBoundTime
726 * @param endBoundTime
727 * @param updateTimeBounds
728 * - Time bounds updated needed e.g. if a new Experiment or trace
730 * @param startVisibleWindow
731 * @param endVisibleWindow
734 protected abstract void displayModel(final ITmfTimeAnalysisEntry
[] items
, final long startBoundTime
,
735 final long endBoundTime
, final boolean updateTimeBounds
, final long startVisibleWindow
,
736 final long endVisibleWindow
, final Object source
);
739 * To be overridden by some sub-classes although may not be needed in some
740 * e.g. statistics view
744 protected abstract ParamsUpdater
getParamsUpdater();
747 * Returns the model's item container
751 protected abstract ItemContainer
<?
> getItemContainer();
754 * Returns LTTng Synthetic Provider ID used for current view
758 protected abstract int getProviderId();