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 *******************************************************************************/
17 package org
.eclipse
.linuxtools
.tmf
.core
.trace
;
20 import java
.nio
.ByteBuffer
;
22 import org
.eclipse
.core
.resources
.IFile
;
23 import org
.eclipse
.core
.resources
.IProject
;
24 import org
.eclipse
.core
.resources
.IResource
;
25 import org
.eclipse
.core
.runtime
.CoreException
;
26 import org
.eclipse
.core
.runtime
.IStatus
;
27 import org
.eclipse
.core
.runtime
.Status
;
28 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.Activator
;
29 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfExperimentContext
;
30 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfExperimentLocation
;
31 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfLocationArray
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.TmfCommonConstants
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TmfTraceException
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfEventRequest
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceRangeUpdatedSignal
;
39 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceSynchronizedSignal
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.synchronization
.SynchronizationAlgorithm
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.synchronization
.SynchronizationManager
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.ITmfPersistentlyIndexable
;
46 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.ITmfTraceIndexer
;
47 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.TmfBTreeTraceIndexer
;
48 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.location
.ITmfLocation
;
51 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
52 * that are part of a tracing experiment.
55 * @author Francois Chouinard
57 public class TmfExperiment
extends TmfTrace
implements ITmfEventParser
, ITmfPersistentlyIndexable
{
59 // ------------------------------------------------------------------------
61 // ------------------------------------------------------------------------
64 * The file name of the Synchronization
68 public final static String SYNCHRONIZATION_FILE_NAME
= "synchronization.bin"; //$NON-NLS-1$
71 * The default index page size
73 public static final int DEFAULT_INDEX_PAGE_SIZE
= 5000;
75 // ------------------------------------------------------------------------
77 // ------------------------------------------------------------------------
80 * The set of traces that constitute the experiment
82 protected ITmfTrace
[] fTraces
;
85 * The set of traces that constitute the experiment
87 private boolean fInitialized
= false;
90 * The experiment bookmarks file
92 private IFile fBookmarksFile
;
94 // ------------------------------------------------------------------------
96 // ------------------------------------------------------------------------
104 * the experiment set of traces
106 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
) {
107 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
, null);
111 * Constructor of experiment taking type, path, traces and resource
118 * the experiment set of traces
120 * the resource associated to the experiment
122 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
, IResource resource
) {
123 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
, resource
);
130 * the experiment path
132 * the experiment set of traces
133 * @param indexPageSize
134 * the experiment index page size
136 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
) {
137 this(type
, path
, traces
, indexPageSize
, null);
141 * Full constructor of an experiment, taking the type, path, traces,
142 * indexPageSize and resource
147 * the experiment path
149 * the experiment set of traces
150 * @param indexPageSize
151 * the experiment index page size
153 * the resource associated to the experiment
155 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
, IResource resource
) {
156 setCacheSize(indexPageSize
);
157 setStreamingInterval(0);
161 super.initialize(resource
, path
, type
);
162 } catch (TmfTraceException e
) {
166 if (resource
!= null) {
168 this.synchronizeTraces();
169 } catch (TmfTraceException e
) {
170 Activator
.logError("Error synchronizing experiment", e
); //$NON-NLS-1$
176 protected ITmfTraceIndexer
createIndexer(int interval
) {
177 if (getCheckpointSize() > 0) {
178 return new TmfBTreeTraceIndexer(this, interval
);
180 return super.createIndexer(interval
);
184 * Clears the experiment
187 public synchronized void dispose() {
189 // Clean up the index if applicable
190 if (getIndexer() != null) {
191 getIndexer().dispose();
194 if (fTraces
!= null) {
195 for (final ITmfTrace trace
: fTraces
) {
203 // ------------------------------------------------------------------------
204 // ITmfTrace - Initializers
205 // ------------------------------------------------------------------------
208 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> type
) {
215 public IStatus
validate(final IProject project
, final String path
) {
216 return Status
.OK_STATUS
;
219 // ------------------------------------------------------------------------
221 // ------------------------------------------------------------------------
224 * Get the traces contained in this experiment.
226 * @return The array of contained traces
228 public ITmfTrace
[] getTraces() {
233 * Returns the timestamp of the event at the requested index. If none,
237 * the event index (rank)
238 * @return the corresponding event timestamp
241 public ITmfTimestamp
getTimestamp(final int index
) {
242 final ITmfContext context
= seekEvent(index
);
243 final ITmfEvent event
= getNext(context
);
245 return (event
!= null) ? event
.getTimestamp() : null;
249 * Set the file to be used for bookmarks on this experiment
254 public void setBookmarksFile(final IFile file
) {
255 fBookmarksFile
= file
;
259 * Get the file used for bookmarks on this experiment
261 * @return the bookmarks file or null if none is set
263 public IFile
getBookmarksFile() {
264 return fBookmarksFile
;
267 // ------------------------------------------------------------------------
268 // Request management
269 // ------------------------------------------------------------------------
275 public synchronized ITmfContext
armRequest(final ITmfEventRequest request
) {
277 // Make sure we have something to read from
278 if (fTraces
== null) {
282 if (!TmfTimestamp
.BIG_BANG
.equals(request
.getRange().getStartTime())
283 && request
.getIndex() == 0) {
284 final ITmfContext context
= seekEvent(request
.getRange().getStartTime());
285 request
.setStartIndex((int) context
.getRank());
290 return seekEvent(request
.getIndex());
293 // ------------------------------------------------------------------------
294 // ITmfTrace trace positioning
295 // ------------------------------------------------------------------------
301 public synchronized ITmfContext
seekEvent(final ITmfLocation location
) {
302 // Validate the location
303 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
304 return null; // Throw an exception?
306 // Make sure we have something to read from
307 if (fTraces
== null) {
311 // Initialize the location array if necessary
312 TmfLocationArray locationArray
= ((location
== null) ?
313 new TmfLocationArray(fTraces
.length
) :
314 ((TmfExperimentLocation
) location
).getLocationInfo());
316 ITmfLocation
[] locations
= locationArray
.getLocations();
317 long[] ranks
= locationArray
.getRanks();
319 // Create and populate the context's traces contexts
320 final TmfExperimentContext context
= new TmfExperimentContext(fTraces
.length
);
322 // Position the traces
324 for (int i
= 0; i
< fTraces
.length
; i
++) {
325 // Get the relevant trace attributes
326 final ITmfContext traceContext
= fTraces
[i
].seekEvent(locations
[i
]);
327 context
.getContexts()[i
] = traceContext
;
328 traceContext
.setRank(ranks
[i
]);
329 locations
[i
] = traceContext
.getLocation(); // update location after seek
330 context
.getEvents()[i
] = fTraces
[i
].getNext(traceContext
);
335 context
.setLocation(new TmfExperimentLocation(new TmfLocationArray(locations
, ranks
)));
336 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
337 context
.setRank(rank
);
342 // ------------------------------------------------------------------------
343 // ITmfTrace - SeekEvent operations (returning a trace context)
344 // ------------------------------------------------------------------------
347 public ITmfContext
seekEvent(final double ratio
) {
348 final ITmfContext context
= seekEvent(Math
.round(ratio
* getNbEvents()));
356 public double getLocationRatio(final ITmfLocation location
) {
357 if (location
instanceof TmfExperimentLocation
) {
359 TmfLocationArray locationArray
= ((TmfExperimentLocation
) location
).getLocationInfo();
360 for (int i
= 0; i
< locationArray
.size(); i
++) {
361 rank
+= locationArray
.getRank(i
);
363 return (double) rank
/ getNbEvents();
372 public ITmfLocation
getCurrentLocation() {
377 // ------------------------------------------------------------------------
378 // ITmfTrace trace positioning
379 // ------------------------------------------------------------------------
382 public synchronized ITmfEvent
parseEvent(final ITmfContext context
) {
383 final ITmfContext tmpContext
= seekEvent(context
.getLocation());
384 final ITmfEvent event
= getNext(tmpContext
);
389 public synchronized ITmfEvent
getNext(ITmfContext context
) {
391 // Validate the context
392 if (!(context
instanceof TmfExperimentContext
)) {
393 return null; // Throw an exception?
396 // Make sure that we have something to read from
397 if (fTraces
== null) {
401 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
403 // If an event was consumed previously, first get the next one from that
405 final int lastTrace
= expContext
.getLastTrace();
406 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
407 final ITmfContext traceContext
= expContext
.getContexts()[lastTrace
];
408 expContext
.getEvents()[lastTrace
] = fTraces
[lastTrace
].getNext(traceContext
);
409 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
412 // Scan the candidate events and identify the "next" trace to read from
413 int trace
= TmfExperimentContext
.NO_TRACE
;
414 ITmfTimestamp timestamp
= TmfTimestamp
.BIG_CRUNCH
;
415 for (int i
= 0; i
< fTraces
.length
; i
++) {
416 final ITmfEvent event
= expContext
.getEvents()[i
];
417 if (event
!= null && event
.getTimestamp() != null) {
418 final ITmfTimestamp otherTS
= event
.getTimestamp();
419 if (otherTS
.compareTo(timestamp
, true) < 0) {
426 ITmfEvent event
= null;
427 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
428 event
= expContext
.getEvents()[trace
];
430 updateAttributes(expContext
, event
.getTimestamp());
431 expContext
.increaseRank();
432 expContext
.setLastTrace(trace
);
433 final ITmfContext traceContext
= expContext
.getContexts()[trace
];
435 // Update the experiment location
436 TmfLocationArray locationArray
= new TmfLocationArray(
437 ((TmfExperimentLocation
) expContext
.getLocation()).getLocationInfo(),
438 trace
, traceContext
.getLocation(), traceContext
.getRank());
439 expContext
.setLocation(new TmfExperimentLocation(locationArray
));
452 public ITmfTimestamp
getInitialRangeOffset() {
453 if ((fTraces
== null) || (fTraces
.length
== 0)) {
454 return super.getInitialRangeOffset();
457 ITmfTimestamp initTs
= TmfTimestamp
.BIG_CRUNCH
;
458 for (int i
= 0; i
< fTraces
.length
; i
++) {
459 ITmfTimestamp ts
= fTraces
[i
].getInitialRangeOffset();
460 if (ts
.compareTo(initTs
) < 0) {
468 * Synchronizes the traces of an experiment. By default it only tries to
469 * read a synchronization file if it exists
471 * @return The synchronization object
472 * @throws TmfTraceException
473 * propagate TmfTraceExceptions
476 public synchronized SynchronizationAlgorithm
synchronizeTraces() throws TmfTraceException
{
477 return synchronizeTraces(false);
481 * Synchronizes the traces of an experiment.
484 * Whether to actually synchronize or just try opening a sync
486 * @return The synchronization object
487 * @throws TmfTraceException
488 * propagate TmfTraceExceptions
491 public synchronized SynchronizationAlgorithm
synchronizeTraces(boolean doSync
) throws TmfTraceException
{
493 /* Set up the path to the synchronization file we'll use */
494 IResource resource
= this.getResource();
495 String supplDirectory
= null;
498 /* get the directory where the file will be stored. */
499 if (resource
!= null) {
500 supplDirectory
= resource
.getPersistentProperty(TmfCommonConstants
.TRACE_SUPPLEMENTARY_FOLDER
);
502 } catch (CoreException e
) {
503 throw new TmfTraceException(e
.toString(), e
);
506 final File syncFile
= (supplDirectory
!= null) ?
new File(supplDirectory
+ File
.separator
+ SYNCHRONIZATION_FILE_NAME
) : null;
508 final SynchronizationAlgorithm syncAlgo
= SynchronizationManager
.synchronizeTraces(syncFile
, fTraces
, doSync
);
510 final TmfTraceSynchronizedSignal signal
= new TmfTraceSynchronizedSignal(this, syncAlgo
);
512 /* Broadcast in separate thread to prevent deadlock */
524 @SuppressWarnings("nls")
525 public synchronized String
toString() {
526 return "[TmfExperiment (" + getName() + ")]";
529 // ------------------------------------------------------------------------
531 // ------------------------------------------------------------------------
533 private synchronized void initializeStreamingMonitor() {
540 if (getStreamingInterval() == 0) {
541 final ITmfContext context
= seekEvent(0);
542 final ITmfEvent event
= getNext(context
);
547 final TmfTimeRange timeRange
= new TmfTimeRange(event
.getTimestamp(), TmfTimestamp
.BIG_CRUNCH
);
548 final TmfTraceRangeUpdatedSignal signal
= new TmfTraceRangeUpdatedSignal(this, this, timeRange
);
550 // Broadcast in separate thread to prevent deadlock
560 final Thread thread
= new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
561 private ITmfTimestamp safeTimestamp
= null;
562 private ITmfTimestamp lastSafeTimestamp
= null;
563 private TmfTimeRange timeRange
= null;
567 while (!executorIsShutdown()) {
568 if (!getIndexer().isIndexing()) {
569 ITmfTimestamp startTimestamp
= TmfTimestamp
.BIG_CRUNCH
;
570 ITmfTimestamp endTimestamp
= TmfTimestamp
.BIG_BANG
;
571 for (final ITmfTrace trace
: fTraces
) {
572 if (trace
.getStartTime().compareTo(startTimestamp
) < 0) {
573 startTimestamp
= trace
.getStartTime();
575 if (trace
.getStreamingInterval() != 0 && trace
.getEndTime().compareTo(endTimestamp
) > 0) {
576 endTimestamp
= trace
.getEndTime();
579 if (safeTimestamp
!= null && (lastSafeTimestamp
== null || safeTimestamp
.compareTo(lastSafeTimestamp
, false) > 0)) {
580 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
581 lastSafeTimestamp
= safeTimestamp
;
585 safeTimestamp
= endTimestamp
;
586 if (timeRange
!= null) {
587 final TmfTraceRangeUpdatedSignal signal
=
588 new TmfTraceRangeUpdatedSignal(TmfExperiment
.this, TmfExperiment
.this, timeRange
);
593 Thread
.sleep(getStreamingInterval());
594 } catch (final InterruptedException e
) {
604 public long getStreamingInterval() {
606 for (final ITmfTrace trace
: fTraces
) {
607 interval
= Math
.max(interval
, trace
.getStreamingInterval());
612 // ------------------------------------------------------------------------
614 // ------------------------------------------------------------------------
618 public void traceOpened(TmfTraceOpenedSignal signal
) {
619 if (signal
.getTrace() == this) {
620 initializeStreamingMonitor();
628 public synchronized int getCheckpointSize() {
629 int totalCheckpointSize
= 0;
631 if (fTraces
!= null) {
632 for (final ITmfTrace trace
: fTraces
) {
633 if (!(trace
instanceof ITmfPersistentlyIndexable
)) {
637 ITmfPersistentlyIndexable persistableIndexTrace
= (ITmfPersistentlyIndexable
) trace
;
638 int currentTraceCheckpointSize
= persistableIndexTrace
.getCheckpointSize();
639 if (currentTraceCheckpointSize
<= 0) {
642 totalCheckpointSize
+= currentTraceCheckpointSize
;
643 totalCheckpointSize
+= 8; // each entry in the TmfLocationArray has a rank in addition of the location
646 } catch (UnsupportedOperationException e
) {
650 return totalCheckpointSize
;
657 public ITmfLocation
restoreLocation(ByteBuffer bufferIn
) {
658 ITmfLocation
[] locations
= new ITmfLocation
[fTraces
.length
];
659 long[] ranks
= new long[fTraces
.length
];
660 for (int i
= 0; i
< fTraces
.length
; ++i
) {
661 final ITmfTrace trace
= fTraces
[i
];
662 locations
[i
] = ((ITmfPersistentlyIndexable
) trace
).restoreLocation(bufferIn
);
663 ranks
[i
] = bufferIn
.getLong();
665 TmfLocationArray arr
= new TmfLocationArray(locations
, ranks
);
666 TmfExperimentLocation l
= new TmfExperimentLocation(arr
);