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
;
80 // ------------------------------------------------------------------------
82 // ------------------------------------------------------------------------
85 * @param type the event type
86 * @param id the experiment id
87 * @param traces the experiment set of traces
89 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
) {
90 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
);
94 * @param type the event type
95 * @param path the experiment path
96 * @param traces the experiment set of traces
97 * @param indexPageSize the experiment index page size
99 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
) {
100 setCacheSize(indexPageSize
);
101 setStreamingInterval(0);
102 setIndexer(new TmfCheckpointIndexer(this, indexPageSize
));
105 super.initialize(null, path
, type
);
106 } catch (TmfTraceException e
) {
111 setTimeRange(TmfTimeRange
.NULL_RANGE
);
115 * Clears the experiment
118 public synchronized void dispose() {
120 final TmfExperimentDisposedSignal signal
= new TmfExperimentDisposedSignal(this, this);
123 if (fCurrentExperiment
== this) {
124 fCurrentExperiment
= null;
127 // Clean up the index if applicable
128 if (getIndexer() != null) {
129 getIndexer().dispose();
132 if (fTraces
!= null) {
133 for (final ITmfTrace trace
: fTraces
) {
142 * @param signal the clear view signal
146 public void handleClearExperimentSignal(TmfClearExperimentSignal signal
) {
150 // ------------------------------------------------------------------------
151 // ITmfTrace - Initializers
152 // ------------------------------------------------------------------------
155 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class)
158 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> type
) {
162 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
165 public boolean validate(final IProject project
, final String path
) {
169 // ------------------------------------------------------------------------
171 // ------------------------------------------------------------------------
174 * Selects the current, framework-wide, experiment
176 * @param experiment das experiment
178 public static void setCurrentExperiment(final TmfExperiment experiment
) {
179 if (fCurrentExperiment
!= null && fCurrentExperiment
!= experiment
) {
180 fCurrentExperiment
.dispose();
182 fCurrentExperiment
= experiment
;
186 * @return das experiment
188 public static TmfExperiment
getCurrentExperiment() {
189 return fCurrentExperiment
;
193 * Get the list of traces. Handle with care...
195 * @return the experiment traces
197 public ITmfTrace
[] getTraces() {
202 * Returns the timestamp of the event at the requested index. If none,
205 * @param index the event index (rank)
206 * @return the corresponding event timestamp
208 public ITmfTimestamp
getTimestamp(final int index
) {
209 final ITmfContext context
= seekEvent(index
);
210 final ITmfEvent event
= getNext(context
);
212 return (event
!= null) ? event
.getTimestamp() : null;
216 * Set the file to be used for bookmarks on this experiment
218 * @param file the bookmarks file
220 public void setBookmarksFile(final IFile file
) {
221 fBookmarksFile
= file
;
225 * Get the file used for bookmarks on this experiment
227 * @return the bookmarks file or null if none is set
229 public IFile
getBookmarksFile() {
230 return fBookmarksFile
;
233 // ------------------------------------------------------------------------
234 // Request management
235 // ------------------------------------------------------------------------
238 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#armRequest(org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest)
241 protected synchronized ITmfContext
armRequest(final ITmfDataRequest request
) {
243 // Make sure we have something to read from
244 if (fTraces
== null) {
248 if (request
instanceof ITmfEventRequest
249 && !TmfTimestamp
.BIG_BANG
.equals(((ITmfEventRequest
) request
).getRange().getStartTime())
250 && request
.getIndex() == 0)
252 final ITmfContext context
= seekEvent(((ITmfEventRequest
) request
).getRange().getStartTime());
253 ((ITmfEventRequest
) request
).setStartIndex((int) context
.getRank());
258 return seekEvent(request
.getIndex());
261 // ------------------------------------------------------------------------
262 // ITmfTrace trace positioning
263 // ------------------------------------------------------------------------
267 * Returns a brand new context based on the location provided and
268 * initializes the event queues
270 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
273 public synchronized ITmfContext
seekEvent(final ITmfLocation location
) {
274 // Validate the location
275 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
276 return null; // Throw an exception?
278 // Make sure we have something to read from
279 if (fTraces
== null) {
283 // Create and populate the context's traces contexts
284 final TmfExperimentContext context
= new TmfExperimentContext(new ITmfContext
[fTraces
.length
]);
285 ITmfLocation
[] expLocations
= new ITmfLocation
[fTraces
.length
];
286 if (location
!= null) {
287 TmfExperimentLocation locations
= (TmfExperimentLocation
) location
;
289 ITmfLocation l
= locations
.getLocationInfo().getLocation(index
);
290 while (index
< expLocations
.length
&& l
!= null) {
291 expLocations
[index
] = l
;
292 l
= locations
.getLocationInfo().getLocation(++index
);
296 // Position the traces
297 for (int i
= 0; i
< fTraces
.length
; i
++) {
298 // Get the relevant trace attributes
299 final ITmfLocation trcLocation
= expLocations
[i
];
300 context
.getContexts()[i
] = fTraces
[i
].seekEvent(trcLocation
);
301 expLocations
[i
] = context
.getContexts()[i
].getLocation();
302 context
.getEvents()[i
] = fTraces
[i
].getNext(context
.getContexts()[i
]);
306 context
.setLocation(new TmfExperimentLocation(new TmfLocationArray(expLocations
)));
307 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
308 context
.setRank((location
== null) ?
0 : ITmfContext
.UNKNOWN_RANK
);
313 // ------------------------------------------------------------------------
314 // ITmfTrace - SeekEvent operations (returning a trace context)
315 // ------------------------------------------------------------------------
318 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(double)
321 public ITmfContext
seekEvent(final double ratio
) {
322 final ITmfContext context
= seekEvent(Math
.round(ratio
* getNbEvents()));
327 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getLocationRatio(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
330 public double getLocationRatio(final ITmfLocation location
) {
331 if (location
instanceof TmfExperimentLocation
) {
332 return (double) seekEvent(location
).getRank() / getNbEvents();
338 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentLocation()
341 public ITmfLocation
getCurrentLocation() {
342 ITmfLocation
[] locations
= new ITmfLocation
[fTraces
.length
];
343 for (int i
= 0; i
< fTraces
.length
; i
++) {
344 locations
[i
] = fTraces
[i
].getCurrentLocation();
346 return new TmfExperimentLocation(new TmfLocationArray(locations
));
349 // ------------------------------------------------------------------------
350 // ITmfTrace trace positioning
351 // ------------------------------------------------------------------------
354 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser#parseEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
357 public synchronized ITmfEvent
parseEvent(final ITmfContext context
) {
358 final ITmfContext savedContext
= context
.clone();
359 final ITmfEvent event
= getNext(savedContext
);
364 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#getNext(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
367 public synchronized ITmfEvent
getNext(ITmfContext context
) {
369 // Validate the context
370 if (!(context
instanceof TmfExperimentContext
)) {
371 return null; // Throw an exception?
374 // Make sure that we have something to read from
375 if (fTraces
== null) {
379 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
381 // If an event was consumed previously, first get the next one from that trace
382 final int lastTrace
= expContext
.getLastTrace();
383 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
384 final ITmfContext traceContext
= expContext
.getContexts()[lastTrace
];
385 expContext
.getEvents()[lastTrace
] = fTraces
[lastTrace
].getNext(traceContext
);
386 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
389 // Scan the candidate events and identify the "next" trace to read from
390 int trace
= TmfExperimentContext
.NO_TRACE
;
391 ITmfTimestamp timestamp
= TmfTimestamp
.BIG_CRUNCH
;
392 for (int i
= 0; i
< fTraces
.length
; i
++) {
393 final ITmfEvent event
= expContext
.getEvents()[i
];
394 if (event
!= null && event
.getTimestamp() != null) {
395 final ITmfTimestamp otherTS
= event
.getTimestamp();
396 if (otherTS
.compareTo(timestamp
, true) < 0) {
403 ITmfEvent event
= null;
404 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
405 event
= expContext
.getEvents()[trace
];
407 updateAttributes(expContext
, event
.getTimestamp());
408 expContext
.increaseRank();
409 expContext
.setLastTrace(trace
);
410 final ITmfContext traceContext
= expContext
.getContexts()[trace
];
412 expContext
.setLocation(new TmfExperimentLocation(
413 (TmfExperimentLocation
) expContext
.getLocation(),
414 trace
, traceContext
.getLocation()));
424 * @see java.lang.Object#toString()
427 @SuppressWarnings("nls")
428 public synchronized String
toString() {
429 return "[TmfExperiment (" + getName() + ")]";
432 // ------------------------------------------------------------------------
434 // ------------------------------------------------------------------------
436 private synchronized void initializeStreamingMonitor() {
443 if (getStreamingInterval() == 0) {
444 final ITmfContext context
= seekEvent(0);
445 final ITmfEvent event
= getNext(context
);
450 final TmfTimeRange timeRange
= new TmfTimeRange(event
.getTimestamp().clone(), TmfTimestamp
.BIG_CRUNCH
);
451 final TmfExperimentRangeUpdatedSignal signal
= new TmfExperimentRangeUpdatedSignal(this, this, timeRange
);
453 // Broadcast in separate thread to prevent deadlock
463 final Thread thread
= new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
464 private ITmfTimestamp safeTimestamp
= null;
465 private ITmfTimestamp lastSafeTimestamp
= null;
466 private TmfTimeRange timeRange
= null;
470 while (!executorIsShutdown()) {
471 if (!getIndexer().isIndexing()) {
472 ITmfTimestamp startTimestamp
= TmfTimestamp
.BIG_CRUNCH
;
473 ITmfTimestamp endTimestamp
= TmfTimestamp
.BIG_BANG
;
474 for (final ITmfTrace trace
: fTraces
) {
475 if (trace
.getStartTime().compareTo(startTimestamp
) < 0) {
476 startTimestamp
= trace
.getStartTime();
478 if (trace
.getStreamingInterval() != 0 && trace
.getEndTime().compareTo(endTimestamp
) > 0) {
479 endTimestamp
= trace
.getEndTime();
482 if (safeTimestamp
!= null && (lastSafeTimestamp
== null || safeTimestamp
.compareTo(lastSafeTimestamp
, false) > 0)) {
483 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
484 lastSafeTimestamp
= safeTimestamp
;
488 safeTimestamp
= endTimestamp
;
489 if (timeRange
!= null) {
490 final TmfExperimentRangeUpdatedSignal signal
=
491 new TmfExperimentRangeUpdatedSignal(TmfExperiment
.this, TmfExperiment
.this, timeRange
);
496 Thread
.sleep(getStreamingInterval());
497 } catch (final InterruptedException e
) {
507 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
510 public long getStreamingInterval() {
512 for (final ITmfTrace trace
: fTraces
) {
513 interval
= Math
.max(interval
, trace
.getStreamingInterval());
518 // ------------------------------------------------------------------------
520 // ------------------------------------------------------------------------
522 private Integer fEndSynchReference
;
525 * Signal handler for the TmfExperimentSelectedSignal signal
527 * @param signal The incoming signal
530 public void experimentSelected(final TmfExperimentSelectedSignal signal
) {
531 final TmfExperiment experiment
= signal
.getExperiment();
532 if (experiment
== this) {
533 setCurrentExperiment(experiment
);
534 fEndSynchReference
= Integer
.valueOf(signal
.getReference());
539 * Signal handler for the TmfEndSynchSignal signal
541 * @param signal The incoming signal
544 public void endSync(final TmfEndSynchSignal signal
) {
545 if (fEndSynchReference
!= null && fEndSynchReference
.intValue() == signal
.getReference()) {
546 fEndSynchReference
= null;
547 initializeStreamingMonitor();
552 * Signal handler for the TmfTraceUpdatedSignal signal
554 * @param signal The incoming signal
557 public void traceUpdated(final TmfTraceUpdatedSignal signal
) {
558 if (signal
.getTrace() == this) {
559 broadcast(new TmfExperimentUpdatedSignal(this, this));
564 * Signal handler for the TmfExperimentRangeUpdatedSignal signal
566 * @param signal The incoming signal
569 public void experimentRangeUpdated(final TmfExperimentRangeUpdatedSignal signal
) {
570 if (signal
.getExperiment() == this) {
571 getIndexer().buildIndex(getNbEvents(), signal
.getRange(), false);