1 /*******************************************************************************
2 * Copyright (c) 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 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.lttng
.control
;
15 import java
.util
.HashMap
;
18 import org
.eclipse
.linuxtools
.lttng
.TraceDebug
;
19 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEvent
;
20 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEventType
;
21 import org
.eclipse
.linuxtools
.lttng
.event
.LttngSyntheticEvent
;
22 import org
.eclipse
.linuxtools
.lttng
.event
.LttngSyntheticEvent
.SequenceInd
;
23 import org
.eclipse
.linuxtools
.lttng
.event
.LttngTimestamp
;
24 import org
.eclipse
.linuxtools
.lttng
.model
.LTTngTreeNode
;
25 import org
.eclipse
.linuxtools
.lttng
.request
.LttngBaseEventRequest
;
26 import org
.eclipse
.linuxtools
.lttng
.state
.evProcessor
.ITransEventProcessor
;
27 import org
.eclipse
.linuxtools
.lttng
.state
.evProcessor
.state
.StateEventToHandlerFactory
;
28 import org
.eclipse
.linuxtools
.lttng
.state
.model
.LttngTraceState
;
29 import org
.eclipse
.linuxtools
.lttng
.state
.trace
.IStateTraceManager
;
30 import org
.eclipse
.linuxtools
.tmf
.component
.TmfEventProvider
;
31 import org
.eclipse
.linuxtools
.tmf
.event
.TmfEventSource
;
32 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
33 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
34 import org
.eclipse
.linuxtools
.tmf
.experiment
.TmfExperiment
;
35 import org
.eclipse
.linuxtools
.tmf
.request
.ITmfDataRequest
;
36 import org
.eclipse
.linuxtools
.tmf
.request
.ITmfEventRequest
;
37 import org
.eclipse
.linuxtools
.tmf
.request
.TmfDataRequest
;
38 import org
.eclipse
.linuxtools
.tmf
.request
.TmfEventRequest
;
39 import org
.eclipse
.linuxtools
.tmf
.trace
.ITmfContext
;
40 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfContext
;
41 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfTrace
;
47 public class LttngSyntheticEventProvider
extends
48 TmfEventProvider
<LttngSyntheticEvent
> {
50 // ========================================================================
52 // ========================================================================
53 public static final int BLOCK_SIZE
= 1;
54 public static final int NB_EVENTS
= 1;
55 public static final int QUEUE_SIZE
= 1; // lttng specific, one event at a
58 // TmfDataProvider<LttngEvent> fExtProvider = null;
59 private ITmfDataRequest
<LttngSyntheticEvent
> fmainRequest
= null;
60 private final Map
<IStateTraceManager
, LttngBaseEventRequest
> feventProviderRequests
= new HashMap
<IStateTraceManager
, LttngBaseEventRequest
>();
61 private final LttngSyntheticEvent fStatusEvent
;
62 private final LttngSyntheticEvent fStatusEventAck
;
63 private int fmainReqEventCount
= 0;
64 volatile boolean startIndSent
= false;
65 private LTTngTreeNode fExperiment
= null;
66 private ITransEventProcessor fstateUpdateProcessor
= StateEventToHandlerFactory
68 private boolean waitForRequest
= false;
70 // ========================================================================
72 // ========================================================================
74 * Accessibility to package - use factory instead of this constructor
78 LttngSyntheticEventProvider(Class
<LttngSyntheticEvent
> type
) {
79 super("LttngSyntheticEventProvider", type
, QUEUE_SIZE
);
81 // prepare empty instance status indicators and allow them to travel via
83 TmfEventSource source
= new TmfEventSource(this);
84 LttngEventType dtype
= new LttngEventType();
85 LttngTimestamp statusTimeStamp
= new LttngTimestamp(
86 TmfTimestamp
.BigBang
);
88 fStatusEvent
= new LttngSyntheticEvent(null, statusTimeStamp
, source
,
89 dtype
, null, null, null);
90 fStatusEvent
.setSequenceInd(SequenceInd
.STARTREQ
);
92 fStatusEventAck
= new LttngSyntheticEvent(null, statusTimeStamp
,
93 source
, dtype
, null, null, null);
94 fStatusEventAck
.setSequenceInd(SequenceInd
.ACK
);
97 // ========================================================================
99 // ========================================================================
100 @SuppressWarnings("unchecked")
102 public ITmfContext
armRequest(
103 final ITmfDataRequest
<LttngSyntheticEvent
> request
) {
105 // make sure we have the right type of request
106 if (!(request
instanceof ITmfEventRequest
<?
>)) {
108 TraceDebug
.debug("Request is not an instance of ITmfEventRequest");
112 if (fExperiment
== null) {
113 TraceDebug
.debug("Experiment is null");
118 // get ready to start processing
121 // At least one base provider shall be available
122 if (feventProviderRequests
.size() < 1) {
124 TraceDebug
.debug("No Base event providers available");
128 fmainRequest
= request
;
129 // define event data handling
130 ITmfEventRequest
<LttngSyntheticEvent
> eventRequest
= (ITmfEventRequest
<LttngSyntheticEvent
>) fmainRequest
;
131 TmfTimeRange reqWindow
= eventRequest
.getRange();
133 TraceDebug
.debug("Main Synthethic event request started on thread: " + Thread
.currentThread().getName());
135 // loop for every traceManager in current experiment
136 for (IStateTraceManager traceManager
: feventProviderRequests
139 // restore trace state system to nearest check point
140 TmfTimestamp checkPoint
= traceManager
141 .restoreCheckPointByTimestamp(reqWindow
.getStartTime());
142 // validate so checkpoint restore is within requested bounds
143 TmfTimeRange traceRange
= traceManager
.getTrace().getTimeRange();
144 if (!(checkPoint
.getValue() >= traceRange
.getStartTime().getValue()
145 && checkPoint
.getValue() <= traceRange
.getEndTime()
146 .getValue() && checkPoint
.getValue() < reqWindow
147 .getEndTime().getValue())) {
148 // checkpoint is out of trace bounds
152 // adjust start time bound to check point
153 TmfTimeRange adjustedRange
= new TmfTimeRange(checkPoint
, reqWindow
156 LttngTraceState traceModel
= traceManager
.getStateModel();
157 // create sub-request for one trace within experiment
158 final LttngBaseEventRequest subRequest
= new LttngBaseEventRequest(
159 adjustedRange
, reqWindow
.getStartTime(), 0,
160 TmfEventRequest
.ALL_DATA
, BLOCK_SIZE
, traceModel
) {
162 private LttngSyntheticEvent syntheticEvent
= null;
163 private LttngSyntheticEvent syntheticAckIndicator
= null;
164 long subEventCount
= 0L;
166 private final long fDispatchTime
= getDispatchTime().getValue();
167 private final LttngTraceState fTraceModel
= getTraceModel();
173 * org.eclipse.linuxtools.lttng.control.LttngEventRequest#handleData
177 public void handleData() {
178 LttngEvent
[] events
= getData();
179 if (events
.length
> 0) {
180 for (LttngEvent e
: events
) {
181 handleIncomingData(e
);
184 TraceDebug
.debug("handle data received with no data");
192 * @see org.eclipse.linuxtools.tmf.request.TmfDataRequest#done()
196 // mark this sub-request as completed
198 handleProviderDone(getTraceModel());
202 * Trigger the Analysis and sequential control of the events.
206 private void handleIncomingData(LttngEvent e
) {
207 long eventTime
= e
.getTimestamp().getValue();
209 // if (eventTime == 13589777932952L) {
210 // // syscall entry id 78 expected
211 // System.out.println("debug mark at 13589777932952L");
214 // queue the new event data and an ACK
219 // If time at or above requested time, update application
220 if (eventTime
>= fDispatchTime
) {
222 syntheticEvent
.setSequenceInd(SequenceInd
.BEFORE
);
223 queueResult(syntheticEvent
);
224 queueResult(syntheticAckIndicator
);
226 // Update state locally
227 syntheticEvent
.setSequenceInd(SequenceInd
.UPDATE
);
228 fstateUpdateProcessor
.process(syntheticEvent
,
232 syntheticEvent
.setSequenceInd(SequenceInd
.AFTER
);
233 queueResult(syntheticEvent
);
234 queueResult(syntheticAckIndicator
);
236 // increment once per dispatch
237 incrementSynEvenCount();
240 // event time is between checkpoint adjusted time and
241 // requested time i.e. application does not expect the
242 // event, however the state system needs to be re-built
243 // to the dispatch point
244 syntheticEvent
.setSequenceInd(SequenceInd
.UPDATE
);
245 fstateUpdateProcessor
.process(syntheticEvent
,
251 * Create a synthetic event from the received new reference, if
252 * the reference is the same there is no need for a new instance
254 * if this is the first event for this request, call start
260 private LttngSyntheticEvent
updateSynEvent(LttngEvent e
) {
261 if (syntheticEvent
== null
262 || syntheticEvent
.getBaseEvent() != e
) {
263 syntheticEvent
= new LttngSyntheticEvent(e
);
264 syntheticAckIndicator
= new LttngSyntheticEvent(e
);
265 syntheticAckIndicator
.setSequenceInd(SequenceInd
.ACK
);
268 // Trace model needed by application handlers
269 syntheticEvent
.setTraceModel(fTraceModel
);
271 // send the start request indication once per request thread
273 TraceDebug
.debug("Thread started: " + Thread
.currentThread().getName());
274 handleProviderStarted(getTraceModel());
278 return syntheticEvent
;
282 // preserve the associated sub request to control it e.g.
284 feventProviderRequests
.put(traceManager
, subRequest
);
287 TmfTrace
<LttngEvent
> provider
= (TmfTrace
<LttngEvent
>) traceManager
289 provider
.sendRequest(subRequest
);
292 // Return a dummy context, not used for relay provider
293 return new TmfContext();
297 * Notify listeners to prepare to receive data e.g. clean previous data etc.
299 public void handleProviderStarted(LttngTraceState traceModel
) {
300 LttngSyntheticEvent startIndEvent
= new LttngSyntheticEvent(
302 startIndEvent
.setSequenceInd(SequenceInd
.STARTREQ
);
304 // Notify application
305 queueResult(startIndEvent
);
306 queueResult(fStatusEventAck
);
308 // Notify state event processor
309 fstateUpdateProcessor
.process(startIndEvent
, null);
313 * Notify listeners, no more events for the current request will be
314 * distributed e.g. update view.
316 public synchronized void handleProviderDone(LttngTraceState traceModel
) {
317 // TODO: The use of a thread per main request and thread per sub-request
319 // to make sure the proper main request is marked completed. So a
320 // relationship of sub-requests to parent needs to be established to
321 // handle completion and cancellations properly
323 // Close the main request when all sub-requests are marked completed
324 for (LttngBaseEventRequest subRequest
: feventProviderRequests
.values()) {
325 if (subRequest
!= null) {
326 if (!subRequest
.isCompleted()) {
327 // Not ready to complete main request
333 // All sub-requests are marked completed so the main request can be
335 // Notify application,
336 LttngSyntheticEvent finishEvent
= new LttngSyntheticEvent(fStatusEvent
);
337 finishEvent
.setSequenceInd(SequenceInd
.ENDREQ
);
338 finishEvent
.setTraceModel(traceModel
);
339 queueResult(finishEvent
);
340 queueResult(fStatusEventAck
);
341 // End the loop in the main request
342 queueResult(LttngSyntheticEvent
.NullEvent
);
346 * Increment the global event counter i.e. events from any sub requests
348 private synchronized void incrementSynEvenCount() {
349 fmainReqEventCount
++;
355 public synchronized int getSynEvenCount() {
356 return fmainReqEventCount
;
360 * Reset provider to a state ready to begin thread execution
362 * @param experimentNode
364 public /* synchronized */ void reset(LTTngTreeNode experimentNode
) {
368 // Make sure previous request are terminated
369 for (LttngBaseEventRequest tmpRequest
: feventProviderRequests
.values()) {
370 if (tmpRequest
!= null && !tmpRequest
.isCompleted()) {
375 feventProviderRequests
.clear();
376 fmainReqEventCount
= 0;
377 startIndSent
= false;
379 // set of base event providers
380 if (fExperiment
!= null) {
381 LTTngTreeNode
[] traces
= fExperiment
.getChildren();
382 for (LTTngTreeNode trace
: traces
) {
383 IStateTraceManager traceBaseEventProvider
= (IStateTraceManager
) trace
;
384 feventProviderRequests
.put(traceBaseEventProvider
, null);
388 if (fExperiment
!= experimentNode
) {
389 updateExperimentNode(experimentNode
);
394 * Point to a new experiment reference
398 private synchronized void updateExperimentNode(LTTngTreeNode experiment
) {
399 if (experiment
!= null
400 && experiment
.getValue() instanceof TmfExperiment
<?
>) {
401 fExperiment
= experiment
;
404 .debug("Experiment received is not instance of TmfExperiment: "
405 + experiment
.getClass().getName());
413 * org.eclipse.linuxtools.tmf.component.TmfDataProvider#sendRequest(org.
414 * eclipse.linuxtools.tmf.request.TmfDataRequest)
416 public void sendRequest(final TmfDataRequest
<LttngSyntheticEvent
> request
) {
417 super.sendRequest(request
);
418 if (waitForRequest
) {
420 request
.waitForCompletion();
421 } catch (InterruptedException e
) {
428 * @return the waitForRequest
430 public boolean isWaitForRequest() {
431 return waitForRequest
;
435 * @param waitForRequest
436 * configures the provider to wait for the request completion
438 public void setWaitForRequest(boolean waitForRequest
) {
439 this.waitForRequest
= waitForRequest
;