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
.request
.ITmfDataRequest
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfEventRequest
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfEndSynchSignal
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentDisposedSignal
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentRangeUpdatedSignal
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentSelectedSignal
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentUpdatedSignal
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceUpdatedSignal
;
38 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
39 * that are part of a tracing experiment.
42 * @author Francois Chouinard
44 public class TmfExperiment
<T
extends ITmfEvent
> extends TmfTrace
<T
> implements ITmfEventParser
<T
> {
46 // ------------------------------------------------------------------------
48 // ------------------------------------------------------------------------
51 * The default index page size
53 public static final int DEFAULT_INDEX_PAGE_SIZE
= 5000;
55 // ------------------------------------------------------------------------
57 // ------------------------------------------------------------------------
60 * The currently selected experiment (null if none)
62 protected static TmfExperiment
<?
> fCurrentExperiment
= null;
65 * The set of traces that constitute the experiment
67 protected ITmfTrace
<T
>[] fTraces
;
70 * The set of traces that constitute the experiment
72 private boolean fInitialized
= false;
75 * The experiment bookmarks file
77 private IFile fBookmarksFile
;
80 // Saved experiment context (optimization)
81 private TmfExperimentContext fExperimentContext
;
83 // ------------------------------------------------------------------------
85 // ------------------------------------------------------------------------
91 * @throws TmfTraceException
93 public TmfExperiment(final Class
<T
> type
, final String id
, final ITmfTrace
<T
>[] traces
) {
94 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
);
101 * @param indexPageSize
102 * @throws TmfTraceException
104 @SuppressWarnings({ "unchecked", "rawtypes" })
105 public TmfExperiment(final Class
<T
> type
, final String path
, final ITmfTrace
<T
>[] traces
, final int indexPageSize
) {
106 setCacheSize(indexPageSize
);
107 setStreamingInterval(0);
108 setIndexer(new TmfCheckpointIndexer(this, indexPageSize
));
111 super.initialize(null, path
, type
);
112 } catch (TmfTraceException e
) {
117 setTimeRange(TmfTimeRange
.NULL_RANGE
);
121 * Clears the experiment
124 @SuppressWarnings("rawtypes")
125 public synchronized void dispose() {
127 final TmfExperimentDisposedSignal
<T
> signal
= new TmfExperimentDisposedSignal
<T
>(this, this);
130 if (fCurrentExperiment
== this) {
131 fCurrentExperiment
= null;
134 // Clean up the index if applicable
135 if (getIndexer() != null) {
136 getIndexer().dispose();
139 if (fTraces
!= null) {
140 for (final ITmfTrace trace
: fTraces
)
147 // ------------------------------------------------------------------------
148 // ITmfTrace - Initializers
149 // ------------------------------------------------------------------------
152 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
155 public boolean validate(final IProject project
, final String path
) {
160 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class)
163 public void initTrace(final IResource resource
, final String path
, final Class
<T
> type
) {
166 // ------------------------------------------------------------------------
168 // ------------------------------------------------------------------------
171 * Selects the current, framework-wide, experiment
173 * @param experiment das experiment
175 public static void setCurrentExperiment(final TmfExperiment
<?
> experiment
) {
176 if (fCurrentExperiment
!= null && fCurrentExperiment
!= experiment
) {
177 fCurrentExperiment
.dispose();
179 fCurrentExperiment
= experiment
;
183 * @return das experiment
185 public static TmfExperiment
<?
> getCurrentExperiment() {
186 return fCurrentExperiment
;
190 * Get the list of traces. Handle with care...
192 * @return the experiment traces
194 public ITmfTrace
<T
>[] getTraces() {
199 * Returns the timestamp of the event at the requested index. If none,
202 * @param index the event index (rank)
203 * @return the corresponding event timestamp
205 public ITmfTimestamp
getTimestamp(final int index
) {
206 final ITmfContext context
= seekEvent(index
);
207 final ITmfEvent event
= getNext(context
);
208 return (event
!= null) ? event
.getTimestamp() : null;
212 * Set the file to be used for bookmarks on this experiment
214 * @param file the bookmarks file
216 public void setBookmarksFile(final IFile file
) {
217 fBookmarksFile
= file
;
221 * Get the file used for bookmarks on this experiment
223 * @return the bookmarks file or null if none is set
225 public IFile
getBookmarksFile() {
226 return fBookmarksFile
;
229 // ------------------------------------------------------------------------
230 // Request management
231 // ------------------------------------------------------------------------
234 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#armRequest(org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest)
237 protected synchronized ITmfContext
armRequest(final ITmfDataRequest
<T
> request
) {
239 // Make sure we have something to read from
240 if (fTraces
== null) {
244 if (request
instanceof ITmfEventRequest
<?
>
245 && !TmfTimestamp
.BIG_BANG
.equals(((ITmfEventRequest
<T
>) request
).getRange().getStartTime())
246 && request
.getIndex() == 0)
248 final ITmfContext context
= seekEvent(((ITmfEventRequest
<T
>) request
).getRange().getStartTime());
249 ((ITmfEventRequest
<T
>) request
).setStartIndex((int) context
.getRank());
254 // Check if we are already at the right index
255 if ((fExperimentContext
!= null) && fExperimentContext
.getRank() == request
.getIndex()) {
256 return fExperimentContext
;
259 return seekEvent(request
.getIndex());
262 // ------------------------------------------------------------------------
263 // ITmfTrace trace positioning
264 // ------------------------------------------------------------------------
267 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#seekEvent(long)
269 * TmfTrace.seekEvent(rank) will return a context that will position the
270 * trace to read the event at rank 'rank' in the trace. In the case of an
271 * experiment context, that event has to be actually read in the fEvents
272 * buffer and the corresponding trace context has to point to the next
273 * event (rank + 1) in the trace (the sum of the traces contexts ranks
274 * should equal [exp context rank + #traces] (corner cases not considered).
276 * In the likely case that TmfTrace.seekEvent() computed the context
277 * by using a read loop (reading from the experiment), the 'lastTraceRead'
278 * field will be set to the actual trace that needs to be read to obtain
279 * event at rank 'rank'.
281 * Therefore, if 'lastTraceRead' is set, we need to read that particular
282 * trace *and* then decrease the context rank (which has to correspond to
283 * the rank of the event to be returned next by TmfExperiemnt.getNext().
286 public synchronized ITmfContext
seekEvent(final long rank
) {
287 TmfExperimentContext context
= (TmfExperimentContext
) super.seekEvent(rank
);
288 int lastTrace
= context
.getLastTrace();
289 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
291 context
.setRank(rank
);
292 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
299 * Returns a brand new context based on the location provided and
300 * initializes the event queues
302 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
305 public synchronized ITmfContext
seekEvent(final ITmfLocation
<?
> location
) {
306 // Validate the location
307 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
308 return null; // Throw an exception?
310 // Make sure we have something to read from
311 if (fTraces
== null) {
315 // Instantiate the location
316 final TmfExperimentLocation expLocation
= (location
== null)
317 ?
new TmfExperimentLocation(new TmfLocationArray(new ITmfLocation
<?
>[fTraces
.length
]))
318 : (TmfExperimentLocation
) location
.clone();
320 // Create and populate the context's traces contexts
321 final TmfExperimentContext context
= new TmfExperimentContext(new ITmfContext
[fTraces
.length
]);
323 for (int i
= 0; i
< fTraces
.length
; i
++) {
324 // Get the relevant trace attributes
325 final ITmfLocation
<?
> trcLocation
= expLocation
.getLocation().getLocations()[i
];
326 context
.getContexts()[i
] = fTraces
[i
].seekEvent(trcLocation
);
327 expLocation
.getLocation().getLocations()[i
] = context
.getContexts()[i
].getLocation().clone();
328 context
.getEvents()[i
] = fTraces
[i
].getNext(context
.getContexts()[i
]);
332 context
.setLocation(expLocation
);
333 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
334 context
.setRank(ITmfContext
.UNKNOWN_RANK
);
336 fExperimentContext
= context
;
337 return (ITmfContext
) context
;
340 // ------------------------------------------------------------------------
341 // ITmfTrace - SeekEvent operations (returning a trace context)
342 // ------------------------------------------------------------------------
345 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(double)
348 public ITmfContext
seekEvent(final double ratio
) {
349 final ITmfContext context
= seekEvent((long) (ratio
* getNbEvents()));
354 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getLocationRatio(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
357 public double getLocationRatio(final ITmfLocation
<?
> location
) {
358 if (location
instanceof TmfExperimentLocation
) {
359 return (double) seekEvent(location
).getRank() / getNbEvents();
365 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentLocation()
368 public ITmfLocation
<?
> getCurrentLocation() {
369 ITmfLocation
<?
>[] locations
= new ITmfLocation
<?
>[fTraces
.length
];
370 for (int i
= 0; i
< fTraces
.length
; i
++) {
371 locations
[i
] = fTraces
[i
].getCurrentLocation();
373 return new TmfExperimentLocation(new TmfLocationArray(locations
));
376 // ------------------------------------------------------------------------
377 // ITmfTrace trace positioning
378 // ------------------------------------------------------------------------
381 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser#parseEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
384 public synchronized T
parseEvent(final ITmfContext context
) {
385 final ITmfContext savedContext
= context
.clone();
386 final T event
= getNext(savedContext
);
391 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#getNext(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
394 @SuppressWarnings("unchecked")
395 public synchronized T
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 trace
410 final int lastTrace
= expContext
.getLastTrace();
411 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
412 final ITmfContext traceContext
= expContext
.getContexts()[lastTrace
];
414 TmfExperimentLocation location
= (TmfExperimentLocation
) expContext
.getLocation();
415 if (location
!= null) {
416 location
.getLocation().getLocations()[lastTrace
] = traceContext
.getLocation().clone();
419 expContext
.getEvents()[lastTrace
] = fTraces
[lastTrace
].getNext(traceContext
);
420 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
423 // Scan the candidate events and identify the "next" trace to read from
424 int trace
= TmfExperimentContext
.NO_TRACE
;
425 ITmfTimestamp timestamp
= TmfTimestamp
.BIG_CRUNCH
;
426 for (int i
= 0; i
< fTraces
.length
; i
++) {
427 final ITmfEvent event
= expContext
.getEvents()[i
];
428 if (event
!= null && event
.getTimestamp() != null) {
429 final ITmfTimestamp otherTS
= event
.getTimestamp();
430 if (otherTS
.compareTo(timestamp
, true) < 0) {
438 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
439 event
= (T
) expContext
.getEvents()[trace
];
441 updateAttributes(expContext
, event
.getTimestamp());
442 expContext
.increaseRank();
443 expContext
.setLastTrace(trace
);
444 fExperimentContext
= expContext
;
453 * @see java.lang.Object#toString()
456 @SuppressWarnings("nls")
457 public String
toString() {
458 return "[TmfExperiment (" + getName() + ")]";
461 // ------------------------------------------------------------------------
463 // ------------------------------------------------------------------------
465 private synchronized void initializeStreamingMonitor() {
472 if (getStreamingInterval() == 0) {
473 final ITmfContext context
= seekEvent(0);
474 final ITmfEvent event
= getNext(context
);
477 final TmfTimeRange timeRange
= new TmfTimeRange(event
.getTimestamp().clone(), TmfTimestamp
.BIG_CRUNCH
);
478 final TmfExperimentRangeUpdatedSignal signal
= new TmfExperimentRangeUpdatedSignal(this, this, timeRange
);
480 // Broadcast in separate thread to prevent deadlock
490 final Thread thread
= new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
491 private ITmfTimestamp safeTimestamp
= null;
492 private TmfTimeRange timeRange
= null;
496 while (!fExecutor
.isShutdown()) {
497 if (!getIndexer().isIndexing()) {
498 ITmfTimestamp startTimestamp
= TmfTimestamp
.BIG_CRUNCH
;
499 ITmfTimestamp endTimestamp
= TmfTimestamp
.BIG_BANG
;
500 for (final ITmfTrace
<T
> trace
: fTraces
) {
501 if (trace
.getStartTime().compareTo(startTimestamp
) < 0)
502 startTimestamp
= trace
.getStartTime();
503 if (trace
.getStreamingInterval() != 0 && trace
.getEndTime().compareTo(endTimestamp
) > 0)
504 endTimestamp
= trace
.getEndTime();
506 if (safeTimestamp
!= null && safeTimestamp
.compareTo(getTimeRange().getEndTime(), false) > 0)
507 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
510 safeTimestamp
= endTimestamp
;
511 if (timeRange
!= null) {
512 final TmfExperimentRangeUpdatedSignal signal
=
513 new TmfExperimentRangeUpdatedSignal(TmfExperiment
.this, TmfExperiment
.this, timeRange
);
518 Thread
.sleep(getStreamingInterval());
519 } catch (final InterruptedException e
) {
529 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
532 public long getStreamingInterval() {
534 for (final ITmfTrace
<T
> trace
: fTraces
)
535 interval
= Math
.max(interval
, trace
.getStreamingInterval());
539 // ------------------------------------------------------------------------
541 // ------------------------------------------------------------------------
543 private Integer fEndSynchReference
;
546 * Signal handler for the TmfExperimentSelectedSignal signal
551 public void experimentSelected(final TmfExperimentSelectedSignal
<T
> signal
) {
552 final TmfExperiment
<?
> experiment
= signal
.getExperiment();
553 if (experiment
== this) {
554 setCurrentExperiment(experiment
);
555 fEndSynchReference
= Integer
.valueOf(signal
.getReference());
560 * Signal handler for the TmfEndSynchSignal signal
565 public void endSync(final TmfEndSynchSignal signal
) {
566 if (fEndSynchReference
!= null && fEndSynchReference
.intValue() == signal
.getReference()) {
567 fEndSynchReference
= null;
568 initializeStreamingMonitor();
573 * Signal handler for the TmfTraceUpdatedSignal signal
578 public void traceUpdated(final TmfTraceUpdatedSignal signal
) {
579 if (signal
.getTrace() == this) {
580 broadcast(new TmfExperimentUpdatedSignal(this, this));
585 * Signal handler for the TmfExperimentRangeUpdatedSignal signal
590 public void experimentRangeUpdated(final TmfExperimentRangeUpdatedSignal signal
) {
591 if (signal
.getExperiment() == this) {
592 getIndexer().buildIndex(getNbEvents(), signal
.getRange(), false);