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
.linuxtools
.tmf
.core
.trace
;
21 import java
.nio
.ByteBuffer
;
22 import java
.util
.Arrays
;
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
.MultiStatus
;
29 import org
.eclipse
.core
.runtime
.Status
;
30 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.Activator
;
31 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfExperimentContext
;
32 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfExperimentLocation
;
33 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfLocationArray
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TmfTraceException
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfEventRequest
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
39 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceRangeUpdatedSignal
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceSynchronizedSignal
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.synchronization
.SynchronizationAlgorithm
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.synchronization
.SynchronizationManager
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
46 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
47 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.ITmfPersistentlyIndexable
;
48 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.ITmfTraceIndexer
;
49 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.TmfBTreeTraceIndexer
;
50 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.location
.ITmfLocation
;
53 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
54 * that are part of a tracing experiment.
57 * @author Francois Chouinard
59 public class TmfExperiment
extends TmfTrace
implements ITmfEventParser
, ITmfPersistentlyIndexable
{
61 // ------------------------------------------------------------------------
63 // ------------------------------------------------------------------------
66 * The file name of the Synchronization
69 * @deprecated This file name shouldn't be used directly anymore. All
70 * synchronization files have been moved to a folder and you
71 * should use the {@link #getSynchronizationFolder(boolean)}
72 * method to return the path to this folder.
75 public static final String SYNCHRONIZATION_FILE_NAME
= "synchronization.bin"; //$NON-NLS-1$
78 * The name of the directory containing trace synchronization data. This
79 * directory typically will be preserved when traces are synchronized.
80 * Analysis involved in synchronization can put their supplementary files in
81 * there so they are not deleted when synchronized traces are copied.
83 private static final String SYNCHRONIZATION_DIRECTORY
= "sync_data"; //$NON-NLS-1$
86 * The default index page size
88 public static final int DEFAULT_INDEX_PAGE_SIZE
= 5000;
90 // ------------------------------------------------------------------------
92 // ------------------------------------------------------------------------
95 * The set of traces that constitute the experiment
97 protected ITmfTrace
[] fTraces
;
100 * The set of traces that constitute the experiment
102 private boolean fInitialized
= false;
104 // ------------------------------------------------------------------------
106 // ------------------------------------------------------------------------
109 * Default constructor
113 public TmfExperiment() {
118 * Constructor with parameters
125 * the experiment set of traces
127 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
) {
128 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
, null);
132 * Constructor of experiment taking type, path, traces and resource
139 * the experiment set of traces
141 * the resource associated to the experiment
143 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
, IResource resource
) {
144 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
, resource
);
151 * the experiment path
153 * the experiment set of traces
154 * @param indexPageSize
155 * the experiment index page size
157 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
) {
158 this(type
, path
, traces
, indexPageSize
, null);
162 * Full constructor of an experiment, taking the type, path, traces,
163 * indexPageSize and resource
168 * the experiment path
170 * the experiment set of traces
171 * @param indexPageSize
172 * the experiment index page size
174 * the resource associated to the experiment
176 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
, IResource resource
) {
177 initExperiment(type
, path
, traces
, indexPageSize
, resource
);
181 protected ITmfTraceIndexer
createIndexer(int interval
) {
182 if (getCheckpointSize() > 0) {
183 return new TmfBTreeTraceIndexer(this, interval
);
185 return super.createIndexer(interval
);
189 * Clears the experiment
192 public synchronized void dispose() {
194 // Clean up the index if applicable
195 if (getIndexer() != null) {
196 getIndexer().dispose();
199 if (fTraces
!= null) {
200 for (final ITmfTrace trace
: fTraces
) {
208 // ------------------------------------------------------------------------
209 // ITmfTrace - Initializers
210 // ------------------------------------------------------------------------
213 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> type
) {
217 * Initialization of an experiment, taking the type, path, traces,
218 * indexPageSize and resource
223 * the experiment path
225 * the experiment set of traces
226 * @param indexPageSize
227 * the experiment index page size
229 * the resource associated to the experiment
232 public void initExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
, IResource resource
) {
233 setCacheSize(indexPageSize
);
234 setStreamingInterval(0);
236 // traces have to be set before super.initialize()
239 super.initialize(resource
, path
, type
);
240 } catch (TmfTraceException e
) {
241 Activator
.logError("Error initializing experiment", e
); //$NON-NLS-1$
244 if (resource
!= null) {
245 this.synchronizeTraces();
253 public IStatus
validate(final IProject project
, final String path
) {
254 return Status
.OK_STATUS
;
257 // ------------------------------------------------------------------------
259 // ------------------------------------------------------------------------
262 * Get the traces contained in this experiment.
264 * @return The array of contained traces
266 public ITmfTrace
[] getTraces() {
271 * Returns the timestamp of the event at the requested index. If none,
275 * the event index (rank)
276 * @return the corresponding event timestamp
279 public ITmfTimestamp
getTimestamp(final int index
) {
280 final ITmfContext context
= seekEvent(index
);
281 final ITmfEvent event
= getNext(context
);
283 return (event
!= null) ? event
.getTimestamp() : null;
286 // ------------------------------------------------------------------------
287 // Request management
288 // ------------------------------------------------------------------------
294 public synchronized ITmfContext
armRequest(final ITmfEventRequest request
) {
296 // Make sure we have something to read from
297 if (fTraces
== null) {
301 if (!TmfTimestamp
.BIG_BANG
.equals(request
.getRange().getStartTime())
302 && request
.getIndex() == 0) {
303 final ITmfContext context
= seekEvent(request
.getRange().getStartTime());
304 request
.setStartIndex((int) context
.getRank());
309 return seekEvent(request
.getIndex());
312 // ------------------------------------------------------------------------
313 // ITmfTrace trace positioning
314 // ------------------------------------------------------------------------
320 public synchronized ITmfContext
seekEvent(final ITmfLocation location
) {
321 // Validate the location
322 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
323 return null; // Throw an exception?
325 // Make sure we have something to read from
326 if (fTraces
== null) {
330 // Initialize the location array if necessary
331 TmfLocationArray locationArray
= ((location
== null) ?
332 new TmfLocationArray(fTraces
.length
) :
333 ((TmfExperimentLocation
) location
).getLocationInfo());
335 ITmfLocation
[] locations
= locationArray
.getLocations();
336 long[] ranks
= locationArray
.getRanks();
338 // Create and populate the context's traces contexts
339 final TmfExperimentContext context
= new TmfExperimentContext(fTraces
.length
);
341 // Position the traces
343 for (int i
= 0; i
< fTraces
.length
; i
++) {
344 // Get the relevant trace attributes
345 final ITmfContext traceContext
= fTraces
[i
].seekEvent(locations
[i
]);
346 context
.setContext(i
, traceContext
);
347 traceContext
.setRank(ranks
[i
]);
348 // update location after seek
349 locations
[i
] = traceContext
.getLocation();
350 context
.setEvent(i
, fTraces
[i
].getNext(traceContext
));
355 context
.setLocation(new TmfExperimentLocation(new TmfLocationArray(locations
, ranks
)));
356 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
357 context
.setRank(rank
);
362 // ------------------------------------------------------------------------
363 // ITmfTrace - SeekEvent operations (returning a trace context)
364 // ------------------------------------------------------------------------
367 public ITmfContext
seekEvent(final double ratio
) {
368 final ITmfContext context
= seekEvent(Math
.round(ratio
* getNbEvents()));
376 public double getLocationRatio(final ITmfLocation location
) {
377 if (location
instanceof TmfExperimentLocation
) {
379 TmfLocationArray locationArray
= ((TmfExperimentLocation
) location
).getLocationInfo();
380 for (int i
= 0; i
< locationArray
.size(); i
++) {
381 rank
+= locationArray
.getRank(i
);
383 return (double) rank
/ getNbEvents();
392 public ITmfLocation
getCurrentLocation() {
397 // ------------------------------------------------------------------------
398 // ITmfTrace trace positioning
399 // ------------------------------------------------------------------------
402 public synchronized ITmfEvent
parseEvent(final ITmfContext context
) {
403 final ITmfContext tmpContext
= seekEvent(context
.getLocation());
404 final ITmfEvent event
= getNext(tmpContext
);
409 public synchronized ITmfEvent
getNext(ITmfContext context
) {
411 // Validate the context
412 if (!(context
instanceof TmfExperimentContext
)) {
413 return null; // Throw an exception?
416 // Make sure that we have something to read from
417 if (fTraces
== null) {
421 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
423 // If an event was consumed previously, first get the next one from that
425 final int lastTrace
= expContext
.getLastTrace();
426 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
427 final ITmfContext traceContext
= expContext
.getContext(lastTrace
);
428 expContext
.setEvent(lastTrace
, fTraces
[lastTrace
].getNext(traceContext
));
429 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
432 // Scan the candidate events and identify the "next" trace to read from
433 int trace
= TmfExperimentContext
.NO_TRACE
;
434 ITmfTimestamp timestamp
= TmfTimestamp
.BIG_CRUNCH
;
435 for (int i
= 0; i
< fTraces
.length
; i
++) {
436 final ITmfEvent event
= expContext
.getEvent(i
);
437 if (event
!= null && event
.getTimestamp() != null) {
438 final ITmfTimestamp otherTS
= event
.getTimestamp();
439 if (otherTS
.compareTo(timestamp
, true) < 0) {
446 ITmfEvent event
= null;
447 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
448 event
= expContext
.getEvent(trace
);
450 updateAttributes(expContext
, event
.getTimestamp());
451 expContext
.increaseRank();
452 expContext
.setLastTrace(trace
);
453 final ITmfContext traceContext
= expContext
.getContext(trace
);
454 if (traceContext
== null) {
455 throw new IllegalStateException();
458 // Update the experiment location
459 TmfLocationArray locationArray
= new TmfLocationArray(
460 ((TmfExperimentLocation
) expContext
.getLocation()).getLocationInfo(),
461 trace
, traceContext
.getLocation(), traceContext
.getRank());
462 expContext
.setLocation(new TmfExperimentLocation(locationArray
));
475 public ITmfTimestamp
getInitialRangeOffset() {
476 if ((fTraces
== null) || (fTraces
.length
== 0)) {
477 return super.getInitialRangeOffset();
480 ITmfTimestamp initTs
= TmfTimestamp
.BIG_CRUNCH
;
481 for (int i
= 0; i
< fTraces
.length
; i
++) {
482 ITmfTimestamp ts
= fTraces
[i
].getInitialRangeOffset();
483 if (ts
.compareTo(initTs
) < 0) {
491 * Get the path to the folder in the supplementary file where
492 * synchronization-related data can be kept so they are not deleted when the
493 * experiment is synchronized. Analysis involved in synchronization can put
494 * their supplementary files in there so they are preserved after
497 * If the directory does not exist, it will be created. A return value of
498 * <code>null</code> means either the trace resource does not exist or
499 * supplementary resources cannot be kept.
502 * If <code>true</code>, it returns the absolute path in the file
503 * system, including the supplementary file path. Otherwise, it
504 * returns only the directory name.
505 * @return The path to the folder where synchronization-related
506 * supplementary files can be kept or <code>null</code> if not
510 public String
getSynchronizationFolder(boolean absolute
) {
511 /* Set up the path to the synchronization file we'll use */
512 IResource resource
= this.getResource();
513 String syncDirectory
= null;
516 /* get the directory where the file will be stored. */
517 if (resource
!= null) {
518 String fullDirectory
= resource
.getPersistentProperty(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER
);
519 /* Create the synchronization data directory if not present */
520 if (fullDirectory
!= null) {
521 fullDirectory
= fullDirectory
+ File
.separator
+ SYNCHRONIZATION_DIRECTORY
;
522 File syncDir
= new File(fullDirectory
);
526 syncDirectory
= fullDirectory
;
528 syncDirectory
= SYNCHRONIZATION_DIRECTORY
;
531 } catch (CoreException e
) {
535 return syncDirectory
;
539 * Synchronizes the traces of an experiment. By default it only tries to
540 * read a synchronization file if it exists
542 * @return The synchronization object
545 public synchronized SynchronizationAlgorithm
synchronizeTraces() {
546 return synchronizeTraces(false);
550 * Synchronizes the traces of an experiment.
553 * Whether to actually synchronize or just try opening a sync
555 * @return The synchronization object
558 public synchronized SynchronizationAlgorithm
synchronizeTraces(boolean doSync
) {
560 String syncDirectory
= getSynchronizationFolder(true);
562 final File syncFile
= (syncDirectory
!= null) ?
new File(syncDirectory
+ File
.separator
+ SYNCHRONIZATION_FILE_NAME
) : null;
564 final SynchronizationAlgorithm syncAlgo
= SynchronizationManager
.synchronizeTraces(syncFile
, Arrays
.asList(fTraces
), doSync
);
566 final TmfTraceSynchronizedSignal signal
= new TmfTraceSynchronizedSignal(this, syncAlgo
);
568 /* Broadcast in separate thread to prevent deadlock */
580 @SuppressWarnings("nls")
581 public synchronized String
toString() {
582 return "[TmfExperiment (" + getName() + ")]";
585 // ------------------------------------------------------------------------
587 // ------------------------------------------------------------------------
589 private synchronized void initializeStreamingMonitor() {
596 if (getStreamingInterval() == 0) {
597 final ITmfContext context
= seekEvent(0);
598 final ITmfEvent event
= getNext(context
);
603 final TmfTimeRange timeRange
= new TmfTimeRange(event
.getTimestamp(), TmfTimestamp
.BIG_CRUNCH
);
604 final TmfTraceRangeUpdatedSignal signal
= new TmfTraceRangeUpdatedSignal(this, this, timeRange
);
606 // Broadcast in separate thread to prevent deadlock
616 final Thread thread
= new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
617 private ITmfTimestamp safeTimestamp
= null;
618 private ITmfTimestamp lastSafeTimestamp
= null;
619 private TmfTimeRange timeRange
= null;
623 while (!executorIsShutdown()) {
624 if (!getIndexer().isIndexing()) {
625 ITmfTimestamp startTimestamp
= TmfTimestamp
.BIG_CRUNCH
;
626 ITmfTimestamp endTimestamp
= TmfTimestamp
.BIG_BANG
;
627 for (final ITmfTrace trace
: fTraces
) {
628 if (trace
.getStartTime().compareTo(startTimestamp
) < 0) {
629 startTimestamp
= trace
.getStartTime();
631 if (trace
.getStreamingInterval() != 0 && trace
.getEndTime().compareTo(endTimestamp
) > 0) {
632 endTimestamp
= trace
.getEndTime();
635 if (safeTimestamp
!= null && (lastSafeTimestamp
== null || safeTimestamp
.compareTo(lastSafeTimestamp
, false) > 0)) {
636 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
637 lastSafeTimestamp
= safeTimestamp
;
641 safeTimestamp
= endTimestamp
;
642 if (timeRange
!= null) {
643 final TmfTraceRangeUpdatedSignal signal
=
644 new TmfTraceRangeUpdatedSignal(TmfExperiment
.this, TmfExperiment
.this, timeRange
);
649 Thread
.sleep(getStreamingInterval());
650 } catch (final InterruptedException e
) {
660 public long getStreamingInterval() {
662 for (final ITmfTrace trace
: fTraces
) {
663 interval
= Math
.max(interval
, trace
.getStreamingInterval());
668 // ------------------------------------------------------------------------
670 // ------------------------------------------------------------------------
674 public void traceOpened(TmfTraceOpenedSignal signal
) {
675 if (signal
.getTrace() == this) {
676 initializeStreamingMonitor();
678 /* Initialize the analysis */
679 MultiStatus status
= new MultiStatus(Activator
.PLUGIN_ID
, IStatus
.OK
, null, null);
680 status
.add(executeAnalysis());
681 if (!status
.isOK()) {
682 Activator
.log(status
);
684 TmfTraceManager
.refreshSupplementaryFiles(this);
692 public synchronized int getCheckpointSize() {
693 int totalCheckpointSize
= 0;
695 if (fTraces
!= null) {
696 for (final ITmfTrace trace
: fTraces
) {
697 if (!(trace
instanceof ITmfPersistentlyIndexable
)) {
701 ITmfPersistentlyIndexable persistableIndexTrace
= (ITmfPersistentlyIndexable
) trace
;
702 int currentTraceCheckpointSize
= persistableIndexTrace
.getCheckpointSize();
703 if (currentTraceCheckpointSize
<= 0) {
706 totalCheckpointSize
+= currentTraceCheckpointSize
;
707 // each entry in the TmfLocationArray has a rank in addition
709 totalCheckpointSize
+= 8;
712 } catch (UnsupportedOperationException e
) {
716 return totalCheckpointSize
;
723 public ITmfLocation
restoreLocation(ByteBuffer bufferIn
) {
724 ITmfLocation
[] locations
= new ITmfLocation
[fTraces
.length
];
725 long[] ranks
= new long[fTraces
.length
];
726 for (int i
= 0; i
< fTraces
.length
; ++i
) {
727 final ITmfTrace trace
= fTraces
[i
];
728 locations
[i
] = ((ITmfPersistentlyIndexable
) trace
).restoreLocation(bufferIn
);
729 ranks
[i
] = bufferIn
.getLong();
731 TmfLocationArray arr
= new TmfLocationArray(locations
, ranks
);
732 TmfExperimentLocation l
= new TmfExperimentLocation(arr
);