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