1 /*******************************************************************************
2 * Copyright (c) 2009, 2013 Ericsson, École Polytechnique de Montréal
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
10 * Francois Chouinard - Initial API and implementation
11 * Francois Chouinard - Updated as per TMF Trace Model 1.0
12 * Patrick Tasse - Updated for removal of context clone
13 * Patrick Tasse - Updated for ranks in experiment location
14 * Geneviève Bastien - Added support of experiment synchronization
15 * Added the initExperiment method and default constructor
16 *******************************************************************************/
18 package org
.eclipse
.linuxtools
.tmf
.core
.trace
;
21 import java
.nio
.ByteBuffer
;
23 import org
.eclipse
.core
.resources
.IFile
;
24 import org
.eclipse
.core
.resources
.IProject
;
25 import org
.eclipse
.core
.resources
.IResource
;
26 import org
.eclipse
.core
.runtime
.CoreException
;
27 import org
.eclipse
.core
.runtime
.IStatus
;
28 import org
.eclipse
.core
.runtime
.Status
;
29 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.Activator
;
30 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfExperimentContext
;
31 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfExperimentLocation
;
32 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfLocationArray
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TmfTraceException
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfEventRequest
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
39 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceRangeUpdatedSignal
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceSynchronizedSignal
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.synchronization
.SynchronizationAlgorithm
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.synchronization
.SynchronizationManager
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
46 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.ITmfPersistentlyIndexable
;
47 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.ITmfTraceIndexer
;
48 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.TmfBTreeTraceIndexer
;
49 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.location
.ITmfLocation
;
52 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
53 * that are part of a tracing experiment.
56 * @author Francois Chouinard
58 public class TmfExperiment
extends TmfTrace
implements ITmfEventParser
, ITmfPersistentlyIndexable
{
60 // ------------------------------------------------------------------------
62 // ------------------------------------------------------------------------
65 * The file name of the Synchronization
69 public final static String SYNCHRONIZATION_FILE_NAME
= "synchronization.bin"; //$NON-NLS-1$
72 * The default index page size
74 public static final int DEFAULT_INDEX_PAGE_SIZE
= 5000;
76 // ------------------------------------------------------------------------
78 // ------------------------------------------------------------------------
81 * The set of traces that constitute the experiment
83 protected ITmfTrace
[] fTraces
;
86 * The set of traces that constitute the experiment
88 private boolean fInitialized
= false;
91 * The experiment bookmarks file
93 private IFile fBookmarksFile
;
95 // ------------------------------------------------------------------------
97 // ------------------------------------------------------------------------
100 * Default constructor
103 public TmfExperiment() {
108 * Constructor with parameters
115 * the experiment set of traces
117 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
) {
118 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
, null);
122 * Constructor of experiment taking type, path, traces and resource
129 * the experiment set of traces
131 * the resource associated to the experiment
133 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
, IResource resource
) {
134 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
, resource
);
141 * the experiment path
143 * the experiment set of traces
144 * @param indexPageSize
145 * the experiment index page size
147 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
) {
148 this(type
, path
, traces
, indexPageSize
, null);
152 * Full constructor of an experiment, taking the type, path, traces,
153 * indexPageSize and resource
158 * the experiment path
160 * the experiment set of traces
161 * @param indexPageSize
162 * the experiment index page size
164 * the resource associated to the experiment
166 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
, IResource resource
) {
167 initExperiment(type
, path
, traces
, indexPageSize
, resource
);
171 protected ITmfTraceIndexer
createIndexer(int interval
) {
172 if (getCheckpointSize() > 0) {
173 return new TmfBTreeTraceIndexer(this, interval
);
175 return super.createIndexer(interval
);
179 * Clears the experiment
182 public synchronized void dispose() {
184 // Clean up the index if applicable
185 if (getIndexer() != null) {
186 getIndexer().dispose();
189 if (fTraces
!= null) {
190 for (final ITmfTrace trace
: fTraces
) {
198 // ------------------------------------------------------------------------
199 // ITmfTrace - Initializers
200 // ------------------------------------------------------------------------
203 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> type
) {
207 * Initialization of an experiment, taking the type, path, traces,
208 * indexPageSize and resource
213 * the experiment path
215 * the experiment set of traces
216 * @param indexPageSize
217 * the experiment index page size
219 * the resource associated to the experiment
222 public void initExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
, IResource resource
) {
223 setCacheSize(indexPageSize
);
224 setStreamingInterval(0);
227 super.initialize(resource
, path
, type
);
228 } catch (TmfTraceException e
) {
229 Activator
.logError("Error initializing experiment", e
); //$NON-NLS-1$
234 if (resource
!= null) {
236 this.synchronizeTraces();
237 } catch (TmfTraceException e
) {
238 Activator
.logError("Error synchronizing experiment", e
); //$NON-NLS-1$
247 public IStatus
validate(final IProject project
, final String path
) {
248 return Status
.OK_STATUS
;
251 // ------------------------------------------------------------------------
253 // ------------------------------------------------------------------------
256 * Get the traces contained in this experiment.
258 * @return The array of contained traces
260 public ITmfTrace
[] getTraces() {
265 * Returns the timestamp of the event at the requested index. If none,
269 * the event index (rank)
270 * @return the corresponding event timestamp
273 public ITmfTimestamp
getTimestamp(final int index
) {
274 final ITmfContext context
= seekEvent(index
);
275 final ITmfEvent event
= getNext(context
);
277 return (event
!= null) ? event
.getTimestamp() : null;
281 * Set the file to be used for bookmarks on this experiment
286 public void setBookmarksFile(final IFile file
) {
287 fBookmarksFile
= file
;
291 * Get the file used for bookmarks on this experiment
293 * @return the bookmarks file or null if none is set
295 public IFile
getBookmarksFile() {
296 return fBookmarksFile
;
299 // ------------------------------------------------------------------------
300 // Request management
301 // ------------------------------------------------------------------------
307 public synchronized ITmfContext
armRequest(final ITmfEventRequest request
) {
309 // Make sure we have something to read from
310 if (fTraces
== null) {
314 if (!TmfTimestamp
.BIG_BANG
.equals(request
.getRange().getStartTime())
315 && request
.getIndex() == 0) {
316 final ITmfContext context
= seekEvent(request
.getRange().getStartTime());
317 request
.setStartIndex((int) context
.getRank());
322 return seekEvent(request
.getIndex());
325 // ------------------------------------------------------------------------
326 // ITmfTrace trace positioning
327 // ------------------------------------------------------------------------
333 public synchronized ITmfContext
seekEvent(final ITmfLocation location
) {
334 // Validate the location
335 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
336 return null; // Throw an exception?
338 // Make sure we have something to read from
339 if (fTraces
== null) {
343 // Initialize the location array if necessary
344 TmfLocationArray locationArray
= ((location
== null) ?
345 new TmfLocationArray(fTraces
.length
) :
346 ((TmfExperimentLocation
) location
).getLocationInfo());
348 ITmfLocation
[] locations
= locationArray
.getLocations();
349 long[] ranks
= locationArray
.getRanks();
351 // Create and populate the context's traces contexts
352 final TmfExperimentContext context
= new TmfExperimentContext(fTraces
.length
);
354 // Position the traces
356 for (int i
= 0; i
< fTraces
.length
; i
++) {
357 // Get the relevant trace attributes
358 final ITmfContext traceContext
= fTraces
[i
].seekEvent(locations
[i
]);
359 context
.getContexts()[i
] = traceContext
;
360 traceContext
.setRank(ranks
[i
]);
361 locations
[i
] = traceContext
.getLocation(); // update location after seek
362 context
.getEvents()[i
] = fTraces
[i
].getNext(traceContext
);
367 context
.setLocation(new TmfExperimentLocation(new TmfLocationArray(locations
, ranks
)));
368 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
369 context
.setRank(rank
);
374 // ------------------------------------------------------------------------
375 // ITmfTrace - SeekEvent operations (returning a trace context)
376 // ------------------------------------------------------------------------
379 public ITmfContext
seekEvent(final double ratio
) {
380 final ITmfContext context
= seekEvent(Math
.round(ratio
* getNbEvents()));
388 public double getLocationRatio(final ITmfLocation location
) {
389 if (location
instanceof TmfExperimentLocation
) {
391 TmfLocationArray locationArray
= ((TmfExperimentLocation
) location
).getLocationInfo();
392 for (int i
= 0; i
< locationArray
.size(); i
++) {
393 rank
+= locationArray
.getRank(i
);
395 return (double) rank
/ getNbEvents();
404 public ITmfLocation
getCurrentLocation() {
409 // ------------------------------------------------------------------------
410 // ITmfTrace trace positioning
411 // ------------------------------------------------------------------------
414 public synchronized ITmfEvent
parseEvent(final ITmfContext context
) {
415 final ITmfContext tmpContext
= seekEvent(context
.getLocation());
416 final ITmfEvent event
= getNext(tmpContext
);
421 public synchronized ITmfEvent
getNext(ITmfContext context
) {
423 // Validate the context
424 if (!(context
instanceof TmfExperimentContext
)) {
425 return null; // Throw an exception?
428 // Make sure that we have something to read from
429 if (fTraces
== null) {
433 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
435 // If an event was consumed previously, first get the next one from that
437 final int lastTrace
= expContext
.getLastTrace();
438 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
439 final ITmfContext traceContext
= expContext
.getContexts()[lastTrace
];
440 expContext
.getEvents()[lastTrace
] = fTraces
[lastTrace
].getNext(traceContext
);
441 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
444 // Scan the candidate events and identify the "next" trace to read from
445 int trace
= TmfExperimentContext
.NO_TRACE
;
446 ITmfTimestamp timestamp
= TmfTimestamp
.BIG_CRUNCH
;
447 for (int i
= 0; i
< fTraces
.length
; i
++) {
448 final ITmfEvent event
= expContext
.getEvents()[i
];
449 if (event
!= null && event
.getTimestamp() != null) {
450 final ITmfTimestamp otherTS
= event
.getTimestamp();
451 if (otherTS
.compareTo(timestamp
, true) < 0) {
458 ITmfEvent event
= null;
459 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
460 event
= expContext
.getEvents()[trace
];
462 updateAttributes(expContext
, event
.getTimestamp());
463 expContext
.increaseRank();
464 expContext
.setLastTrace(trace
);
465 final ITmfContext traceContext
= expContext
.getContexts()[trace
];
467 // Update the experiment location
468 TmfLocationArray locationArray
= new TmfLocationArray(
469 ((TmfExperimentLocation
) expContext
.getLocation()).getLocationInfo(),
470 trace
, traceContext
.getLocation(), traceContext
.getRank());
471 expContext
.setLocation(new TmfExperimentLocation(locationArray
));
484 public ITmfTimestamp
getInitialRangeOffset() {
485 if ((fTraces
== null) || (fTraces
.length
== 0)) {
486 return super.getInitialRangeOffset();
489 ITmfTimestamp initTs
= TmfTimestamp
.BIG_CRUNCH
;
490 for (int i
= 0; i
< fTraces
.length
; i
++) {
491 ITmfTimestamp ts
= fTraces
[i
].getInitialRangeOffset();
492 if (ts
.compareTo(initTs
) < 0) {
500 * Synchronizes the traces of an experiment. By default it only tries to
501 * read a synchronization file if it exists
503 * @return The synchronization object
504 * @throws TmfTraceException
505 * propagate TmfTraceExceptions
508 public synchronized SynchronizationAlgorithm
synchronizeTraces() throws TmfTraceException
{
509 return synchronizeTraces(false);
513 * Synchronizes the traces of an experiment.
516 * Whether to actually synchronize or just try opening a sync
518 * @return The synchronization object
519 * @throws TmfTraceException
520 * propagate TmfTraceExceptions
523 public synchronized SynchronizationAlgorithm
synchronizeTraces(boolean doSync
) throws TmfTraceException
{
525 /* Set up the path to the synchronization file we'll use */
526 IResource resource
= this.getResource();
527 String supplDirectory
= null;
530 /* get the directory where the file will be stored. */
531 if (resource
!= null) {
532 supplDirectory
= resource
.getPersistentProperty(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER
);
534 } catch (CoreException e
) {
535 throw new TmfTraceException(e
.toString(), e
);
538 final File syncFile
= (supplDirectory
!= null) ?
new File(supplDirectory
+ File
.separator
+ SYNCHRONIZATION_FILE_NAME
) : null;
540 final SynchronizationAlgorithm syncAlgo
= SynchronizationManager
.synchronizeTraces(syncFile
, fTraces
, doSync
);
542 final TmfTraceSynchronizedSignal signal
= new TmfTraceSynchronizedSignal(this, syncAlgo
);
544 /* Broadcast in separate thread to prevent deadlock */
556 @SuppressWarnings("nls")
557 public synchronized String
toString() {
558 return "[TmfExperiment (" + getName() + ")]";
561 // ------------------------------------------------------------------------
563 // ------------------------------------------------------------------------
565 private synchronized void initializeStreamingMonitor() {
572 if (getStreamingInterval() == 0) {
573 final ITmfContext context
= seekEvent(0);
574 final ITmfEvent event
= getNext(context
);
579 final TmfTimeRange timeRange
= new TmfTimeRange(event
.getTimestamp(), TmfTimestamp
.BIG_CRUNCH
);
580 final TmfTraceRangeUpdatedSignal signal
= new TmfTraceRangeUpdatedSignal(this, this, timeRange
);
582 // Broadcast in separate thread to prevent deadlock
592 final Thread thread
= new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
593 private ITmfTimestamp safeTimestamp
= null;
594 private ITmfTimestamp lastSafeTimestamp
= null;
595 private TmfTimeRange timeRange
= null;
599 while (!executorIsShutdown()) {
600 if (!getIndexer().isIndexing()) {
601 ITmfTimestamp startTimestamp
= TmfTimestamp
.BIG_CRUNCH
;
602 ITmfTimestamp endTimestamp
= TmfTimestamp
.BIG_BANG
;
603 for (final ITmfTrace trace
: fTraces
) {
604 if (trace
.getStartTime().compareTo(startTimestamp
) < 0) {
605 startTimestamp
= trace
.getStartTime();
607 if (trace
.getStreamingInterval() != 0 && trace
.getEndTime().compareTo(endTimestamp
) > 0) {
608 endTimestamp
= trace
.getEndTime();
611 if (safeTimestamp
!= null && (lastSafeTimestamp
== null || safeTimestamp
.compareTo(lastSafeTimestamp
, false) > 0)) {
612 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
613 lastSafeTimestamp
= safeTimestamp
;
617 safeTimestamp
= endTimestamp
;
618 if (timeRange
!= null) {
619 final TmfTraceRangeUpdatedSignal signal
=
620 new TmfTraceRangeUpdatedSignal(TmfExperiment
.this, TmfExperiment
.this, timeRange
);
625 Thread
.sleep(getStreamingInterval());
626 } catch (final InterruptedException e
) {
636 public long getStreamingInterval() {
638 for (final ITmfTrace trace
: fTraces
) {
639 interval
= Math
.max(interval
, trace
.getStreamingInterval());
644 // ------------------------------------------------------------------------
646 // ------------------------------------------------------------------------
650 public void traceOpened(TmfTraceOpenedSignal signal
) {
651 if (signal
.getTrace() == this) {
652 initializeStreamingMonitor();
660 public synchronized int getCheckpointSize() {
661 int totalCheckpointSize
= 0;
663 if (fTraces
!= null) {
664 for (final ITmfTrace trace
: fTraces
) {
665 if (!(trace
instanceof ITmfPersistentlyIndexable
)) {
669 ITmfPersistentlyIndexable persistableIndexTrace
= (ITmfPersistentlyIndexable
) trace
;
670 int currentTraceCheckpointSize
= persistableIndexTrace
.getCheckpointSize();
671 if (currentTraceCheckpointSize
<= 0) {
674 totalCheckpointSize
+= currentTraceCheckpointSize
;
675 totalCheckpointSize
+= 8; // each entry in the TmfLocationArray has a rank in addition of the location
678 } catch (UnsupportedOperationException e
) {
682 return totalCheckpointSize
;
689 public ITmfLocation
restoreLocation(ByteBuffer bufferIn
) {
690 ITmfLocation
[] locations
= new ITmfLocation
[fTraces
.length
];
691 long[] ranks
= new long[fTraces
.length
];
692 for (int i
= 0; i
< fTraces
.length
; ++i
) {
693 final ITmfTrace trace
= fTraces
[i
];
694 locations
[i
] = ((ITmfPersistentlyIndexable
) trace
).restoreLocation(bufferIn
);
695 ranks
[i
] = bufferIn
.getLong();
697 TmfLocationArray arr
= new TmfLocationArray(locations
, ranks
);
698 TmfExperimentLocation l
= new TmfExperimentLocation(arr
);