1 /*******************************************************************************
2 * Copyright (c) 2009, 2010, 2012 Ericsson
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 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.tmf
.core
.trace
;
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
.signal
.TmfEndSynchSignal
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentDisposedSignal
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentRangeUpdatedSignal
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentSelectedSignal
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentUpdatedSignal
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceUpdatedSignal
;
36 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
37 * that are part of a tracing experiment.
39 public class TmfExperiment
<T
extends ITmfEvent
> extends TmfTrace
<T
> implements ITmfEventParser
<T
> {
41 // ------------------------------------------------------------------------
43 // ------------------------------------------------------------------------
46 * The default index page size
48 public static final int DEFAULT_INDEX_PAGE_SIZE
= 5000;
50 // ------------------------------------------------------------------------
52 // ------------------------------------------------------------------------
55 * The currently selected experiment (null if none)
57 protected static TmfExperiment
<?
> fCurrentExperiment
= null;
60 * The set of traces that constitute the experiment
62 protected ITmfTrace
<T
>[] fTraces
;
65 * The set of traces that constitute the experiment
67 private boolean fInitialized
= false;
70 * The experiment bookmarks file
72 private IFile fBookmarksFile
;
74 // ------------------------------------------------------------------------
76 // ------------------------------------------------------------------------
82 * @throws TmfTraceException
84 public TmfExperiment(final Class
<T
> type
, final String id
, final ITmfTrace
<T
>[] traces
) {
85 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
);
92 * @param indexPageSize
93 * @throws TmfTraceException
95 @SuppressWarnings({ "unchecked", "rawtypes" })
96 public TmfExperiment(final Class
<T
> type
, final String path
, final ITmfTrace
<T
>[] traces
, final int indexPageSize
) {
97 setCacheSize(indexPageSize
);
98 setStreamingInterval(0);
99 setIndexer(new TmfCheckpointIndexer(this, indexPageSize
));
102 super.initialize(null, path
, type
);
103 } catch (TmfTraceException e
) {
108 setTimeRange(TmfTimeRange
.NULL_RANGE
);
112 * Clears the experiment
115 @SuppressWarnings("rawtypes")
116 public synchronized void dispose() {
118 final TmfExperimentDisposedSignal
<T
> signal
= new TmfExperimentDisposedSignal
<T
>(this, this);
121 if (fCurrentExperiment
== this) {
122 fCurrentExperiment
= null;
125 if (fTraces
!= null) {
126 for (final ITmfTrace trace
: fTraces
)
133 // ------------------------------------------------------------------------
134 // ITmfTrace - Initializers
135 // ------------------------------------------------------------------------
138 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
141 public boolean validate(final IProject project
, final String path
) {
146 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class)
149 public void initTrace(final IResource resource
, final String path
, final Class
<T
> type
) {
152 // ------------------------------------------------------------------------
154 // ------------------------------------------------------------------------
157 * Selects the current, framework-wide, experiment
159 * @param experiment das experiment
161 public static void setCurrentExperiment(final TmfExperiment
<?
> experiment
) {
162 if (fCurrentExperiment
!= null && fCurrentExperiment
!= experiment
) {
163 fCurrentExperiment
.dispose();
165 fCurrentExperiment
= experiment
;
169 * @return das experiment
171 public static TmfExperiment
<?
> getCurrentExperiment() {
172 return fCurrentExperiment
;
176 * Get the list of traces. Handle with care...
178 * @return the experiment traces
180 public ITmfTrace
<T
>[] getTraces() {
185 * Returns the timestamp of the event at the requested index. If none,
188 * @param index the event index (rank)
189 * @return the corresponding event timestamp
191 public ITmfTimestamp
getTimestamp(final int index
) {
192 final ITmfContext context
= seekEvent(index
);
193 final ITmfEvent event
= getNext(context
);
194 return (event
!= null) ? event
.getTimestamp() : null;
198 * Set the file to be used for bookmarks on this experiment
200 * @param file the bookmarks file
202 public void setBookmarksFile(final IFile file
) {
203 fBookmarksFile
= file
;
207 * Get the file used for bookmarks on this experiment
209 * @return the bookmarks file or null if none is set
211 public IFile
getBookmarksFile() {
212 return fBookmarksFile
;
215 // ------------------------------------------------------------------------
216 // ITmfTrace trace positioning
217 // ------------------------------------------------------------------------
221 * Returns a brand new context based on the location provided and
222 * initializes the event queues
224 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
227 public synchronized ITmfContext
seekEvent(final ITmfLocation
<?
> location
) {
228 // Validate the location
229 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
230 return null; // Throw an exception?
232 // Make sure we have something to read from
233 if (fTraces
== null) {
237 // Instantiate the location
238 final TmfExperimentLocation expLocation
= (location
== null)
239 ?
new TmfExperimentLocation(new TmfLocationArray(new ITmfLocation
<?
>[fTraces
.length
]))
240 : (TmfExperimentLocation
) location
.clone();
242 // Create and populate the context's traces contexts
243 final TmfExperimentContext context
= new TmfExperimentContext(new ITmfContext
[fTraces
.length
]);
245 for (int i
= 0; i
< fTraces
.length
; i
++) {
246 // Get the relevant trace attributes
247 final ITmfLocation
<?
> traceLocation
= expLocation
.getLocation().getLocations()[i
];
248 context
.getContexts()[i
] = fTraces
[i
].seekEvent(traceLocation
);
249 expLocation
.getLocation().getLocations()[i
] = context
.getContexts()[i
].getLocation().clone();
250 context
.getEvents()[i
] = fTraces
[i
].getNext(context
.getContexts()[i
]);
254 context
.setLocation(expLocation
);
255 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
256 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
257 return (ITmfContext
) context
;
261 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(double)
264 public ITmfContext
seekEvent(final double ratio
) {
265 final ITmfContext context
= seekEvent((long) (ratio
* getNbEvents()));
270 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getLocationRatio(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
273 public double getLocationRatio(final ITmfLocation
<?
> location
) {
274 if (location
instanceof TmfExperimentLocation
) {
275 return (double) seekEvent(location
).getRank() / getNbEvents();
281 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentLocation()
284 public ITmfLocation
<?
> getCurrentLocation() {
285 ITmfLocation
<?
>[] locations
= new ITmfLocation
<?
>[fTraces
.length
];
286 for (int i
= 0; i
< fTraces
.length
; i
++) {
287 locations
[i
] = fTraces
[i
].getCurrentLocation();
289 return new TmfExperimentLocation(new TmfLocationArray(locations
));
292 // ------------------------------------------------------------------------
293 // ITmfTrace trace positioning
294 // ------------------------------------------------------------------------
297 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#getNext(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
300 public synchronized T
getNext(final ITmfContext context
) {
301 final ITmfContext previousContext
= (TmfExperimentContext
) context
.clone();
302 final T event
= parseEvent(context
);
304 updateAttributes(previousContext
, event
.getTimestamp());
306 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
307 int trace
= expContext
.getLastTrace();
308 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
309 TmfExperimentLocation location
= (TmfExperimentLocation
) expContext
.getLocation();
310 location
.getLocation().getLocations()[trace
] = expContext
.getContexts()[trace
].getLocation();
313 context
.increaseRank();
320 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser#parseEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
322 @SuppressWarnings("unchecked")
324 public T
parseEvent(ITmfContext context
) {
326 // Validate the context
327 if (!(context
instanceof TmfExperimentContext
)) {
328 return null; // Throw an exception?
331 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
333 // If an event was consumed previously, first get the next one from that trace
334 final int lastTrace
= expContext
.getLastTrace();
335 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
336 final ITmfContext traceContext
= expContext
.getContexts()[lastTrace
];
337 expContext
.getEvents()[lastTrace
] = fTraces
[lastTrace
].getNext(traceContext
);
338 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
341 // Scan the candidate events and identify the "next" trace to read from
342 int trace
= TmfExperimentContext
.NO_TRACE
;
343 ITmfTimestamp timestamp
= TmfTimestamp
.BIG_CRUNCH
;
344 for (int i
= 0; i
< fTraces
.length
; i
++) {
345 final ITmfEvent event
= expContext
.getEvents()[i
];
346 if (event
!= null && event
.getTimestamp() != null) {
347 final ITmfTimestamp otherTS
= event
.getTimestamp();
348 if (otherTS
.compareTo(timestamp
, true) < 0) {
356 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
357 event
= (T
) expContext
.getEvents()[trace
];
360 expContext
.setLastTrace(trace
);
365 * @see java.lang.Object#toString()
368 @SuppressWarnings("nls")
369 public String
toString() {
370 return "[TmfExperiment (" + getName() + ")]";
373 // ------------------------------------------------------------------------
375 // ------------------------------------------------------------------------
377 private synchronized void initializeStreamingMonitor() {
384 if (getStreamingInterval() == 0) {
385 final ITmfContext context
= seekEvent(0);
386 final ITmfEvent event
= getNext(context
);
389 final TmfTimeRange timeRange
= new TmfTimeRange(event
.getTimestamp().clone(), TmfTimestamp
.BIG_CRUNCH
);
390 final TmfExperimentRangeUpdatedSignal signal
= new TmfExperimentRangeUpdatedSignal(this, this, timeRange
);
392 // Broadcast in separate thread to prevent deadlock
402 final Thread thread
= new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
403 private ITmfTimestamp safeTimestamp
= null;
404 private TmfTimeRange timeRange
= null;
408 while (!fExecutor
.isShutdown()) {
409 if (!getIndexer().isIndexing()) {
410 ITmfTimestamp startTimestamp
= TmfTimestamp
.BIG_CRUNCH
;
411 ITmfTimestamp endTimestamp
= TmfTimestamp
.BIG_BANG
;
412 for (final ITmfTrace
<T
> trace
: fTraces
) {
413 if (trace
.getStartTime().compareTo(startTimestamp
) < 0)
414 startTimestamp
= trace
.getStartTime();
415 if (trace
.getStreamingInterval() != 0 && trace
.getEndTime().compareTo(endTimestamp
) > 0)
416 endTimestamp
= trace
.getEndTime();
418 if (safeTimestamp
!= null && safeTimestamp
.compareTo(getTimeRange().getEndTime(), false) > 0)
419 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
422 safeTimestamp
= endTimestamp
;
423 if (timeRange
!= null) {
424 final TmfExperimentRangeUpdatedSignal signal
=
425 new TmfExperimentRangeUpdatedSignal(TmfExperiment
.this, TmfExperiment
.this, timeRange
);
430 Thread
.sleep(getStreamingInterval());
431 } catch (final InterruptedException e
) {
441 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
444 public long getStreamingInterval() {
446 for (final ITmfTrace
<T
> trace
: fTraces
)
447 interval
= Math
.max(interval
, trace
.getStreamingInterval());
451 // ------------------------------------------------------------------------
453 // ------------------------------------------------------------------------
455 private Integer fEndSynchReference
;
458 * Signal handler for the TmfExperimentSelectedSignal signal
463 public void experimentSelected(final TmfExperimentSelectedSignal
<T
> signal
) {
464 final TmfExperiment
<?
> experiment
= signal
.getExperiment();
465 if (experiment
== this) {
466 setCurrentExperiment(experiment
);
467 fEndSynchReference
= Integer
.valueOf(signal
.getReference());
472 * Signal handler for the TmfEndSynchSignal signal
477 public void endSync(final TmfEndSynchSignal signal
) {
478 if (fEndSynchReference
!= null && fEndSynchReference
.intValue() == signal
.getReference()) {
479 fEndSynchReference
= null;
480 initializeStreamingMonitor();
485 * Signal handler for the TmfTraceUpdatedSignal signal
490 public void traceUpdated(final TmfTraceUpdatedSignal signal
) {
491 if (signal
.getTrace() == this) {
492 broadcast(new TmfExperimentUpdatedSignal(this, this));
497 * Signal handler for the TmfExperimentRangeUpdatedSignal signal
502 public void experimentRangeUpdated(final TmfExperimentRangeUpdatedSignal signal
) {
503 if (signal
.getExperiment() == this) {
504 getIndexer().buildIndex(getNbEvents(), signal
.getRange(), false);