Commit | Line | Data |
---|---|---|
5d10d135 ASL |
1 | /******************************************************************************* |
2 | * Copyright (c) 2010 Ericsson | |
3 | * | |
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 | |
8 | * | |
9 | * Contributors: | |
10 | * Alvaro Sanchez-Leon (alvsan09@gmail.com) - Initial API and implementation | |
3f2b9283 | 11 | * Marc Dumais (marc.dumais@ericsson.com) - Fix for 316455 (first part) |
5d10d135 ASL |
12 | *******************************************************************************/ |
13 | ||
14 | package org.eclipse.linuxtools.lttng.control; | |
15 | ||
16 | import java.util.HashMap; | |
3f2b9283 FC |
17 | import java.util.Iterator; |
18 | import java.util.List; | |
5d10d135 | 19 | import java.util.Map; |
3f2b9283 | 20 | import java.util.Vector; |
5d10d135 ASL |
21 | |
22 | import org.eclipse.linuxtools.lttng.TraceDebug; | |
23 | import org.eclipse.linuxtools.lttng.event.LttngEvent; | |
24 | import org.eclipse.linuxtools.lttng.event.LttngEventType; | |
25 | import org.eclipse.linuxtools.lttng.event.LttngSyntheticEvent; | |
26 | import org.eclipse.linuxtools.lttng.event.LttngSyntheticEvent.SequenceInd; | |
27 | import org.eclipse.linuxtools.lttng.event.LttngTimestamp; | |
28 | import org.eclipse.linuxtools.lttng.model.LTTngTreeNode; | |
29 | import org.eclipse.linuxtools.lttng.request.LttngBaseEventRequest; | |
30 | import org.eclipse.linuxtools.lttng.state.evProcessor.ITransEventProcessor; | |
31 | import org.eclipse.linuxtools.lttng.state.evProcessor.state.StateEventToHandlerFactory; | |
32 | import org.eclipse.linuxtools.lttng.state.model.LttngTraceState; | |
33 | import org.eclipse.linuxtools.lttng.state.trace.IStateTraceManager; | |
34 | import org.eclipse.linuxtools.tmf.component.TmfEventProvider; | |
35 | import org.eclipse.linuxtools.tmf.event.TmfEventSource; | |
36 | import org.eclipse.linuxtools.tmf.event.TmfTimeRange; | |
37 | import org.eclipse.linuxtools.tmf.event.TmfTimestamp; | |
38 | import org.eclipse.linuxtools.tmf.experiment.TmfExperiment; | |
39 | import org.eclipse.linuxtools.tmf.request.ITmfDataRequest; | |
40 | import org.eclipse.linuxtools.tmf.request.ITmfEventRequest; | |
5d10d135 | 41 | import org.eclipse.linuxtools.tmf.request.TmfEventRequest; |
9b635e61 FC |
42 | import org.eclipse.linuxtools.tmf.signal.TmfEndSynchSignal; |
43 | import org.eclipse.linuxtools.tmf.signal.TmfStartSynchSignal; | |
5d10d135 | 44 | import org.eclipse.linuxtools.tmf.trace.ITmfContext; |
9b635e61 | 45 | import org.eclipse.linuxtools.tmf.trace.ITmfTrace; |
5d10d135 ASL |
46 | import org.eclipse.linuxtools.tmf.trace.TmfContext; |
47 | import org.eclipse.linuxtools.tmf.trace.TmfTrace; | |
48 | ||
49 | /** | |
50 | * @author alvaro | |
51 | * | |
52 | */ | |
a72a38d9 | 53 | public class LttngSyntheticEventProvider extends TmfEventProvider<LttngSyntheticEvent> { |
5d10d135 ASL |
54 | |
55 | // ======================================================================== | |
56 | // Data | |
57 | // ======================================================================== | |
58 | public static final int BLOCK_SIZE = 1; | |
3d62f8b7 | 59 | public static final int NB_EVENTS = 1; |
f9673903 | 60 | public static final int QUEUE_SIZE = 1; // lttng specific, one event at a time |
5d10d135 | 61 | |
5d10d135 | 62 | private ITmfDataRequest<LttngSyntheticEvent> fmainRequest = null; |
c1c69938 FC |
63 | private LttngBaseEventRequest fSubRequest = null; |
64 | ||
3f2b9283 FC |
65 | private final List<IStateTraceManager> fEventProviderRequests = new Vector<IStateTraceManager>(); |
66 | ||
5d10d135 | 67 | private final LttngSyntheticEvent fStatusEvent; |
5d10d135 ASL |
68 | volatile boolean startIndSent = false; |
69 | private LTTngTreeNode fExperiment = null; | |
3f2b9283 | 70 | private ITransEventProcessor fstateUpdateProcessor = StateEventToHandlerFactory.getInstance(); |
5d10d135 | 71 | private boolean waitForRequest = false; |
3f2b9283 FC |
72 | long dispatchTime = 0L; |
73 | private final Map<ITmfTrace, LttngTraceState> traceToTraceStateModel = new HashMap<ITmfTrace, LttngTraceState>(); | |
5d10d135 | 74 | |
c1c69938 FC |
75 | private boolean fIsExperimentNotified = false; |
76 | ||
5d10d135 ASL |
77 | // ======================================================================== |
78 | // Constructor | |
79 | // ======================================================================== | |
80 | /** | |
81 | * Accessibility to package - use factory instead of this constructor | |
82 | * | |
83 | * @param type | |
84 | */ | |
85 | LttngSyntheticEventProvider(Class<LttngSyntheticEvent> type) { | |
86 | super("LttngSyntheticEventProvider", type, QUEUE_SIZE); | |
87 | ||
88 | // prepare empty instance status indicators and allow them to travel via | |
89 | // the framework | |
90 | TmfEventSource source = new TmfEventSource(this); | |
91 | LttngEventType dtype = new LttngEventType(); | |
f9673903 FC |
92 | LttngTimestamp statusTimeStamp = new LttngTimestamp( |
93 | TmfTimestamp.Zero); | |
5d10d135 | 94 | |
f9673903 FC |
95 | fStatusEvent = new LttngSyntheticEvent(null, statusTimeStamp, source, |
96 | dtype, null, null, null); | |
5d10d135 | 97 | fStatusEvent.setSequenceInd(SequenceInd.STARTREQ); |
5d10d135 ASL |
98 | } |
99 | ||
100 | // ======================================================================== | |
101 | // Methods | |
102 | // ======================================================================== | |
550d787e | 103 | |
5d10d135 ASL |
104 | @SuppressWarnings("unchecked") |
105 | @Override | |
3f2b9283 | 106 | public ITmfContext armRequest(final ITmfDataRequest<LttngSyntheticEvent> request) { |
5d10d135 ASL |
107 | // validate |
108 | // make sure we have the right type of request | |
109 | if (!(request instanceof ITmfEventRequest<?>)) { | |
110 | request.cancel(); | |
111 | TraceDebug.debug("Request is not an instance of ITmfEventRequest"); | |
112 | return null; | |
113 | } | |
114 | ||
115 | if (fExperiment == null) { | |
116 | TraceDebug.debug("Experiment is null"); | |
117 | request.cancel(); | |
118 | return null; | |
119 | } | |
120 | ||
121 | // get ready to start processing | |
122 | reset(fExperiment); | |
123 | ||
124 | // At least one base provider shall be available | |
550d787e | 125 | if (fEventProviderRequests.size() < 1) { |
5d10d135 ASL |
126 | request.cancel(); |
127 | TraceDebug.debug("No Base event providers available"); | |
128 | return null; | |
129 | } | |
130 | ||
131 | fmainRequest = request; | |
c1c69938 | 132 | |
5d10d135 ASL |
133 | // define event data handling |
134 | ITmfEventRequest<LttngSyntheticEvent> eventRequest = (ITmfEventRequest<LttngSyntheticEvent>) fmainRequest; | |
135 | TmfTimeRange reqWindow = eventRequest.getRange(); | |
550d787e | 136 | |
5d10d135 ASL |
137 | TraceDebug.debug("Main Synthethic event request started on thread: " + Thread.currentThread().getName()); |
138 | ||
9b635e61 FC |
139 | TmfExperiment<LttngEvent> experiment = (TmfExperiment<LttngEvent>) fExperiment.getValue(); |
140 | experiment.startSynch(new TmfStartSynchSignal(0)); | |
3f2b9283 FC |
141 | |
142 | TmfTimeRange adjustedRange = reqWindow; | |
143 | ||
144 | // Figure-out if we need to increase the range of the request: if some | |
145 | // checkpoints are before the beginning of the range, increase the | |
146 | // range to catch them. We will then exercise the state system of | |
147 | // those traces until the requested beginning time range, discarding | |
148 | // the unrequested data. | |
149 | IStateTraceManager traceManager; | |
150 | Iterator<IStateTraceManager> iter = fEventProviderRequests.iterator(); | |
151 | // For each traceManager in the current experiment... | |
152 | while(iter.hasNext()) { | |
153 | traceManager = iter.next(); | |
5d10d135 | 154 | // restore trace state system to nearest check point |
f9673903 FC |
155 | TmfTimestamp checkPoint = traceManager |
156 | .restoreCheckPointByTimestamp(reqWindow.getStartTime()); | |
550d787e | 157 | |
3f2b9283 FC |
158 | // validate that the checkpoint restored is within requested bounds |
159 | // (not outside the current trace's range or after the end of requested range) | |
5d10d135 | 160 | TmfTimeRange traceRange = traceManager.getTrace().getTimeRange(); |
550d787e FC |
161 | if ((checkPoint != null) && !( |
162 | checkPoint.getValue() >= traceRange.getStartTime().getValue() && | |
163 | checkPoint.getValue() <= traceRange.getEndTime().getValue() && | |
164 | checkPoint.getValue() < reqWindow.getEndTime().getValue()) | |
165 | ) { | |
3f2b9283 FC |
166 | // checkpoint is out of trace bounds; no need to adjust request for this |
167 | // trace | |
168 | } | |
169 | else { | |
170 | // use checkpoint time as new startTime for request if it's earlier than | |
171 | // current startTime | |
172 | if (checkPoint != null && adjustedRange.getStartTime().getValue() > checkPoint.getValue()) { | |
173 | adjustedRange = new TmfTimeRange(checkPoint, reqWindow.getEndTime()); | |
174 | } | |
175 | } | |
176 | // Save which trace state model corresponds to current trace | |
177 | traceToTraceStateModel.put(traceManager.getTrace(), traceManager.getStateModel()); | |
178 | } | |
c1c69938 | 179 | |
3f2b9283 | 180 | dispatchTime = reqWindow.getStartTime().getValue(); |
c1c69938 | 181 | |
3f2b9283 | 182 | // Create a single request for all traces in the experiment, with coalesced time range. |
c1c69938 FC |
183 | fSubRequest = new LttngBaseEventRequest(adjustedRange, reqWindow.getStartTime(), |
184 | 0, TmfEventRequest.ALL_DATA, BLOCK_SIZE, eventRequest.getExecType() /*ITmfDataRequest.ExecutionType.FOREGROUND*/) { | |
3f2b9283 FC |
185 | |
186 | private LttngSyntheticEvent syntheticEvent = null; | |
3f2b9283 FC |
187 | |
188 | /* | |
189 | * (non-Javadoc) | |
190 | * | |
191 | * @see org.eclipse.linuxtools.lttng.control.LttngEventRequest#handleData() | |
192 | */ | |
193 | @Override | |
194 | public void handleData(LttngEvent event) { | |
195 | super.handleData(event); | |
196 | if (event != null) { | |
c1c69938 FC |
197 | synchronized (LttngSyntheticEventProvider.this) { |
198 | // Check if request was canceled | |
199 | if ((fmainRequest == null) || (fmainRequest.isCompleted()) ) { | |
200 | TraceDebug.debug("fmainRequest was canceled. Ignoring event " + event); | |
201 | return; | |
202 | } | |
203 | ||
204 | handleIncomingData(event); | |
205 | } | |
3f2b9283 FC |
206 | } else { |
207 | TraceDebug.debug("handle data received with no data"); | |
208 | } | |
5d10d135 | 209 | } |
3f2b9283 FC |
210 | |
211 | /* | |
212 | * (non-Javadoc) | |
213 | * | |
c1c69938 | 214 | * @see org.eclipse.linuxtools.tmf.request.TmfDataRequest#handleCompleted() |
3f2b9283 FC |
215 | */ |
216 | @Override | |
c1c69938 | 217 | public void handleCompleted() { |
3f2b9283 | 218 | // mark this sub-request as completed |
c1c69938 FC |
219 | handleProviderDone(!isCancelled() && !isFailed()); |
220 | super.handleCompleted(); | |
550d787e | 221 | } |
5d10d135 | 222 | |
3f2b9283 FC |
223 | /** |
224 | * Trigger the Analysis and sequential control of the events. | |
225 | * | |
226 | * @param e | |
227 | */ | |
228 | private void handleIncomingData(LttngEvent e) { | |
229 | long eventTime = e.getTimestamp().getValue(); | |
230 | ||
231 | TmfTrace<LttngEvent> inTrace = e.getParentTrace(); | |
232 | LttngTraceState traceModel = traceToTraceStateModel.get(inTrace); | |
233 | ||
c1c69938 | 234 | // queue the new event data |
3f2b9283 FC |
235 | updateSynEvent(e); |
236 | ||
237 | // If time at or above requested time, update application | |
238 | if (eventTime >= dispatchTime) { | |
239 | // Before update | |
240 | syntheticEvent.setSequenceInd(SequenceInd.BEFORE); | |
241 | fmainRequest.handleData(syntheticEvent); | |
3f2b9283 FC |
242 | |
243 | // Update state locally | |
244 | syntheticEvent.setSequenceInd(SequenceInd.UPDATE); | |
245 | fstateUpdateProcessor.process(syntheticEvent, traceModel); | |
246 | ||
247 | // After Update | |
248 | syntheticEvent.setSequenceInd(SequenceInd.AFTER); | |
249 | fmainRequest.handleData(syntheticEvent); | |
3f2b9283 | 250 | |
3f2b9283 FC |
251 | } else { |
252 | // event time is between checkpoint adjusted time and | |
253 | // requested time i.e. application does not expect the | |
254 | // event, however the state system needs to be re-built | |
255 | // to the dispatch point | |
256 | syntheticEvent.setSequenceInd(SequenceInd.UPDATE); | |
257 | fstateUpdateProcessor.process(syntheticEvent, traceModel); | |
5d10d135 | 258 | } |
3f2b9283 FC |
259 | } |
260 | ||
261 | /** | |
262 | * Create a synthetic event from the received new reference, if | |
263 | * the reference is the same there is no need for a new instance | |
264 | * | |
265 | * if this is the first event for this request, call start | |
266 | * handler | |
267 | * | |
268 | * @param e | |
269 | * @return | |
270 | */ | |
271 | private LttngSyntheticEvent updateSynEvent(LttngEvent e) { | |
c1c69938 | 272 | if ((syntheticEvent == null) || (syntheticEvent.getBaseEvent() != e)) { |
3f2b9283 | 273 | syntheticEvent = new LttngSyntheticEvent(e); |
5d10d135 | 274 | } |
3f2b9283 FC |
275 | |
276 | TmfTrace<LttngEvent> inTrace = e.getParentTrace(); | |
277 | LttngTraceState traceModel = traceToTraceStateModel.get(inTrace); | |
f9673903 | 278 | |
3f2b9283 FC |
279 | // Trace model needed by application handlers |
280 | syntheticEvent.setTraceModel(traceModel); | |
281 | ||
282 | // send the start request indication once per request thread | |
283 | if (!startIndSent) { | |
284 | TraceDebug.debug("Thread started: " + Thread.currentThread().getName()); | |
285 | handleProviderStarted(traceModel); | |
286 | startIndSent = true; | |
5d10d135 ASL |
287 | } |
288 | ||
3f2b9283 FC |
289 | return syntheticEvent; |
290 | } | |
291 | }; | |
292 | ||
293 | // start request | |
294 | TmfExperiment<LttngEvent> provider = (TmfExperiment<LttngEvent>) fExperiment.getValue(); | |
c1c69938 | 295 | provider.sendRequest(fSubRequest); |
3f2b9283 | 296 | |
c1c69938 FC |
297 | // notify LTTngEvent provider that all requests were sent |
298 | synchronized (this) { | |
299 | TmfExperiment.getCurrentExperiment().notifyPendingRequest(false); | |
300 | fIsExperimentNotified = false; | |
301 | } | |
5d10d135 | 302 | |
9b635e61 FC |
303 | experiment.endSynch(new TmfEndSynchSignal(0)); |
304 | ||
5d10d135 | 305 | // Return a dummy context, not used for relay provider |
c1c69938 | 306 | return new TmfContext(); |
5d10d135 ASL |
307 | } |
308 | ||
309 | /** | |
310 | * Notify listeners to prepare to receive data e.g. clean previous data etc. | |
311 | */ | |
c1c69938 | 312 | public synchronized void handleProviderStarted(LttngTraceState traceModel) { |
3d62f8b7 | 313 | LttngSyntheticEvent startIndEvent = new LttngSyntheticEvent(fStatusEvent); |
5d10d135 ASL |
314 | startIndEvent.setSequenceInd(SequenceInd.STARTREQ); |
315 | ||
316 | // Notify application | |
f9673903 | 317 | fmainRequest.handleData(startIndEvent); |
5d10d135 ASL |
318 | |
319 | // Notify state event processor | |
320 | fstateUpdateProcessor.process(startIndEvent, null); | |
321 | } | |
322 | ||
323 | /** | |
f9673903 FC |
324 | * Notify listeners, no more events for the current request will be |
325 | * distributed e.g. update view. | |
5d10d135 | 326 | */ |
c1c69938 | 327 | public synchronized void handleProviderDone(boolean isSuccess) { |
3f2b9283 FC |
328 | // Notify application. One notification per trace so the last state of each trace can be |
329 | // drawn | |
c1c69938 FC |
330 | for (LttngTraceState traceModel : traceToTraceStateModel.values()) { |
331 | // Take the trace model from traceToTraceStateModel list since it has a copy | |
332 | // of the state | |
333 | LttngSyntheticEvent finishEvent = new LttngSyntheticEvent(fStatusEvent); | |
334 | finishEvent.setSequenceInd(SequenceInd.ENDREQ); | |
335 | finishEvent.setTraceModel(traceModel); | |
336 | ||
337 | fmainRequest.handleData(finishEvent); | |
338 | } | |
339 | ||
340 | if(isSuccess) { | |
341 | // Finish main request | |
342 | fmainRequest.done(); | |
343 | } | |
344 | else { | |
345 | // Cancel main request | |
346 | fmainRequest.cancel(); | |
347 | ||
348 | } | |
5d10d135 ASL |
349 | } |
350 | ||
351 | /** | |
352 | * Reset provider to a state ready to begin thread execution | |
353 | * | |
354 | * @param experimentNode | |
355 | */ | |
550d787e | 356 | public synchronized void reset(LTTngTreeNode experimentNode) { |
c1c69938 FC |
357 | |
358 | conditionallyCancelRequests(); | |
5d10d135 | 359 | |
550d787e | 360 | fEventProviderRequests.clear(); |
5d10d135 ASL |
361 | startIndSent = false; |
362 | ||
363 | // set of base event providers | |
364 | if (fExperiment != null) { | |
365 | LTTngTreeNode[] traces = fExperiment.getChildren(); | |
366 | for (LTTngTreeNode trace : traces) { | |
367 | IStateTraceManager traceBaseEventProvider = (IStateTraceManager) trace; | |
3f2b9283 | 368 | fEventProviderRequests.add(traceBaseEventProvider); |
5d10d135 ASL |
369 | } |
370 | } | |
371 | ||
372 | if (fExperiment != experimentNode) { | |
373 | updateExperimentNode(experimentNode); | |
374 | } | |
375 | } | |
376 | ||
377 | /** | |
378 | * Point to a new experiment reference | |
379 | * | |
380 | * @param experiment | |
381 | */ | |
382 | private synchronized void updateExperimentNode(LTTngTreeNode experiment) { | |
f9673903 FC |
383 | if (experiment != null |
384 | && experiment.getValue() instanceof TmfExperiment<?>) { | |
5d10d135 ASL |
385 | fExperiment = experiment; |
386 | } else { | |
387 | TraceDebug | |
f9673903 FC |
388 | .debug("Experiment received is not instance of TmfExperiment: " |
389 | + experiment.getClass().getName()); | |
5d10d135 ASL |
390 | } |
391 | } | |
392 | ||
393 | /* | |
394 | * (non-Javadoc) | |
395 | * | |
f9673903 FC |
396 | * @see |
397 | * org.eclipse.linuxtools.tmf.component.TmfDataProvider#sendRequest(org. | |
5d10d135 ASL |
398 | * eclipse.linuxtools.tmf.request.TmfDataRequest) |
399 | */ | |
cb866e08 | 400 | @Override |
550d787e | 401 | public void sendRequest(final ITmfDataRequest<LttngSyntheticEvent> request) { |
c1c69938 FC |
402 | synchronized (this) { |
403 | if (!fIsExperimentNotified) { | |
404 | @SuppressWarnings("unchecked") | |
405 | TmfExperiment<LttngSyntheticEvent> experiment = (TmfExperiment<LttngSyntheticEvent>) TmfExperiment.getCurrentExperiment(); | |
406 | if (experiment != null) { | |
407 | experiment.notifyPendingRequest(true); | |
408 | fIsExperimentNotified = true; | |
409 | } | |
410 | } | |
411 | } | |
412 | ||
5d10d135 ASL |
413 | super.sendRequest(request); |
414 | if (waitForRequest) { | |
415 | try { | |
416 | request.waitForCompletion(); | |
417 | } catch (InterruptedException e) { | |
418 | e.printStackTrace(); | |
419 | } | |
420 | } | |
421 | } | |
422 | ||
423 | /** | |
424 | * @return the waitForRequest | |
425 | */ | |
426 | public boolean isWaitForRequest() { | |
427 | return waitForRequest; | |
428 | } | |
429 | ||
430 | /** | |
431 | * @param waitForRequest | |
432 | * configures the provider to wait for the request completion | |
433 | */ | |
434 | public void setWaitForRequest(boolean waitForRequest) { | |
435 | this.waitForRequest = waitForRequest; | |
436 | } | |
437 | ||
cb866e08 | 438 | @Override |
3d62f8b7 FC |
439 | public LttngSyntheticEvent getNext(ITmfContext context) { |
440 | try { | |
441 | fmainRequest.waitForCompletion(); | |
442 | } catch (InterruptedException e) { | |
443 | e.printStackTrace(); | |
444 | } | |
445 | return null; | |
cb866e08 FC |
446 | } |
447 | ||
c1c69938 FC |
448 | /** |
449 | * Cancels the ongoing requests for this data provider if necessary | |
450 | */ | |
451 | public synchronized void conditionallyCancelRequests() { | |
452 | if ((fSubRequest != null) && (!fSubRequest.isCompleted())) { | |
453 | ||
454 | TraceDebug.debug("Canceling synthethic event request!"); | |
455 | ||
456 | // This will also cancel the fmainRequest | |
457 | fSubRequest.cancel(); | |
458 | // Reset the request references | |
459 | fSubRequest = null; | |
460 | fmainRequest = null; | |
461 | } | |
462 | } | |
5d10d135 | 463 | } |