[Bug 303523] LTTng/TMF udpates:
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng / src / org / eclipse / linuxtools / lttng / state / StateManager.java
1 /*******************************************************************************
2 * Copyright (c) 2009 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
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.lttng.state;
14
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.Observable;
19 import java.util.Set;
20 import java.util.Vector;
21
22 import org.eclipse.linuxtools.lttng.TraceDebug;
23 import org.eclipse.linuxtools.lttng.event.LttngEvent;
24 import org.eclipse.linuxtools.lttng.event.LttngTimestamp;
25 import org.eclipse.linuxtools.lttng.state.evProcessor.AbsEventProcessorFactory;
26 import org.eclipse.linuxtools.lttng.state.evProcessor.EventProcessorProxy;
27 import org.eclipse.linuxtools.lttng.state.evProcessor.IEventProcessing;
28 import org.eclipse.linuxtools.lttng.state.model.ILttngStateInputRef;
29 import org.eclipse.linuxtools.lttng.state.model.LttngTraceState;
30 import org.eclipse.linuxtools.lttng.state.model.StateModelFactory;
31 import org.eclipse.linuxtools.tmf.event.TmfEvent;
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.TmfDataRequest;
36 import org.eclipse.linuxtools.tmf.trace.TmfTrace;
37 import org.eclipse.linuxtools.tmf.trace.TmfTraceCheckpoint;
38
39 /**
40 *
41 * @author alvaro
42 *
43 */
44 public class StateManager extends Observable {
45
46 private static final long LTTNG_STATE_SAVE_INTERVAL = 5000000L;
47
48 // These are used in the building of the data request.
49 private static final long DEFAULT_OFFSET = 0L;
50 private static final int DEFAULT_CHUNK = 1;
51
52 // ========================================================================
53 // Data
54 // =======================================================================
55 private TmfExperiment<LttngEvent> fExperiment = null;
56 private TmfTrace<LttngEvent> fEventLog = null;
57 private StateStacksHandler stateIn = null;
58 private Long eventCount = 0L;
59
60 private HashMap<Long, LttngTraceState> stateCheckpointsList = new HashMap<Long, LttngTraceState>();
61 private Vector<TmfTraceCheckpoint> timestampCheckpointsList = new Vector<TmfTraceCheckpoint>();
62
63 // ========================================================================
64 // Constructor
65 // =======================================================================
66
67 // /**
68 // * Default constructor
69 // * <p>
70 // * Instanciate its own StateStacksHandler.
71 // *
72 // */
73 // public StateManager() {
74 // this.stateIn = new StateStacksHandler();
75 // }
76
77 /**
78 * Constructor with parameter
79 * <p>
80 *
81 * @param stateInputHandler
82 * A valid StateStacksHandler
83 *
84 */
85 public StateManager(StateStacksHandler stateInputHandler) {
86 this.stateIn = stateInputHandler;
87 }
88
89 // /**
90 // * Copy constructor
91 // * <p>
92 // *
93 // * @param oldStateManager
94 // * the StateManager we want to copy
95 // *
96 // */
97 // public StateManager(StateManager oldStateManager) {
98 // fEventLog = oldStateManager.fEventLog;
99 // stateIn = oldStateManager.stateIn;
100 // trace = oldStateManager.trace;
101 // eventCount = oldStateManager.eventCount;
102 //
103 // stateCheckpointsList = oldStateManager.stateCheckpointsList;
104 // timestampCheckpointsList = oldStateManager.timestampCheckpointsList;
105 // }
106
107 // ========================================================================
108 // Methods
109 // =======================================================================
110 /**
111 * A new Experiment or trace selected
112 * @param experiment
113 * @param clearPreviousData
114 */
115 @SuppressWarnings("unchecked")
116 public void setTraceSelection(TmfExperiment<LttngEvent> experiment,
117 boolean clearPreviousData) {
118 // New log in use, read all events and build state transition stack
119 if (experiment != null) {
120 if (fExperiment != null && fExperiment != experiment) {
121 this.fExperiment.deregister();
122 }
123
124 this.fExperiment = experiment;
125
126 // if (fEventLog != null) {
127 // this.fEventLog.dispose();
128 // }
129
130 this.fEventLog = (TmfTrace<LttngEvent>) experiment.getTraces()[0];
131 try {
132 stateIn.init(fEventLog);
133 } catch (LttngStateException e) {
134 e.printStackTrace();
135 }
136
137 // Restart count and collections
138 eventCount = 0L;
139 stateCheckpointsList.clear();
140 timestampCheckpointsList.clear();
141
142 // Obtain a dataRequest to pass to the processRequest function
143 TmfTimeRange allTraceWindow = fEventLog.getTimeRange();
144 StateDataRequest request = getDataRequestStateSave(allTraceWindow,
145 null);
146 request.setclearDataInd(clearPreviousData);
147
148 // Wait for completion
149 request.startRequestInd(fExperiment, true, true);
150
151 if (TraceDebug.isDEBUG()) {
152 StringBuilder sb = new StringBuilder(
153 "Total number of processes in the State provider: "
154 + stateIn.getTraceStateModel().getProcesses().length);
155
156 TmfTimeRange logTimes = fEventLog.getTimeRange();
157 sb.append("\n\tLog file times "
158 + new LttngTimestamp(logTimes.getStartTime()));
159 sb.append(" - " + new LttngTimestamp(logTimes.getEndTime()));
160
161 sb.append("\n\tCheckPoints available at: ");
162 for (TmfTraceCheckpoint cpoint : timestampCheckpointsList) {
163 sb.append("\n\t" + cpoint.getTimestamp());
164 }
165 TraceDebug.debug(sb.toString());
166 }
167 }
168
169 }
170
171 /**
172 * TODO: Not ready for threading
173 * <p>
174 * Read events within specific time window
175 * </p>
176 *
177 * @param trange
178 * @param obs
179 * @param transactionID
180 */
181 public void executeDataRequest(TmfTimeRange trange, String transactionID,
182 IStateDataRequestListener listener) {
183 TmfTimestamp restoredStartTime = restoreCheckPointByTimestamp(trange
184 .getStartTime());
185 // Adjust the time range to consider rewinding to the start time
186 trange = new TmfTimeRange(restoredStartTime, trange.getEndTime());
187 // Get a data request for the time range we want (nearest checkpoint
188 // to timestamp wanted)
189 eventCount = 0L;
190
191 // Process request to that point
192 StateDataRequest request = getDataRequestByTimeRange(trange, listener);
193 // don't wait for completion i.e. allow cancellations
194 request.startRequestInd(fExperiment, false, false);
195
196 if (TraceDebug.isDEBUG()) {
197 TraceDebug
198 .debug(" Time Window requested, (start adjusted to checkpoint): "
199 + trange.getStartTime()
200 + "-" + trange.getEndTime()
201 + " Total number of processes in the State provider: "
202 + stateIn.getTraceStateModel().getProcesses().length + " Completed");
203 }
204 }
205
206 /**
207 * Current value of event counter
208 *
209 * @return Long The number of events, if it is known
210 */
211 public Long getEventCount() {
212 return eventCount;
213 }
214
215 /**
216 * used to obtain details on the log associated with this manager e.g.
217 * logid.
218 *
219 * @return
220 */
221 public TmfTrace<LttngEvent> getEventLog() {
222 return fEventLog;
223 }
224
225 /**
226 * Used for troubleshooting when debug mode is on
227 *
228 * @return Set<String> Set of event that were not handled
229 */
230 public Set<String> getEventsNotHandled() {
231 return stateIn.getEventsNotHandled();
232 }
233
234 /**
235 * Needed for verification purposes
236 *
237 * @param listener
238 * The IEventProcessing we want to register
239 */
240 void registerListener(IEventProcessing listener) {
241 stateIn.registerListener(listener);
242 }
243
244 /**
245 * Needed for verification purposes
246 *
247 * @param listener
248 * The IEventProcessing we want to unregister
249 */
250 void deregisterListener(IEventProcessing listener) {
251 stateIn.deregisterListener(listener);
252 }
253
254 /**
255 * Save a checkpoint if it is needed at that point
256 * <p>
257 * The function will use "eventCount" internally to determine if a save was
258 * needed
259 *
260 * @param eventCounter
261 * The event "count" or event "id" so far
262 * @param eventTime
263 * The timestamp of this event
264 *
265 * @return boolean True if a checkpoint was saved, false otherwise
266 */
267 private boolean saveCheckPointIfNeeded(Long eventCounter,
268 TmfTimestamp eventTime) {
269 boolean saveHappened = false;
270 // Crate new location to store checkpoint reference
271 Long location = new Long(eventCounter.longValue());
272 // Save a checkpoint every LTTNG_STATE_SAVE_INTERVAL event
273 if ((location % LTTNG_STATE_SAVE_INTERVAL) == 0) {
274 // Save the checkpoint
275 stateCheckpointsList.put(location, stateIn.traceStateModel.clone());
276 // Save correlation between timestamp and checkpoint index
277
278 timestampCheckpointsList.add(new TmfTraceCheckpoint(eventTime,
279 location));
280
281 saveHappened = true;
282 }
283
284 return saveHappened;
285 }
286
287 /**
288 * Restore to the closest checkpoint from TmfTimestamp
289 * <p>
290 * Note : it is heavier to restore by timestamp than by event position,
291 * restore by event position whichever possible.
292 *
293 * @param eventTime
294 * The timestamp of the event to restore to
295 *
296 * @return TmfTimestamp indicates the nearest time used to restore the
297 * state, null sent if input is invalid
298 */
299 public TmfTimestamp restoreCheckPointByTimestamp(TmfTimestamp eventTime) {
300 TmfTimeRange logRange = fExperiment.getTimeRange();
301 TmfTimestamp nearestTimeStamp = logRange.getStartTime();
302
303 // The GUI can have time limits higher than this log, since GUI can
304 // handle multiple logs
305 if ((eventTime.getValue() < 0)
306 || (eventTime.getValue() > logRange.getEndTime().getValue())) {
307 return null;
308 }
309
310 // The GUI can have time limits lower than this log, since GUI can
311 // handle multiple logs
312 if ((eventTime.getValue() < logRange.getStartTime().getValue())) {
313 eventTime = logRange.getStartTime();
314 }
315
316 // Sort the checkpoints, required before the binary search
317 Collections.sort(timestampCheckpointsList);
318 // Initiate the compare with a checkpoint containing the target time
319 // stamp to find
320 int index = Collections.binarySearch(timestampCheckpointsList,
321 new TmfTraceCheckpoint(eventTime, 0));
322 // adjust index to round down to earlier checkpoint when exact match not
323 // found
324 index = getPrevIndex(index);
325
326 LttngTraceState traceState;
327 Long location = 0L;
328 if (index == 0) {
329 // No checkpoint restore is needed, start with a brand new
330 // TraceState
331 ILttngStateInputRef inputDataRef = new LttngStateInputRef(fEventLog);
332 traceState = StateModelFactory.getStateEntryInstance(inputDataRef);
333 } else {
334 // Useful CheckPoint found
335 TmfTraceCheckpoint checkpoint = timestampCheckpointsList.get(index);
336 nearestTimeStamp = checkpoint.getTimestamp();
337 // get the location associated with the checkpoint
338 location = (Long) (checkpoint.getLocation());
339 // reference a new copy of the checkpoint template
340 traceState = stateCheckpointsList.get(location).clone();
341 }
342
343 // Make sure eventCount stay consistent!
344 eventCount = new Long(location);
345
346 // Restore the stored traceState
347 stateIn.setTraceStateModel(traceState);
348
349 return nearestTimeStamp;
350 }
351
352 /**
353 * Adjust the result from a binary search to the round down position
354 *
355 * @param position
356 * if Negative is: (-(insertion point) -1)
357 * @return position or if no match found, earlier than insertion point
358 */
359 private int getPrevIndex(int position) {
360 int roundDownPosition = position;
361 if (position < 0) {
362 roundDownPosition = -(position + 2);
363 }
364
365 roundDownPosition = roundDownPosition < 0 ? 0 : roundDownPosition;
366 return roundDownPosition;
367 }
368
369 // /**
370 // * Restore to the closest checkpoint from position
371 // * <p>
372 // *
373 // * @param position
374 // * The position of the event to restore to
375 // *
376 // * @return boolean True if a checkpoint was restored, false otherwise
377 // */
378 // private boolean restoreCheckPointByPosition(long position) {
379 // long nearestCheckPoint = (position - (position %
380 // LTTNG_STATE_SAVE_INTERVAL));
381 //
382 // // Some sanity check :
383 // // Not under 0
384 // // Not over eventCount
385 // // A checkpoint exist
386 // if ((nearestCheckPoint < 0) || (nearestCheckPoint > eventCount)
387 // || (stateCheckpointsList.get(nearestCheckPoint) == null)) {
388 // return false;
389 // } else {
390 // // Restore the stored traceState
391 // stateIn.setTraceStateModel(stateCheckpointsList
392 // .get(nearestCheckPoint));
393 //
394 // // Make sure eventCount stay consistent!
395 // eventCount = new Long(nearestCheckPoint);
396 //
397 // // * Rewind to the correct position
398 // // To do so, we need a request to the correct window
399 // // We will seek to nearestCheckPoint and read next events until
400 // // position
401 // TmfDataRequest<TmfEvent> request = getDataRequestByPosition(
402 // (int) nearestCheckPoint, (int) position);
403 //
404 // // Process request to that point
405 // fExperiment.processRequest(request, true);
406 //
407 // return true;
408 // }
409 // }
410
411 /**
412 * Get a Tmf data request for the current eventlog
413 * <p>
414 *
415 * @param TmfTimeRange
416 * The time range we want events from.
417 *
418 * @return TmfDataRequest<TmfEvent> The request made
419 */
420 StateDataRequest getDataRequestByTimeRange(TmfTimeRange timeWindow,
421 IStateDataRequestListener listener) {
422
423 final TmfEvent[] evt = new TmfEvent[1];
424
425 // ***TODO***
426 // The override of handlePartialResult is similar to the one in
427 // getDataRequestByPosition()
428 // ***
429
430 // Create the new request and override the handlePartialResult function
431 StateDataRequest request = new StateDataRequest(timeWindow,
432 DEFAULT_OFFSET, TmfDataRequest.ALL_DATA, DEFAULT_CHUNK,
433 listener, this) {
434 @Override
435 public void handleData() {
436 TmfEvent[] result = getData();
437
438 evt[0] = (result.length > 0) ? result[0] : null;
439 // Dispatch information for Event processing
440 stateIn.processEvent(evt[0]);
441
442 // increment internal and external number of events
443 setNumOfEvents(getNumOfEvents() + 1);
444 eventCount++;
445 }
446
447 @Override
448 public void handleCompleted() {
449 if (isCancelled() || isFailed()) {
450 // No notification to end request handlers
451 } else {
452 // notify the associated end request handlers
453 requestCompleted();
454 }
455
456 // notify listeners
457 notifyCompletion();
458 }
459 };
460
461 return request;
462 }
463
464 private StateDataRequest getDataRequestStateSave(TmfTimeRange timeWindow,
465 IStateDataRequestListener requestListener) {
466
467 final TmfEvent[] evt = new TmfEvent[1];
468
469 // ***TODO***
470 // The override of handlePartialResult is similar to the one in
471 // getDataRequestByPosition()
472 // ***
473
474 // Create the new request and override the handlePartialResult function
475 StateDataRequest request = new StateDataRequest(timeWindow,
476 DEFAULT_OFFSET, TmfDataRequest.ALL_DATA, DEFAULT_CHUNK,
477 requestListener, this) {
478
479 @Override
480 public void handleData() {
481 TmfEvent[] result = getData();
482
483 evt[0] = (result.length > 0) ? result[0] : null;
484 // Dispatch information for Event processing
485 stateIn.processEvent(evt[0]);
486
487 // Call the function that will save a checkpoint if needed at
488 // that point
489 // Note : We call this function before incrementing eventCount
490 // to avoid skipping the "0th" event
491 if (evt[0] != null) {
492 saveCheckPointIfNeeded(getNumOfEvents(), evt[0]
493 .getTimestamp());
494 }
495
496 // increment internal and external counters
497 setNumOfEvents(getNumOfEvents() + 1);
498 eventCount++;
499 }
500
501 @Override
502 public void handleCompleted() {
503 if (isCancelled() || isFailed()) {
504 // No notification to end request handlers
505 } else {
506 // notify the associated end request handlers
507 requestCompleted();
508 }
509
510 // notify listeners
511 notifyCompletion();
512 TraceDebug.debug("number of events processed on file opening"
513 + getNumOfEvents());
514 }
515 };
516
517 return request;
518 }
519
520 // /**
521 // * Get a Tmf data request for the current eventlog
522 // * <p>
523 // *
524 // * @param startPosition
525 // * The position to start the get request from
526 // * @param endPosition
527 // * The position to ed the get request at
528 // *
529 // * @return TmfDataRequest<TmfEvent> The request made
530 // */
531 // private TmfDataRequest<TmfEvent> getDataRequestByPosition(
532 // long startPosition, long endPosition) {
533 // final TmfEvent[] evt = new TmfEvent[1];
534 //
535 // // ***FIXME***
536 // // The override of handlePartialResult is exactly the same as the one in
537 // // getDataRequestByPosition()
538 // // However, there is no way to override it in only one place to avoid
539 // // code duplication!
540 // // ***
541 //
542 // // Create the new request and override the handlePartialResult function
543 // TmfDataRequest<TmfEvent> request = new TmfDataRequest<TmfEvent>(
544 // (int) startPosition, DEFAULT_OFFSET,
545 // (int) (endPosition - startPosition), DEFAULT_CHUNK) {
546 // //@Override
547 // public void handlePartialResult() {
548 // TmfEvent[] result = getData();
549 //
550 // evt[0] = (result.length > 0) ? result[0] : null;
551 // // Dispatch information for Event processing
552 // stateIn.processEvent(evt[0]);
553 // }
554 // };
555 //
556 // return request;
557 // }
558
559 /**
560 * @return
561 */
562 public TmfTimeRange getExperimentTimeWindow() {
563 if (fExperiment != null) {
564 return fExperiment.getTimeRange();
565 }
566 return null;
567 }
568
569 /**
570 * This method has to be called once all events of the associated Trace have
571 * been processed, this method then triggers the drawing of the final state
572 * which is necessary e.g when zooming.
573 */
574 public synchronized void requestCompleted() {
575 Set<AbsEventProcessorFactory> handlerRegister = EventProcessorProxy
576 .getInstance().getProcessingFactories();
577 // Notify the FINISH handlers
578 for (Iterator<AbsEventProcessorFactory> iterator = handlerRegister
579 .iterator(); iterator.hasNext();) {
580 AbsEventProcessorFactory handlerRegistry = (AbsEventProcessorFactory) iterator
581 .next();
582 IEventProcessing handler = handlerRegistry.getfinishProcessor();
583 if (handler != null) {
584 // process State Update
585 handler.process(null, stateIn.traceStateModel);
586 }
587 }
588 }
589 }
This page took 0.044674 seconds and 5 git commands to generate.