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