1 /*******************************************************************************
2 * Copyright (c) 2009, 2014 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
.tracecompass
.tmf
.core
.trace
.experiment
;
21 import java
.nio
.ByteBuffer
;
22 import java
.util
.Collections
;
23 import java
.util
.concurrent
.locks
.Lock
;
24 import java
.util
.concurrent
.locks
.ReentrantLock
;
26 import org
.eclipse
.core
.resources
.IProject
;
27 import org
.eclipse
.core
.resources
.IResource
;
28 import org
.eclipse
.core
.runtime
.CoreException
;
29 import org
.eclipse
.core
.runtime
.IStatus
;
30 import org
.eclipse
.core
.runtime
.MultiStatus
;
31 import org
.eclipse
.core
.runtime
.Status
;
32 import org
.eclipse
.jdt
.annotation
.Nullable
;
33 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.Activator
;
34 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.trace
.experiment
.TmfExperimentContext
;
35 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.trace
.experiment
.TmfExperimentLocation
;
36 import org
.eclipse
.tracecompass
.internal
.tmf
.core
.trace
.experiment
.TmfLocationArray
;
37 import org
.eclipse
.tracecompass
.tmf
.core
.TmfCommonConstants
;
38 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
39 import org
.eclipse
.tracecompass
.tmf
.core
.exceptions
.TmfTraceException
;
40 import org
.eclipse
.tracecompass
.tmf
.core
.request
.ITmfEventRequest
;
41 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
42 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
43 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceRangeUpdatedSignal
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSynchronizedSignal
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.synchronization
.SynchronizationAlgorithm
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.synchronization
.SynchronizationManager
;
47 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
48 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimeRange
;
49 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
50 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfContext
;
51 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfEventParser
;
52 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
53 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTrace
;
54 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
55 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.indexer
.ITmfPersistentlyIndexable
;
56 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.indexer
.ITmfTraceIndexer
;
57 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.indexer
.TmfBTreeTraceIndexer
;
58 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.location
.ITmfLocation
;
61 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
62 * that are part of a tracing experiment.
65 * @author Francois Chouinard
67 public class TmfExperiment
extends TmfTrace
implements ITmfEventParser
, ITmfPersistentlyIndexable
{
69 // ------------------------------------------------------------------------
71 // ------------------------------------------------------------------------
74 * The file name of the Synchronization
77 * @deprecated This file name shouldn't be used directly anymore. All
78 * synchronization files have been moved to a folder and you
79 * should use the {@link #getSynchronizationFolder(boolean)}
80 * method to return the path to this folder.
83 public static final String SYNCHRONIZATION_FILE_NAME
= "synchronization.bin"; //$NON-NLS-1$
86 * The name of the directory containing trace synchronization data. This
87 * directory typically will be preserved when traces are synchronized.
88 * Analysis involved in synchronization can put their supplementary files in
89 * there so they are not deleted when synchronized traces are copied.
91 private static final String SYNCHRONIZATION_DIRECTORY
= "sync_data"; //$NON-NLS-1$
94 * The default index page size
96 public static final int DEFAULT_INDEX_PAGE_SIZE
= 5000;
98 // ------------------------------------------------------------------------
100 // ------------------------------------------------------------------------
103 * The set of traces that constitute the experiment
105 protected ITmfTrace
[] fTraces
;
108 * The set of traces that constitute the experiment
110 private boolean fInitialized
= false;
113 * Lock for synchronization methods. These methods cannot be 'synchronized'
114 * since it makes it impossible to use an event request on the experiment
115 * during synchronization (the request thread would block)
117 private final Lock fSyncLock
= new ReentrantLock();
119 // ------------------------------------------------------------------------
121 // ------------------------------------------------------------------------
124 * Default constructor. Should not be used directly, but is needed for
127 * @deprecated Do not call this directly (but do not remove it either!)
130 public TmfExperiment() {
135 * Constructor of an experiment, taking the type, path, traces,
136 * indexPageSize and resource
141 * The experiment path
143 * The experiment set of traces
144 * @param indexPageSize
145 * The experiment index page size. You can use
146 * {@link TmfExperiment#DEFAULT_INDEX_PAGE_SIZE} for a default
149 * The resource associated to the experiment. You can use 'null'
150 * for no resources (tests, etc.)
152 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
,
154 final ITmfTrace
[] traces
,
155 final int indexPageSize
,
156 final @Nullable IResource resource
) {
157 initExperiment(type
, path
, traces
, indexPageSize
, resource
);
161 protected ITmfTraceIndexer
createIndexer(int interval
) {
162 if (getCheckpointSize() > 0) {
163 return new TmfBTreeTraceIndexer(this, interval
);
165 return super.createIndexer(interval
);
169 * Clears the experiment
172 public synchronized void dispose() {
174 // Clean up the index if applicable
175 if (getIndexer() != null) {
176 getIndexer().dispose();
179 if (fTraces
!= null) {
180 for (final ITmfTrace trace
: fTraces
) {
188 // ------------------------------------------------------------------------
189 // ITmfTrace - Initializers
190 // ------------------------------------------------------------------------
193 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> type
) {
194 /* Do nothing for experiments */
198 * Initialization of an experiment, taking the type, path, traces,
199 * indexPageSize and resource
204 * the experiment path
206 * the experiment set of traces
207 * @param indexPageSize
208 * the experiment index page size
210 * the resource associated to the experiment
213 public void initExperiment(final Class
<?
extends ITmfEvent
> type
,
215 final ITmfTrace
[] traces
,
216 final int indexPageSize
,
217 final @Nullable IResource resource
) {
219 setCacheSize(indexPageSize
);
220 setStreamingInterval(0);
222 // traces have to be set before super.initialize()
225 super.initialize(resource
, path
, type
);
226 } catch (TmfTraceException e
) {
227 Activator
.logError("Error initializing experiment", e
); //$NON-NLS-1$
230 if (resource
!= null) {
231 this.synchronizeTraces();
239 public IStatus
validate(final IProject project
, final String path
) {
240 return Status
.OK_STATUS
;
243 // ------------------------------------------------------------------------
245 // ------------------------------------------------------------------------
248 * Get the traces contained in this experiment.
250 * @return The array of contained traces
252 public ITmfTrace
[] getTraces() {
257 * Returns the timestamp of the event at the requested index. If none,
261 * the event index (rank)
262 * @return the corresponding event timestamp
265 public ITmfTimestamp
getTimestamp(final int index
) {
266 final ITmfContext context
= seekEvent(index
);
267 final ITmfEvent event
= getNext(context
);
269 return (event
!= null) ? event
.getTimestamp() : null;
272 // ------------------------------------------------------------------------
273 // Request management
274 // ------------------------------------------------------------------------
280 public synchronized ITmfContext
armRequest(final ITmfEventRequest request
) {
282 // Make sure we have something to read from
283 if (fTraces
== null) {
287 if (!TmfTimestamp
.BIG_BANG
.equals(request
.getRange().getStartTime())
288 && request
.getIndex() == 0) {
289 final ITmfContext context
= seekEvent(request
.getRange().getStartTime());
290 request
.setStartIndex((int) context
.getRank());
295 return seekEvent(request
.getIndex());
298 // ------------------------------------------------------------------------
299 // ITmfTrace trace positioning
300 // ------------------------------------------------------------------------
306 public synchronized ITmfContext
seekEvent(final ITmfLocation location
) {
307 // Validate the location
308 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
309 return null; // Throw an exception?
311 // Make sure we have something to read from
312 if (fTraces
== null) {
316 // Initialize the location array if necessary
317 TmfLocationArray locationArray
= ((location
== null) ?
318 new TmfLocationArray(fTraces
.length
) :
319 ((TmfExperimentLocation
) location
).getLocationInfo());
321 ITmfLocation
[] locations
= locationArray
.getLocations();
322 long[] ranks
= locationArray
.getRanks();
324 // Create and populate the context's traces contexts
325 final TmfExperimentContext context
= new TmfExperimentContext(fTraces
.length
);
327 // Position the traces
329 for (int i
= 0; i
< fTraces
.length
; i
++) {
330 // Get the relevant trace attributes
331 final ITmfContext traceContext
= fTraces
[i
].seekEvent(locations
[i
]);
332 context
.setContext(i
, traceContext
);
333 traceContext
.setRank(ranks
[i
]);
334 // update location after seek
335 locations
[i
] = traceContext
.getLocation();
336 context
.setEvent(i
, fTraces
[i
].getNext(traceContext
));
341 context
.setLocation(new TmfExperimentLocation(new TmfLocationArray(locations
, ranks
)));
342 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
343 context
.setRank(rank
);
348 // ------------------------------------------------------------------------
349 // ITmfTrace - SeekEvent operations (returning a trace context)
350 // ------------------------------------------------------------------------
353 public ITmfContext
seekEvent(final double ratio
) {
354 final ITmfContext context
= seekEvent(Math
.round(ratio
* getNbEvents()));
362 public double getLocationRatio(final ITmfLocation location
) {
363 if (location
instanceof TmfExperimentLocation
) {
365 TmfLocationArray locationArray
= ((TmfExperimentLocation
) location
).getLocationInfo();
366 for (int i
= 0; i
< locationArray
.size(); i
++) {
367 rank
+= locationArray
.getRank(i
);
369 return (double) rank
/ getNbEvents();
378 public ITmfLocation
getCurrentLocation() {
383 // ------------------------------------------------------------------------
384 // ITmfTrace trace positioning
385 // ------------------------------------------------------------------------
388 public synchronized ITmfEvent
parseEvent(final ITmfContext context
) {
389 final ITmfContext tmpContext
= seekEvent(context
.getLocation());
390 final ITmfEvent event
= getNext(tmpContext
);
395 public synchronized ITmfEvent
getNext(ITmfContext context
) {
397 // Validate the context
398 if (!(context
instanceof TmfExperimentContext
)) {
399 return null; // Throw an exception?
402 // Make sure that we have something to read from
403 if (fTraces
== null) {
407 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
409 // If an event was consumed previously, first get the next one from that
411 final int lastTrace
= expContext
.getLastTrace();
412 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
413 final ITmfContext traceContext
= expContext
.getContext(lastTrace
);
414 expContext
.setEvent(lastTrace
, fTraces
[lastTrace
].getNext(traceContext
));
415 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
418 // Scan the candidate events and identify the "next" trace to read from
419 int trace
= TmfExperimentContext
.NO_TRACE
;
420 ITmfTimestamp timestamp
= TmfTimestamp
.BIG_CRUNCH
;
421 for (int i
= 0; i
< fTraces
.length
; i
++) {
422 final ITmfEvent event
= expContext
.getEvent(i
);
423 if (event
!= null && event
.getTimestamp() != null) {
424 final ITmfTimestamp otherTS
= event
.getTimestamp();
425 if (otherTS
.compareTo(timestamp
) < 0) {
432 ITmfEvent event
= null;
433 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
434 event
= expContext
.getEvent(trace
);
436 updateAttributes(expContext
, event
.getTimestamp());
437 expContext
.increaseRank();
438 expContext
.setLastTrace(trace
);
439 final ITmfContext traceContext
= expContext
.getContext(trace
);
440 if (traceContext
== null) {
441 throw new IllegalStateException();
444 // Update the experiment location
445 TmfLocationArray locationArray
= new TmfLocationArray(
446 ((TmfExperimentLocation
) expContext
.getLocation()).getLocationInfo(),
447 trace
, traceContext
.getLocation(), traceContext
.getRank());
448 expContext
.setLocation(new TmfExperimentLocation(locationArray
));
461 public ITmfTimestamp
getInitialRangeOffset() {
462 if ((fTraces
== null) || (fTraces
.length
== 0)) {
463 return super.getInitialRangeOffset();
466 ITmfTimestamp initTs
= TmfTimestamp
.BIG_CRUNCH
;
467 for (int i
= 0; i
< fTraces
.length
; i
++) {
468 ITmfTimestamp ts
= fTraces
[i
].getInitialRangeOffset();
469 if (ts
.compareTo(initTs
) < 0) {
477 * Get the path to the folder in the supplementary file where
478 * synchronization-related data can be kept so they are not deleted when the
479 * experiment is synchronized. Analysis involved in synchronization can put
480 * their supplementary files in there so they are preserved after
483 * If the directory does not exist, it will be created. A return value of
484 * <code>null</code> means either the trace resource does not exist or
485 * supplementary resources cannot be kept.
488 * If <code>true</code>, it returns the absolute path in the file
489 * system, including the supplementary file path. Otherwise, it
490 * returns only the directory name.
491 * @return The path to the folder where synchronization-related
492 * supplementary files can be kept or <code>null</code> if not
496 public String
getSynchronizationFolder(boolean absolute
) {
497 /* Set up the path to the synchronization file we'll use */
498 IResource resource
= this.getResource();
499 String syncDirectory
= null;
502 /* get the directory where the file will be stored. */
503 if (resource
!= null) {
504 String fullDirectory
= resource
.getPersistentProperty(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER
);
505 /* Create the synchronization data directory if not present */
506 if (fullDirectory
!= null) {
507 fullDirectory
= fullDirectory
+ File
.separator
+ SYNCHRONIZATION_DIRECTORY
;
508 File syncDir
= new File(fullDirectory
);
512 syncDirectory
= fullDirectory
;
514 syncDirectory
= SYNCHRONIZATION_DIRECTORY
;
517 } catch (CoreException e
) {
521 return syncDirectory
;
525 * Synchronizes the traces of an experiment. By default it only tries to
526 * read a synchronization file if it exists
528 * @return The synchronization object
531 public SynchronizationAlgorithm
synchronizeTraces() {
532 return synchronizeTraces(false);
536 * Synchronizes the traces of an experiment.
539 * Whether to actually synchronize or just try opening a sync
541 * @return The synchronization object
544 public SynchronizationAlgorithm
synchronizeTraces(boolean doSync
) {
548 String syncDirectory
= getSynchronizationFolder(true);
550 final File syncFile
= (syncDirectory
!= null) ?
new File(syncDirectory
+ File
.separator
+ SYNCHRONIZATION_FILE_NAME
) : null;
552 final SynchronizationAlgorithm syncAlgo
= SynchronizationManager
.synchronizeTraces(syncFile
, Collections
.<ITmfTrace
> singleton(this), doSync
);
554 final TmfTraceSynchronizedSignal signal
= new TmfTraceSynchronizedSignal(this, syncAlgo
);
556 /* Broadcast in separate thread to prevent deadlock */
571 @SuppressWarnings("nls")
572 public synchronized String
toString() {
573 return "[TmfExperiment (" + getName() + ")]";
576 // ------------------------------------------------------------------------
578 // ------------------------------------------------------------------------
580 private synchronized void initializeStreamingMonitor() {
587 if (getStreamingInterval() == 0) {
588 final ITmfContext context
= seekEvent(0);
589 final ITmfEvent event
= getNext(context
);
594 final TmfTimeRange timeRange
= new TmfTimeRange(event
.getTimestamp(), TmfTimestamp
.BIG_CRUNCH
);
595 final TmfTraceRangeUpdatedSignal signal
= new TmfTraceRangeUpdatedSignal(this, this, timeRange
);
597 // Broadcast in separate thread to prevent deadlock
607 final Thread thread
= new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
608 private ITmfTimestamp safeTimestamp
= null;
609 private ITmfTimestamp lastSafeTimestamp
= null;
610 private TmfTimeRange timeRange
= null;
614 while (!executorIsShutdown()) {
615 if (!getIndexer().isIndexing()) {
616 ITmfTimestamp startTimestamp
= TmfTimestamp
.BIG_CRUNCH
;
617 ITmfTimestamp endTimestamp
= TmfTimestamp
.BIG_BANG
;
618 for (final ITmfTrace trace
: fTraces
) {
619 if (trace
.getStartTime().compareTo(startTimestamp
) < 0) {
620 startTimestamp
= trace
.getStartTime();
622 if (trace
.getStreamingInterval() != 0 && trace
.getEndTime().compareTo(endTimestamp
) > 0) {
623 endTimestamp
= trace
.getEndTime();
626 if (safeTimestamp
!= null && (lastSafeTimestamp
== null || safeTimestamp
.compareTo(lastSafeTimestamp
) > 0)) {
627 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
628 lastSafeTimestamp
= safeTimestamp
;
632 safeTimestamp
= endTimestamp
;
633 if (timeRange
!= null) {
634 final TmfTraceRangeUpdatedSignal signal
=
635 new TmfTraceRangeUpdatedSignal(TmfExperiment
.this, TmfExperiment
.this, timeRange
);
640 Thread
.sleep(getStreamingInterval());
641 } catch (final InterruptedException e
) {
651 public long getStreamingInterval() {
653 for (final ITmfTrace trace
: fTraces
) {
654 interval
= Math
.max(interval
, trace
.getStreamingInterval());
659 // ------------------------------------------------------------------------
661 // ------------------------------------------------------------------------
665 public void traceOpened(TmfTraceOpenedSignal signal
) {
666 if (signal
.getTrace() == this) {
667 initializeStreamingMonitor();
669 /* Initialize the analysis */
670 MultiStatus status
= new MultiStatus(Activator
.PLUGIN_ID
, IStatus
.OK
, null, null);
671 status
.add(executeAnalysis());
672 if (!status
.isOK()) {
673 Activator
.log(status
);
675 TmfTraceManager
.refreshSupplementaryFiles(this);
683 public synchronized int getCheckpointSize() {
684 int totalCheckpointSize
= 0;
686 if (fTraces
!= null) {
687 for (final ITmfTrace trace
: fTraces
) {
688 if (!(trace
instanceof ITmfPersistentlyIndexable
)) {
692 ITmfPersistentlyIndexable persistableIndexTrace
= (ITmfPersistentlyIndexable
) trace
;
693 int currentTraceCheckpointSize
= persistableIndexTrace
.getCheckpointSize();
694 if (currentTraceCheckpointSize
<= 0) {
697 totalCheckpointSize
+= currentTraceCheckpointSize
;
698 // each entry in the TmfLocationArray has a rank in addition
700 totalCheckpointSize
+= 8;
703 } catch (UnsupportedOperationException e
) {
707 return totalCheckpointSize
;
714 public ITmfLocation
restoreLocation(ByteBuffer bufferIn
) {
715 ITmfLocation
[] locations
= new ITmfLocation
[fTraces
.length
];
716 long[] ranks
= new long[fTraces
.length
];
717 for (int i
= 0; i
< fTraces
.length
; ++i
) {
718 final ITmfTrace trace
= fTraces
[i
];
719 locations
[i
] = ((ITmfPersistentlyIndexable
) trace
).restoreLocation(bufferIn
);
720 ranks
[i
] = bufferIn
.getLong();
722 TmfLocationArray arr
= new TmfLocationArray(locations
, ranks
);
723 TmfExperimentLocation l
= new TmfExperimentLocation(arr
);