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
.tmf
.event
.TmfEvent
;
30 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
31 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
32 import org
.eclipse
.linuxtools
.tmf
.experiment
.TmfExperiment
;
33 import org
.eclipse
.linuxtools
.tmf
.request
.TmfDataRequest
;
34 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfRangeSynchSignal
;
35 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfSignalHandler
;
36 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfSignalManager
;
37 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfTimeSynchSignal
;
38 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.ITimeAnalysisViewer
;
39 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.TmfTimeScaleSelectionEvent
;
40 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.TmfTimeSelectionEvent
;
41 import org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.timeAnalysis
.model
.ITmfTimeAnalysisEntry
;
42 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
43 import org
.eclipse
.swt
.widgets
.Display
;
47 * Abstract class used as a base for views handling specific time range data
51 * The class handles a single element queue of data requests, i.e. request can
52 * be triggered from different sources e.g. opening a file as well as a new
53 * selected time window
59 public abstract class AbsTimeUpdateView
extends TmfView
implements
60 IRequestStatusListener
{
62 // ========================================================================
64 // ========================================================================
66 * One second in nanoseconds
68 private static final long INITIAL_WINDOW_OFFSET
= 1000000000L; /*
72 // private static final long INITIAL_WINDOW_OFFSET = 100000000L; /* 100 ms
75 * Number of events before a GUI refresh
77 private static final Long INPUT_CHANGED_REFRESH
= 3000L;
78 private static final long DEFAULT_OFFSET
= 0L;
79 private static final int DEFAULT_CHUNK
= 1;
81 protected boolean synch
= true; // time synchronisation, used to be an
83 protected ITimeAnalysisViewer tsfviewer
= null;
85 private LttngSyntEventRequest fCurrentRequest
= null;
87 // ========================================================================
89 // ========================================================================
90 public AbsTimeUpdateView(String viewID
) {
92 // freqState = UiCommonFactory.getQueue(this);
95 // ========================================================================
97 // ========================================================================
101 * @seeorg.eclipse.linuxtools.lttng.state.IStateDataRequestListener#
102 * processingStarted(org.eclipse.linuxtools.lttng.state.StateDataRequest)
105 public synchronized void processingStarted(RequestStartedSignal signal
) {
106 LttngSyntEventRequest request
= signal
.getRequest();
107 if (request
!= null) {
108 // update queue with the id of the current request.
109 // freqState.requestStarted(request);
111 // if there was no new request then this one is still on
112 // prepare for the reception of new data
115 // no new time range for zoom orders
116 TmfTimeRange trange
= null;
117 // Time Range will be used to filter out events which are
118 // not visible in one pixel
119 trange
= request
.getRange();
121 // indicate if the data model needs to be cleared e.g. a new
122 // experiment is being selected
123 boolean clearData
= request
.isclearDataInd();
124 // Indicate if current data needs to be cleared and if so
125 // specify the new experiment time range that applies
126 ModelUpdatePrep(trange
, clearData
);
133 * @seeorg.eclipse.linuxtools.lttng.state.IStateDataRequestListener#
134 * processingCompleted(org.eclipse.linuxtools.lttng.state.StateDataRequest)
137 public void processingCompleted(RequestCompletedSignal signal
) {
138 ILttngSyntEventRequest request
= signal
.getRequest();
140 if (request
== null) {
144 // Update wait cursor
147 // No data refresh actions for cancelled requests.
148 if (request
.isCancelled() || request
.isFailed()) {
149 if (TraceDebug
.isDEBUG()) {
150 TmfTimeRange trange
= request
.getRange();
151 if (request
.isCancelled()) {
152 TraceDebug
.debug("Request cancelled "
153 + trange
.getStartTime() + "-" + trange
.getEndTime()
154 + " Handled Events: " + request
.getSynEventCount()
155 + " " + request
.toString(), 15);
156 } else if (request
.isFailed()) {
157 TraceDebug
.debug("Request Failed " + trange
.getStartTime()
158 + "-" + trange
.getEndTime() + " Handled Events: "
159 + request
.getSynEventCount() + " "
160 + request
.toString());
166 modelInputChanged(request
, true);
171 * Registers as listener of time selection from other views
175 public void synchToTime(TmfTimeSynchSignal signal
) {
177 Object source
= signal
.getSource();
178 if (signal
!= null && source
!= null && source
!= this) {
179 // Internal value is expected in nano seconds.
180 long selectedTime
= signal
.getCurrentTime().getValue();
181 if (tsfviewer
!= null) {
182 tsfviewer
.setSelectedTime(selectedTime
, true, source
);
189 * Process the reception of time window adjustment in this view if the
190 * source of the update is not this view.
193 * @param clearingData
195 public void synchToTimeRange(TmfRangeSynchSignal signal
, boolean clearingData
) {
197 Object source
= signal
.getSource();
198 if (signal
!= null && source
!= null && source
!= this) {
199 // Internal value is expected in nano seconds.
200 TmfTimeRange trange
= signal
.getCurrentRange();
201 TmfExperiment
<?
> experiment
= TmfExperiment
.getCurrentExperiment();
202 if (experiment
== null) {
203 TraceDebug
.debug("Current selected experiment is null");
207 // Clearing of process data is configurable
208 dataRequest(trange
, experiment
.getTimeRange(), clearingData
);
214 * Trigger time synchronisation to other views this method shall be called
215 * when a check has been performed to note that an actual change of time has
216 * been performed vs a pure re-selection of the same time
221 protected void synchTimeNotification(long time
, Object source
) {
222 // if synchronisation selected
224 // Notify other views
225 TmfSignalManager
.dispatchSignal(new TmfTimeSynchSignal(source
, new LttngTimestamp(time
)));
230 * Common implementation of ITmfTimeSelectionListener, not used by all the
231 * views extending this abstract class
235 protected void tsfTmProcessSelEvent(TmfTimeSelectionEvent event
) {
236 Object source
= event
.getSource();
237 if (source
== null) {
241 ParamsUpdater paramUpdater
= getParamsUpdater();
242 Long savedSelTime
= paramUpdater
.getSelectedTime();
244 long selTimens
= event
.getSelectedTime();
246 // make sure the new selected time is different than saved before
248 if (savedSelTime
== null || savedSelTime
!= selTimens
) {
249 // Notify listener views.
250 synchTimeNotification(selTimens
, source
);
252 // Update the parameter updater to save the selected time
253 paramUpdater
.setSelectedTime(selTimens
);
255 if (TraceDebug
.isDEBUG()) {
256 TraceDebug
.debug("Selected Time: " + new LttngTimestamp(selTimens
) + "\n\t\t" + getName());
262 * Common implementation of ITmfTimeScaleSelectionListener, not used by all
263 * the views extending this abstract class
267 protected synchronized void tsfTmProcessTimeScaleEvent(TmfTimeScaleSelectionEvent event
) {
268 // source needed to keep track of source values
269 Object source
= event
.getSource();
271 if (source
!= null) {
272 // Update the parameter updater before carrying out a read request
273 ParamsUpdater paramUpdater
= getParamsUpdater();
274 boolean newParams
= paramUpdater
.processTimeScaleEvent(event
);
277 // Read the updated time window
278 TmfTimeRange trange
= paramUpdater
.getTrange();
279 if (trange
!= null) {
281 // Notify listener views. to perform data requests
282 // upon this notification
283 synchTimeRangeNotification(trange
, paramUpdater
.getSelectedTime(), source
);
290 * Inform registered listeners about the new time range
293 * @param selectedTime
296 protected void synchTimeRangeNotification(TmfTimeRange trange
, Long selectedTime
, Object source
) {
297 // if synchronisation selected
299 // Notify other views
300 TmfSignalManager
.dispatchSignal(new TmfRangeSynchSignal(source
, trange
, new LttngTimestamp(selectedTime
)));
305 * @param zoomedTRange
306 * @param experimentTRange
308 public void dataRequest(TmfTimeRange zoomedTRange
,
309 TmfTimeRange experimentTRange
, boolean clearingData
) {
311 // timeRange is the Experiment time range
312 boolean sent
= processDataRequest(zoomedTRange
, experimentTRange
, clearingData
);
320 * send data request directly e.g. doesn't use a queue
322 * @param requestTrange
324 * @param experimentTRange
328 private boolean processDataRequest(TmfTimeRange requestTrange
,
329 TmfTimeRange experimentTRange
, boolean clearingData
) {
331 if (requestTrange
== null || experimentTRange
== null) {
332 TraceDebug
.debug("Invalid input");
336 // Cancel the currently executing request before starting a new one
337 if (fCurrentRequest
!= null && !fCurrentRequest
.isCompleted()) {
338 System
.out
.println("Cancelling request");
339 // fCurrentRequest.cancel();
342 fCurrentRequest
= new LttngSyntEventRequest(
343 requestTrange
, DEFAULT_OFFSET
, TmfDataRequest
.ALL_DATA
,
344 DEFAULT_CHUNK
, this, experimentTRange
, getEventProcessor()) {
346 Long fCount
= getSynEventCount();
347 ITransEventProcessor processor
= getProcessor();
348 TmfTimestamp frunningTimeStamp
;
354 * org.eclipse.linuxtools.lttng.request.LttngSyntEventRequest#handleData
357 // int handleDataCount = 0;
358 // int handleDataValidCount = 0;
360 public void handleData() {
361 LttngSyntheticEvent
[] result
= getData();
363 TmfEvent evt
= (result
.length
> 0) ? result
[0] : null;
364 // handleDataCount++;
366 // handleDataValidCount++;
367 LttngSyntheticEvent synEvent
= (LttngSyntheticEvent
) evt
;
369 SequenceInd indicator
= synEvent
.getSynType();
370 if (indicator
== SequenceInd
.BEFORE
371 || indicator
== SequenceInd
.AFTER
) {
372 processor
.process(evt
, synEvent
.getTraceModel());
373 } else if (indicator
== SequenceInd
.STARTREQ
) {
374 handleRequestStarted();
375 } else if (indicator
== SequenceInd
.ENDREQ
) {
376 processor
.process(evt
, synEvent
.getTraceModel());
377 // handleCompleted();
380 if (indicator
== SequenceInd
.BEFORE
) {
382 if (fCount
!= 0 && fCount
% INPUT_CHANGED_REFRESH
== 0) {
383 // send partial update
384 modelInputChanged(this, false);
386 if (TraceDebug
.isDEBUG()) {
387 frunningTimeStamp
= evt
.getTimestamp();
388 TraceDebug
.debug("handled: " + fCount
+ " sequence: " + synEvent
.getSynType());
396 public void handleRequestStarted() {
402 // if (TraceDebug.isDEBUG()) {
403 // TraceDebug.debug("AbsTimeUpdateView: Received=" + handleDataCount + ", Valid=" + handleDataCount + ", fCount=" + fCount);
409 public void handleCompleted() {
410 super.handleCompleted();
412 // Data is not complete and should be handled as such
413 if (isFailed() || isCancelled()) {
414 modelIncomplete(this);
417 if (TraceDebug
.isDEBUG()) {
418 if (frunningTimeStamp
!= null) {
419 TraceDebug
.debug("Last event time stamp: "
420 + frunningTimeStamp
.getValue());
426 // obtain singleton core provider
427 LttngSyntheticEventProvider provider
= LttngCoreProviderFactory
430 // send the request to TMF
431 fCurrentRequest
.startRequestInd(provider
);
432 fCurrentRequest
.setclearDataInd(clearingData
);
437 * Returns an initial smaller window to allow the user to select the area of
440 * @param experimentTRange
443 protected TmfTimeRange
getInitTRange(TmfTimeRange experimentTRange
) {
444 TmfTimestamp expStartTime
= experimentTRange
.getStartTime();
445 TmfTimestamp expEndTime
= experimentTRange
.getEndTime();
446 TmfTimestamp initialEndOfWindow
= new LttngTimestamp(expStartTime
448 + INITIAL_WINDOW_OFFSET
);
449 if (initialEndOfWindow
.compareTo(expEndTime
, false) < 0) {
450 return new TmfTimeRange(expStartTime
, initialEndOfWindow
);
453 // The original size of the experiment is smaller than proposed adjusted
455 return experimentTRange
;
459 * Request the Time Analysis widget to enable or disable the wait cursor
460 * e.g. data request in progress or data request completed
464 protected void waitCursor(final boolean waitInd
) {
465 if (tsfviewer
!= null) {
466 Display display
= tsfviewer
.getControl().getDisplay();
468 // Perform the updates on the UI thread
469 display
.asyncExec(new Runnable() {
471 tsfviewer
.waitCursor(waitInd
);
478 * View preparation to override the current local information
481 * - new total time range e.g. Experiment level
482 * @param clearAllData
484 protected void ModelUpdatePrep(TmfTimeRange timeRange
, boolean clearAllData
) {
485 ItemContainer
<?
> itemContainer
= getItemContainer();
487 // start fresh e.g. new experiment selected
488 itemContainer
.clearItems();
490 // clear children but keep processes
491 itemContainer
.clearChildren();
494 // Obtain the current resource array
495 ITmfTimeAnalysisEntry
[] itemArr
= itemContainer
.readItems();
497 // clean up data and boundaries
498 displayModel(itemArr
, -1, -1, false, -1, -1, null);
500 ParamsUpdater updater
= getParamsUpdater();
501 if (updater
!= null) {
503 updater
.setEventsDiscarded(0);
505 // Update new visible time range if available
506 if (timeRange
!= null) {
507 updater
.update(timeRange
.getStartTime().getValue(), timeRange
.getEndTime().getValue());
513 * Initialize the model and view before reloading items
515 * @param boundaryRange
516 * @param visibleRange
519 protected void ModelUpdateInit(TmfTimeRange boundaryRange
, TmfTimeRange visibleRange
, Object source
) {
520 // Update the view boundaries
521 if (boundaryRange
!= null) {
522 ItemContainer
<?
> itemContainer
= getItemContainer();
523 if (itemContainer
!= null) {
524 itemContainer
.clearItems();
525 // Obtain the current process array
526 ITmfTimeAnalysisEntry
[] itemArr
= itemContainer
.readItems();
528 long startTime
= boundaryRange
.getStartTime().getValue();
529 long endTime
= boundaryRange
.getEndTime().getValue();
531 // Update the view part
532 displayModel(itemArr
, startTime
, endTime
, true, visibleRange
.getStartTime().getValue(), visibleRange
533 .getEndTime().getValue(), source
);
537 // update the view filtering parameters
538 if (visibleRange
!= null) {
539 ParamsUpdater updater
= getParamsUpdater();
540 if (updater
!= null) {
542 updater
.setEventsDiscarded(0);
543 // Update new visible time range if available
544 updater
.update(visibleRange
.getStartTime().getValue(), visibleRange
.getEndTime().getValue());
550 * Actions taken by the view to refresh its widget(s) with the updated data
555 * true: yes, false: partial update
557 protected void modelInputChanged(ILttngSyntEventRequest request
, boolean complete
) {
558 long experimentStartTime
= -1;
559 long experimentEndTime
= -1;
560 TmfTimeRange experimentTimeRange
= request
.getExperimentTimeRange();
561 if (experimentTimeRange
!= null) {
562 experimentStartTime
= experimentTimeRange
.getStartTime().getValue();
563 experimentEndTime
= experimentTimeRange
.getEndTime().getValue();
566 // Obtain the current resource list
567 ITmfTimeAnalysisEntry
[] itemArr
= getItemContainer().readItems();
569 if (itemArr
!= null) {
570 // Sort the array by pid
571 Arrays
.sort(itemArr
);
573 // Update the view part
574 displayModel(itemArr
, experimentStartTime
, experimentEndTime
, false, request
.getRange().getStartTime()
575 .getValue(), request
.getRange().getEndTime().getValue(), request
.getSource());
579 // reselect to original time
580 ParamsUpdater paramUpdater
= getParamsUpdater();
581 if (paramUpdater
!= null && tsfviewer
!= null) {
582 final Long selTime
= paramUpdater
.getSelectedTime();
583 if (selTime
!= null) {
584 TraceDebug
.debug("View: " + getName() + "\n\t\tRestoring the selected time to: " + selTime
);
585 Display display
= tsfviewer
.getControl().getDisplay();
586 display
.asyncExec(new Runnable() {
588 tsfviewer
.setSelectedTime(selTime
, false, this);
593 if (TraceDebug
.isDEBUG()) {
595 Long count
= request
.getSynEventCount();
596 for (int pos
= 0; pos
< itemArr
.length
; pos
++) {
597 eventCount
+= itemArr
[pos
].getTraceEvents().size();
600 int discarded
= paramUpdater
.getEventsDiscarded();
601 int discardedOutofOrder
= paramUpdater
.getEventsDiscardedWrongOrder();
602 int discardedOutofViewRange
= paramUpdater
.getEventsDiscardedOutOfViewRange();
603 int dicardedNotVisible
= paramUpdater
.getEventsDiscardedNotVisible();
605 TmfTimeRange range
= request
.getRange();
606 StringBuilder sb
= new StringBuilder("View: " + getName() + ", Events handled: " + count
607 + ", Events loaded in view: " + eventCount
+ ", Number of events discarded: " + discarded
608 + "\n\tNumber of events discarded with start time earlier than next good time: "
609 + discardedOutofOrder
+ "\n\tDiscarded Not visible: " + dicardedNotVisible
610 + "\n\tDiscarded out of view Range: " + discardedOutofViewRange
);
612 sb
.append("\n\t\tRequested Time Range: " + range
.getStartTime() + "-" + range
.getEndTime());
613 sb
.append("\n\t\tExperiment Time Range: " + experimentStartTime
+ "-" + experimentEndTime
);
614 TraceDebug
.debug(sb
.toString());
622 // * Obtains the remainder fraction on unit Seconds of the entered value in
623 // * nanoseconds. e.g. input: 1241207054171080214 ns The number of seconds
625 // * be obtain by removing the last 9 digits: 1241207054 the fractional
626 // * portion of seconds, expressed in ns is: 171080214
631 // protected String formatNs(long v) {
632 // StringBuffer str = new StringBuffer();
633 // boolean neg = v < 0;
639 // String strVal = String.valueOf(v);
640 // if (v < 1000000000) {
644 // // Extract the last nine digits (e.g. fraction of a S expressed in ns
645 // return strVal.substring(strVal.length() - 9);
649 * The request was stopped, the data is incomplete
653 protected abstract void modelIncomplete(ILttngSyntEventRequest request
);
656 * Returns the Event processor instance related to a specific view
660 protected abstract ITransEventProcessor
getEventProcessor();
663 * To be overridden by some sub-classes although may not be needed in some
664 * e.g. statistics view
667 * @param startBoundTime
668 * @param endBoundTime
669 * @param updateTimeBounds
670 * - Time bounds updated needed e.g. if a new Experiment or trace
672 * @param startVisibleWindow
673 * @param endVisibleWindow
676 protected abstract void displayModel(final ITmfTimeAnalysisEntry
[] items
, final long startBoundTime
,
677 final long endBoundTime
, final boolean updateTimeBounds
, final long startVisibleWindow
,
678 final long endVisibleWindow
, final Object source
);
681 * To be overridden by some sub-classes although may not be needed in some
682 * e.g. statistics view
686 protected abstract ParamsUpdater
getParamsUpdater();
689 * Returns the model's item container
693 protected abstract ItemContainer
<?
> getItemContainer();