Augment the TmfCheckpoint API (Bug381411)
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / trace / TmfExperiment.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2010, 2012 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 * Francois Chouinard - Initial API and implementation
11 * Francois Chouinard - Updated as per TMF Trace Model 1.0
12 *******************************************************************************/
13
14 package org.eclipse.linuxtools.tmf.core.trace;
15
16 import org.eclipse.core.resources.IFile;
17 import org.eclipse.core.resources.IProject;
18 import org.eclipse.core.resources.IResource;
19 import org.eclipse.linuxtools.internal.tmf.core.trace.TmfExperimentContext;
20 import org.eclipse.linuxtools.internal.tmf.core.trace.TmfExperimentLocation;
21 import org.eclipse.linuxtools.internal.tmf.core.trace.TmfLocationArray;
22 import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
23 import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
24 import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
25 import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
26 import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
27 import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest;
28 import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest;
29 import org.eclipse.linuxtools.tmf.core.signal.TmfEndSynchSignal;
30 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentDisposedSignal;
31 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentRangeUpdatedSignal;
32 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentSelectedSignal;
33 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentUpdatedSignal;
34 import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
35 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal;
36
37 /**
38 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
39 * that are part of a tracing experiment.
40 *
41 * @version 1.0
42 * @author Francois Chouinard
43 */
44 public class TmfExperiment<T extends ITmfEvent> extends TmfTrace<T> implements ITmfEventParser<T> {
45
46 // ------------------------------------------------------------------------
47 // Constants
48 // ------------------------------------------------------------------------
49
50 /**
51 * The default index page size
52 */
53 public static final int DEFAULT_INDEX_PAGE_SIZE = 5000;
54
55 // ------------------------------------------------------------------------
56 // Attributes
57 // ------------------------------------------------------------------------
58
59 /**
60 * The currently selected experiment (null if none)
61 */
62 protected static TmfExperiment<?> fCurrentExperiment = null;
63
64 /**
65 * The set of traces that constitute the experiment
66 */
67 protected ITmfTrace<T>[] fTraces;
68
69 /**
70 * The set of traces that constitute the experiment
71 */
72 private boolean fInitialized = false;
73
74 /**
75 * The experiment bookmarks file
76 */
77 private IFile fBookmarksFile;
78
79
80 // Saved experiment context (optimization)
81 private TmfExperimentContext fExperimentContext;
82
83 // ------------------------------------------------------------------------
84 // Construction
85 // ------------------------------------------------------------------------
86
87 /**
88 * @param type
89 * @param id
90 * @param traces
91 * @throws TmfTraceException
92 */
93 public TmfExperiment(final Class<T> type, final String id, final ITmfTrace<T>[] traces) {
94 this(type, id, traces, DEFAULT_INDEX_PAGE_SIZE);
95 }
96
97 /**
98 * @param type
99 * @param id
100 * @param traces
101 * @param indexPageSize
102 * @throws TmfTraceException
103 */
104 @SuppressWarnings({ "unchecked", "rawtypes" })
105 public TmfExperiment(final Class<T> type, final String path, final ITmfTrace<T>[] traces, final int indexPageSize) {
106 setCacheSize(indexPageSize);
107 setStreamingInterval(0);
108 setIndexer(new TmfCheckpointIndexer(this, indexPageSize));
109 setParser(this);
110 try {
111 super.initialize(null, path, type);
112 } catch (TmfTraceException e) {
113 e.printStackTrace();
114 }
115
116 fTraces = traces;
117 setTimeRange(TmfTimeRange.NULL_RANGE);
118 }
119
120 /**
121 * Clears the experiment
122 */
123 @Override
124 @SuppressWarnings("rawtypes")
125 public synchronized void dispose() {
126
127 final TmfExperimentDisposedSignal<T> signal = new TmfExperimentDisposedSignal<T>(this, this);
128 broadcast(signal);
129
130 if (fCurrentExperiment == this) {
131 fCurrentExperiment = null;
132 }
133
134 // Clean up the index if applicable
135 if (getIndexer() != null) {
136 getIndexer().dispose();
137 }
138
139 if (fTraces != null) {
140 for (final ITmfTrace trace : fTraces)
141 trace.dispose();
142 fTraces = null;
143 }
144 super.dispose();
145 }
146
147 // ------------------------------------------------------------------------
148 // ITmfTrace - Initializers
149 // ------------------------------------------------------------------------
150
151 /* (non-Javadoc)
152 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
153 */
154 @Override
155 public boolean validate(final IProject project, final String path) {
156 return true;
157 }
158
159 /* (non-Javadoc)
160 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class)
161 */
162 @Override
163 public void initTrace(final IResource resource, final String path, final Class<T> type) {
164 }
165
166 // ------------------------------------------------------------------------
167 // Accessors
168 // ------------------------------------------------------------------------
169
170 /**
171 * Selects the current, framework-wide, experiment
172 *
173 * @param experiment das experiment
174 */
175 public static void setCurrentExperiment(final TmfExperiment<?> experiment) {
176 if (fCurrentExperiment != null && fCurrentExperiment != experiment) {
177 fCurrentExperiment.dispose();
178 }
179 fCurrentExperiment = experiment;
180 }
181
182 /**
183 * @return das experiment
184 */
185 public static TmfExperiment<?> getCurrentExperiment() {
186 return fCurrentExperiment;
187 }
188
189 /**
190 * Get the list of traces. Handle with care...
191 *
192 * @return the experiment traces
193 */
194 public ITmfTrace<T>[] getTraces() {
195 return fTraces;
196 }
197
198 /**
199 * Returns the timestamp of the event at the requested index. If none,
200 * returns null.
201 *
202 * @param index the event index (rank)
203 * @return the corresponding event timestamp
204 */
205 public ITmfTimestamp getTimestamp(final int index) {
206 final ITmfContext context = seekEvent(index);
207 final ITmfEvent event = getNext(context);
208 return (event != null) ? event.getTimestamp() : null;
209 }
210
211 /**
212 * Set the file to be used for bookmarks on this experiment
213 *
214 * @param file the bookmarks file
215 */
216 public void setBookmarksFile(final IFile file) {
217 fBookmarksFile = file;
218 }
219
220 /**
221 * Get the file used for bookmarks on this experiment
222 *
223 * @return the bookmarks file or null if none is set
224 */
225 public IFile getBookmarksFile() {
226 return fBookmarksFile;
227 }
228
229 // ------------------------------------------------------------------------
230 // Request management
231 // ------------------------------------------------------------------------
232
233 @Override
234 protected ITmfContext armRequest(final ITmfDataRequest<T> request) {
235 if (request instanceof ITmfEventRequest<?>
236 && !TmfTimestamp.BIG_BANG.equals(((ITmfEventRequest<T>) request).getRange().getStartTime())
237 && request.getIndex() == 0)
238 {
239 final ITmfContext context = seekEvent(((ITmfEventRequest<T>) request).getRange().getStartTime());
240 ((ITmfEventRequest<T>) request).setStartIndex((int) context.getRank());
241 return context;
242
243 }
244
245 // Check if we are already at the right index
246 if ((fExperimentContext != null) && fExperimentContext.getRank() == request.getIndex()) {
247 return fExperimentContext;
248 }
249
250 return seekEvent(request.getIndex());
251 }
252
253 // ------------------------------------------------------------------------
254 // ITmfTrace trace positioning
255 // ------------------------------------------------------------------------
256
257 /* (non-Javadoc)
258 *
259 * Returns a brand new context based on the location provided and
260 * initializes the event queues
261 *
262 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
263 */
264 @Override
265 public synchronized ITmfContext seekEvent(final ITmfLocation<?> location) {
266 // Validate the location
267 if (location != null && !(location instanceof TmfExperimentLocation)) {
268 return null; // Throw an exception?
269 }
270 // Make sure we have something to read from
271 if (fTraces == null) {
272 return null;
273 }
274
275 // Instantiate the location
276 final TmfExperimentLocation expLocation = (location == null)
277 ? new TmfExperimentLocation(new TmfLocationArray(new ITmfLocation<?>[fTraces.length]))
278 : (TmfExperimentLocation) location.clone();
279
280 // Create and populate the context's traces contexts
281 final TmfExperimentContext context = new TmfExperimentContext(new ITmfContext[fTraces.length]);
282
283 for (int i = 0; i < fTraces.length; i++) {
284 // Get the relevant trace attributes
285 final ITmfLocation<?> traceLocation = expLocation.getLocation().getLocations()[i];
286 context.getContexts()[i] = fTraces[i].seekEvent(traceLocation);
287 expLocation.getLocation().getLocations()[i] = context.getContexts()[i].getLocation().clone();
288 context.getEvents()[i] = fTraces[i].getNext(context.getContexts()[i]);
289 }
290
291 // Finalize context
292 context.setLocation(expLocation);
293 context.setLastTrace(TmfExperimentContext.NO_TRACE);
294 context.setRank(ITmfContext.UNKNOWN_RANK);
295
296 fExperimentContext = context;
297
298 return (ITmfContext) context;
299 }
300
301 /* (non-Javadoc)
302 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(double)
303 */
304 @Override
305 public ITmfContext seekEvent(final double ratio) {
306 final ITmfContext context = seekEvent((long) (ratio * getNbEvents()));
307 return context;
308 }
309
310 /* (non-Javadoc)
311 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getLocationRatio(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
312 */
313 @Override
314 public double getLocationRatio(final ITmfLocation<?> location) {
315 if (location instanceof TmfExperimentLocation) {
316 return (double) seekEvent(location).getRank() / getNbEvents();
317 }
318 return 0.0;
319 }
320
321 /* (non-Javadoc)
322 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentLocation()
323 */
324 @Override
325 public ITmfLocation<?> getCurrentLocation() {
326 ITmfLocation<?>[] locations = new ITmfLocation<?>[fTraces.length];
327 for (int i = 0; i < fTraces.length; i++) {
328 locations[i] = fTraces[i].getCurrentLocation();
329 }
330 return new TmfExperimentLocation(new TmfLocationArray(locations));
331 }
332
333 /* (non-Javadoc)
334 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(long)
335 */
336 @Override
337 public synchronized ITmfContext seekEvent(final long rank) {
338
339 TmfExperimentContext context = (TmfExperimentContext) super.seekEvent(rank);
340
341 // // A rank <= 0 indicates to seek the first event
342 // if (rank <= 0) {
343 // ITmfContext context = seekEvent((ITmfLocation<?>) null);
344 // context.setRank(0);
345 // return context;
346 // }
347 //
348 // // Position the trace at the checkpoint
349 // final ITmfContext context = fIndexer.seekIndex(rank);
350 //
351 // // And locate the requested event context
352 // long pos = context.getRank();
353 // if (pos < rank) {
354 // ITmfEvent event = getNext(context);
355 // while (event != null && ++pos < rank) {
356 // event = getNext(context);
357 // }
358 // }
359 return context;
360 }
361
362 // ------------------------------------------------------------------------
363 // ITmfTrace trace positioning
364 // ------------------------------------------------------------------------
365
366 /* (non-Javadoc)
367 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#getNext(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
368 */
369 @Override
370 public synchronized T getNext(final ITmfContext context) {
371 final ITmfContext previousContext = (TmfExperimentContext) context.clone();
372 final T event = parseEvent(context);
373 if (event != null) {
374 updateAttributes(previousContext, event.getTimestamp());
375
376 fExperimentContext = (TmfExperimentContext) context;
377 int trace = fExperimentContext.getLastTrace();
378 if (trace != TmfExperimentContext.NO_TRACE) {
379 TmfExperimentLocation location = (TmfExperimentLocation) fExperimentContext.getLocation();
380 location.getLocation().getLocations()[trace] = fExperimentContext.getContexts()[trace].getLocation();
381 }
382
383 context.increaseRank();
384 processEvent(event);
385 }
386 return event;
387 }
388
389 /* (non-Javadoc)
390 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser#parseEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
391 */
392 @SuppressWarnings("unchecked")
393 @Override
394 public T parseEvent(ITmfContext context) {
395
396 // Validate the context
397 if (!(context instanceof TmfExperimentContext)) {
398 return null; // Throw an exception?
399 }
400
401 TmfExperimentContext expContext = (TmfExperimentContext) context;
402
403 // If an event was consumed previously, first get the next one from that trace
404 final int lastTrace = expContext.getLastTrace();
405 if (lastTrace != TmfExperimentContext.NO_TRACE) {
406 final ITmfContext traceContext = expContext.getContexts()[lastTrace];
407 expContext.getEvents()[lastTrace] = fTraces[lastTrace].getNext(traceContext);
408 expContext.setLastTrace(TmfExperimentContext.NO_TRACE);
409 }
410
411 // Scan the candidate events and identify the "next" trace to read from
412 int trace = TmfExperimentContext.NO_TRACE;
413 ITmfTimestamp timestamp = TmfTimestamp.BIG_CRUNCH;
414 for (int i = 0; i < fTraces.length; i++) {
415 final ITmfEvent event = expContext.getEvents()[i];
416 if (event != null && event.getTimestamp() != null) {
417 final ITmfTimestamp otherTS = event.getTimestamp();
418 if (otherTS.compareTo(timestamp, true) < 0) {
419 trace = i;
420 timestamp = otherTS;
421 }
422 }
423 }
424
425 T event = null;
426 if (trace != TmfExperimentContext.NO_TRACE) {
427 event = (T) expContext.getEvents()[trace];
428 }
429
430 expContext.setLastTrace(trace);
431 return event;
432 }
433
434 /* (non-Javadoc)
435 * @see java.lang.Object#toString()
436 */
437 @Override
438 @SuppressWarnings("nls")
439 public String toString() {
440 return "[TmfExperiment (" + getName() + ")]";
441 }
442
443 // ------------------------------------------------------------------------
444 // Streaming support
445 // ------------------------------------------------------------------------
446
447 private synchronized void initializeStreamingMonitor() {
448
449 if (fInitialized) {
450 return;
451 }
452 fInitialized = true;
453
454 if (getStreamingInterval() == 0) {
455 final ITmfContext context = seekEvent(0);
456 final ITmfEvent event = getNext(context);
457 if (event == null)
458 return;
459 final TmfTimeRange timeRange = new TmfTimeRange(event.getTimestamp().clone(), TmfTimestamp.BIG_CRUNCH);
460 final TmfExperimentRangeUpdatedSignal signal = new TmfExperimentRangeUpdatedSignal(this, this, timeRange);
461
462 // Broadcast in separate thread to prevent deadlock
463 new Thread() {
464 @Override
465 public void run() {
466 broadcast(signal);
467 }
468 }.start();
469 return;
470 }
471
472 final Thread thread = new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
473 private ITmfTimestamp safeTimestamp = null;
474 private TmfTimeRange timeRange = null;
475
476 @Override
477 public void run() {
478 while (!fExecutor.isShutdown()) {
479 if (!getIndexer().isIndexing()) {
480 ITmfTimestamp startTimestamp = TmfTimestamp.BIG_CRUNCH;
481 ITmfTimestamp endTimestamp = TmfTimestamp.BIG_BANG;
482 for (final ITmfTrace<T> trace : fTraces) {
483 if (trace.getStartTime().compareTo(startTimestamp) < 0)
484 startTimestamp = trace.getStartTime();
485 if (trace.getStreamingInterval() != 0 && trace.getEndTime().compareTo(endTimestamp) > 0)
486 endTimestamp = trace.getEndTime();
487 }
488 if (safeTimestamp != null && safeTimestamp.compareTo(getTimeRange().getEndTime(), false) > 0)
489 timeRange = new TmfTimeRange(startTimestamp, safeTimestamp);
490 else
491 timeRange = null;
492 safeTimestamp = endTimestamp;
493 if (timeRange != null) {
494 final TmfExperimentRangeUpdatedSignal signal =
495 new TmfExperimentRangeUpdatedSignal(TmfExperiment.this, TmfExperiment.this, timeRange);
496 broadcast(signal);
497 }
498 }
499 try {
500 Thread.sleep(getStreamingInterval());
501 } catch (final InterruptedException e) {
502 e.printStackTrace();
503 }
504 }
505 }
506 };
507 thread.start();
508 }
509
510 /* (non-Javadoc)
511 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
512 */
513 @Override
514 public long getStreamingInterval() {
515 long interval = 0;
516 for (final ITmfTrace<T> trace : fTraces)
517 interval = Math.max(interval, trace.getStreamingInterval());
518 return interval;
519 }
520
521 // ------------------------------------------------------------------------
522 // Signal handlers
523 // ------------------------------------------------------------------------
524
525 private Integer fEndSynchReference;
526
527 /**
528 * Signal handler for the TmfExperimentSelectedSignal signal
529 *
530 * @param signal
531 */
532 @TmfSignalHandler
533 public void experimentSelected(final TmfExperimentSelectedSignal<T> signal) {
534 final TmfExperiment<?> experiment = signal.getExperiment();
535 if (experiment == this) {
536 setCurrentExperiment(experiment);
537 fEndSynchReference = Integer.valueOf(signal.getReference());
538 }
539 }
540
541 /**
542 * Signal handler for the TmfEndSynchSignal signal
543 *
544 * @param signal
545 */
546 @TmfSignalHandler
547 public void endSync(final TmfEndSynchSignal signal) {
548 if (fEndSynchReference != null && fEndSynchReference.intValue() == signal.getReference()) {
549 fEndSynchReference = null;
550 initializeStreamingMonitor();
551 }
552 }
553
554 /**
555 * Signal handler for the TmfTraceUpdatedSignal signal
556 *
557 * @param signal
558 */
559 @TmfSignalHandler
560 public void traceUpdated(final TmfTraceUpdatedSignal signal) {
561 if (signal.getTrace() == this) {
562 broadcast(new TmfExperimentUpdatedSignal(this, this));
563 }
564 }
565
566 /**
567 * Signal handler for the TmfExperimentRangeUpdatedSignal signal
568 *
569 * @param signal
570 */
571 @TmfSignalHandler
572 public void experimentRangeUpdated(final TmfExperimentRangeUpdatedSignal signal) {
573 if (signal.getExperiment() == this) {
574 getIndexer().buildIndex(getNbEvents(), signal.getRange(), false);
575 }
576 }
577
578 }
This page took 0.045047 seconds and 6 git commands to generate.