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
.TmfClearExperimentSignal
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfEndSynchSignal
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentDisposedSignal
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentRangeUpdatedSignal
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentSelectedSignal
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentUpdatedSignal
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceUpdatedSignal
;
39 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
40 * that are part of a tracing experiment.
43 * @author Francois Chouinard
45 public class TmfExperiment
extends TmfTrace
implements ITmfEventParser
{
47 // ------------------------------------------------------------------------
49 // ------------------------------------------------------------------------
52 * The default index page size
54 public static final int DEFAULT_INDEX_PAGE_SIZE
= 5000;
56 // ------------------------------------------------------------------------
58 // ------------------------------------------------------------------------
61 * The currently selected experiment (null if none)
63 protected static TmfExperiment fCurrentExperiment
= null;
66 * The set of traces that constitute the experiment
68 protected ITmfTrace
[] fTraces
;
71 * The set of traces that constitute the experiment
73 private boolean fInitialized
= false;
76 * The experiment bookmarks file
78 private IFile fBookmarksFile
;
81 // Saved experiment context (optimization)
82 private TmfExperimentContext fExperimentContext
;
84 // ------------------------------------------------------------------------
86 // ------------------------------------------------------------------------
89 * @param type the event type
90 * @param id the experiment id
91 * @param traces the experiment set of traces
93 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
) {
94 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
);
98 * @param type the event type
99 * @param path the experiment path
100 * @param traces the experiment set of traces
101 * @param indexPageSize the experiment index page size
103 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
) {
104 setCacheSize(indexPageSize
);
105 setStreamingInterval(0);
106 setIndexer(new TmfCheckpointIndexer(this, indexPageSize
));
109 super.initialize(null, path
, type
);
110 } catch (TmfTraceException e
) {
115 setTimeRange(TmfTimeRange
.NULL_RANGE
);
119 * Clears the experiment
122 public synchronized void dispose() {
124 final TmfExperimentDisposedSignal signal
= new TmfExperimentDisposedSignal(this, this);
127 if (fCurrentExperiment
== this) {
128 fCurrentExperiment
= null;
131 // Clean up the index if applicable
132 if (getIndexer() != null) {
133 getIndexer().dispose();
136 if (fTraces
!= null) {
137 for (final ITmfTrace trace
: fTraces
) {
146 * @param signal the clear view signal
150 public void handleClearExperimentSignal(TmfClearExperimentSignal signal
) {
154 // ------------------------------------------------------------------------
155 // ITmfTrace - Initializers
156 // ------------------------------------------------------------------------
159 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class)
162 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> type
) {
166 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
169 public boolean validate(final IProject project
, final String path
) {
173 // ------------------------------------------------------------------------
175 // ------------------------------------------------------------------------
178 * Selects the current, framework-wide, experiment
180 * @param experiment das experiment
182 public static void setCurrentExperiment(final TmfExperiment experiment
) {
183 if (fCurrentExperiment
!= null && fCurrentExperiment
!= experiment
) {
184 fCurrentExperiment
.dispose();
186 fCurrentExperiment
= experiment
;
190 * @return das experiment
192 public static TmfExperiment
getCurrentExperiment() {
193 return fCurrentExperiment
;
197 * Get the list of traces. Handle with care...
199 * @return the experiment traces
201 public ITmfTrace
[] getTraces() {
206 * Returns the timestamp of the event at the requested index. If none,
209 * @param index the event index (rank)
210 * @return the corresponding event timestamp
212 public ITmfTimestamp
getTimestamp(final int index
) {
213 final ITmfContext context
= seekEvent(index
);
214 final ITmfEvent event
= getNext(context
);
215 return (event
!= null) ? event
.getTimestamp() : null;
219 * Set the file to be used for bookmarks on this experiment
221 * @param file the bookmarks file
223 public void setBookmarksFile(final IFile file
) {
224 fBookmarksFile
= file
;
228 * Get the file used for bookmarks on this experiment
230 * @return the bookmarks file or null if none is set
232 public IFile
getBookmarksFile() {
233 return fBookmarksFile
;
236 // ------------------------------------------------------------------------
237 // Request management
238 // ------------------------------------------------------------------------
241 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#armRequest(org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest)
244 protected synchronized ITmfContext
armRequest(final ITmfDataRequest request
) {
246 // Make sure we have something to read from
247 if (fTraces
== null) {
251 if (request
instanceof ITmfEventRequest
252 && !TmfTimestamp
.BIG_BANG
.equals(((ITmfEventRequest
) request
).getRange().getStartTime())
253 && request
.getIndex() == 0)
255 final ITmfContext context
= seekEvent(((ITmfEventRequest
) request
).getRange().getStartTime());
256 ((ITmfEventRequest
) request
).setStartIndex((int) context
.getRank());
261 // Check if we are already at the right index
262 if ((fExperimentContext
!= null) && fExperimentContext
.getRank() == request
.getIndex()) {
263 return fExperimentContext
;
266 return seekEvent(request
.getIndex());
269 // ------------------------------------------------------------------------
270 // ITmfTrace trace positioning
271 // ------------------------------------------------------------------------
275 * Returns a brand new context based on the location provided and
276 * initializes the event queues
278 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
281 public synchronized ITmfContext
seekEvent(final ITmfLocation location
) {
282 // Validate the location
283 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
284 return null; // Throw an exception?
286 // Make sure we have something to read from
287 if (fTraces
== null) {
291 // Instantiate the location
292 final TmfExperimentLocation expLocation
= (location
== null)
293 ?
new TmfExperimentLocation(new TmfLocationArray(new ITmfLocation
[fTraces
.length
]))
294 : (TmfExperimentLocation
) location
.clone();
296 // Create and populate the context's traces contexts
297 final TmfExperimentContext context
= new TmfExperimentContext(new ITmfContext
[fTraces
.length
]);
299 for (int i
= 0; i
< fTraces
.length
; i
++) {
300 // Get the relevant trace attributes
301 final ITmfLocation trcLocation
= expLocation
.getLocationInfo().getLocations()[i
];
302 context
.getContexts()[i
] = fTraces
[i
].seekEvent(trcLocation
);
303 expLocation
.getLocationInfo().getLocations()[i
] = context
.getContexts()[i
].getLocation().clone();
304 context
.getEvents()[i
] = fTraces
[i
].getNext(context
.getContexts()[i
]);
308 context
.setLocation(expLocation
);
309 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
310 context
.setRank((location
== null) ?
0 : ITmfContext
.UNKNOWN_RANK
);
312 fExperimentContext
= context
;
316 // ------------------------------------------------------------------------
317 // ITmfTrace - SeekEvent operations (returning a trace context)
318 // ------------------------------------------------------------------------
321 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(double)
324 public ITmfContext
seekEvent(final double ratio
) {
325 final ITmfContext context
= seekEvent((long) (ratio
* getNbEvents()));
330 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getLocationRatio(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
333 public double getLocationRatio(final ITmfLocation location
) {
334 if (location
instanceof TmfExperimentLocation
) {
335 return (double) seekEvent(location
).getRank() / getNbEvents();
341 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentLocation()
344 public ITmfLocation
getCurrentLocation() {
345 ITmfLocation
[] locations
= new ITmfLocation
[fTraces
.length
];
346 for (int i
= 0; i
< fTraces
.length
; i
++) {
347 locations
[i
] = fTraces
[i
].getCurrentLocation();
349 return new TmfExperimentLocation(new TmfLocationArray(locations
));
352 // ------------------------------------------------------------------------
353 // ITmfTrace trace positioning
354 // ------------------------------------------------------------------------
357 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser#parseEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
360 public synchronized ITmfEvent
parseEvent(final ITmfContext context
) {
361 final ITmfContext savedContext
= context
.clone();
362 final ITmfEvent event
= getNext(savedContext
);
367 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#getNext(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
370 public synchronized ITmfEvent
getNext(ITmfContext context
) {
372 // Validate the context
373 if (!(context
instanceof TmfExperimentContext
)) {
374 return null; // Throw an exception?
377 // Make sure that we have something to read from
378 if (fTraces
== null) {
382 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
384 // If an event was consumed previously, first get the next one from that trace
385 final int lastTrace
= expContext
.getLastTrace();
386 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
387 final ITmfContext traceContext
= expContext
.getContexts()[lastTrace
];
388 expContext
.getEvents()[lastTrace
] = fTraces
[lastTrace
].getNext(traceContext
);
389 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
392 // Scan the candidate events and identify the "next" trace to read from
393 int trace
= TmfExperimentContext
.NO_TRACE
;
394 ITmfTimestamp timestamp
= TmfTimestamp
.BIG_CRUNCH
;
395 for (int i
= 0; i
< fTraces
.length
; i
++) {
396 final ITmfEvent event
= expContext
.getEvents()[i
];
397 if (event
!= null && event
.getTimestamp() != null) {
398 final ITmfTimestamp otherTS
= event
.getTimestamp();
399 if (otherTS
.compareTo(timestamp
, true) < 0) {
406 ITmfEvent event
= null;
407 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
408 event
= expContext
.getEvents()[trace
];
410 updateAttributes(expContext
, event
.getTimestamp());
411 expContext
.increaseRank();
412 expContext
.setLastTrace(trace
);
413 final ITmfContext traceContext
= expContext
.getContexts()[trace
];
415 TmfExperimentLocation location
= (TmfExperimentLocation
) expContext
.getLocation();
416 if (location
!= null) {
417 location
.getLocationInfo().getLocations()[trace
] = traceContext
.getLocation().clone();
420 fExperimentContext
= expContext
.clone();
429 * @see java.lang.Object#toString()
432 @SuppressWarnings("nls")
433 public synchronized String
toString() {
434 return "[TmfExperiment (" + getName() + ")]";
437 // ------------------------------------------------------------------------
439 // ------------------------------------------------------------------------
441 private synchronized void initializeStreamingMonitor() {
448 if (getStreamingInterval() == 0) {
449 final ITmfContext context
= seekEvent(0);
450 final ITmfEvent event
= getNext(context
);
454 final TmfTimeRange timeRange
= new TmfTimeRange(event
.getTimestamp().clone(), TmfTimestamp
.BIG_CRUNCH
);
455 final TmfExperimentRangeUpdatedSignal signal
= new TmfExperimentRangeUpdatedSignal(this, this, timeRange
);
457 // Broadcast in separate thread to prevent deadlock
467 final Thread thread
= new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
468 private ITmfTimestamp safeTimestamp
= null;
469 private ITmfTimestamp lastSafeTimestamp
= null;
470 private TmfTimeRange timeRange
= null;
474 while (!executorIsShutdown()) {
475 if (!getIndexer().isIndexing()) {
476 ITmfTimestamp startTimestamp
= TmfTimestamp
.BIG_CRUNCH
;
477 ITmfTimestamp endTimestamp
= TmfTimestamp
.BIG_BANG
;
478 for (final ITmfTrace trace
: fTraces
) {
479 if (trace
.getStartTime().compareTo(startTimestamp
) < 0) {
480 startTimestamp
= trace
.getStartTime();
482 if (trace
.getStreamingInterval() != 0 && trace
.getEndTime().compareTo(endTimestamp
) > 0) {
483 endTimestamp
= trace
.getEndTime();
486 if (safeTimestamp
!= null && (lastSafeTimestamp
== null || safeTimestamp
.compareTo(lastSafeTimestamp
, false) > 0)) {
487 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
488 lastSafeTimestamp
= safeTimestamp
;
492 safeTimestamp
= endTimestamp
;
493 if (timeRange
!= null) {
494 final TmfExperimentRangeUpdatedSignal signal
=
495 new TmfExperimentRangeUpdatedSignal(TmfExperiment
.this, TmfExperiment
.this, timeRange
);
500 Thread
.sleep(getStreamingInterval());
501 } catch (final InterruptedException e
) {
511 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
514 public long getStreamingInterval() {
516 for (final ITmfTrace trace
: fTraces
) {
517 interval
= Math
.max(interval
, trace
.getStreamingInterval());
522 // ------------------------------------------------------------------------
524 // ------------------------------------------------------------------------
526 private Integer fEndSynchReference
;
529 * Signal handler for the TmfExperimentSelectedSignal signal
531 * @param signal The incoming signal
534 public void experimentSelected(final TmfExperimentSelectedSignal signal
) {
535 final TmfExperiment experiment
= signal
.getExperiment();
536 if (experiment
== this) {
537 setCurrentExperiment(experiment
);
538 fEndSynchReference
= Integer
.valueOf(signal
.getReference());
543 * Signal handler for the TmfEndSynchSignal signal
545 * @param signal The incoming signal
548 public void endSync(final TmfEndSynchSignal signal
) {
549 if (fEndSynchReference
!= null && fEndSynchReference
.intValue() == signal
.getReference()) {
550 fEndSynchReference
= null;
551 initializeStreamingMonitor();
556 * Signal handler for the TmfTraceUpdatedSignal signal
558 * @param signal The incoming signal
561 public void traceUpdated(final TmfTraceUpdatedSignal signal
) {
562 if (signal
.getTrace() == this) {
563 broadcast(new TmfExperimentUpdatedSignal(this, this));
568 * Signal handler for the TmfExperimentRangeUpdatedSignal signal
570 * @param signal The incoming signal
573 public void experimentRangeUpdated(final TmfExperimentRangeUpdatedSignal signal
) {
574 if (signal
.getExperiment() == this) {
575 getIndexer().buildIndex(getNbEvents(), signal
.getRange(), false);