1 /*******************************************************************************
2 * Copyright (c) 2009, 2010, 2012, 2013 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 * Patrick Tasse - Updated for removal of context clone
13 * Patrick Tasse - Updated for ranks in experiment location
14 *******************************************************************************/
16 package org
.eclipse
.linuxtools
.tmf
.core
.trace
;
18 import org
.eclipse
.core
.resources
.IFile
;
19 import org
.eclipse
.core
.resources
.IProject
;
20 import org
.eclipse
.core
.resources
.IResource
;
21 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfExperimentContext
;
22 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfExperimentLocation
;
23 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfLocationArray
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimeRange
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TmfTraceException
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfDataRequest
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfEventRequest
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfClearExperimentSignal
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceRangeUpdatedSignal
;
37 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
38 * that are part of a tracing experiment.
41 * @author Francois Chouinard
43 public class TmfExperiment
extends TmfTrace
implements ITmfEventParser
{
45 // ------------------------------------------------------------------------
47 // ------------------------------------------------------------------------
50 * The default index page size
52 public static final int DEFAULT_INDEX_PAGE_SIZE
= 5000;
54 // ------------------------------------------------------------------------
56 // ------------------------------------------------------------------------
59 * The set of traces that constitute the experiment
61 protected ITmfTrace
[] fTraces
;
64 * The set of traces that constitute the experiment
66 private boolean fInitialized
= false;
69 * The experiment bookmarks file
71 private IFile fBookmarksFile
;
73 // ------------------------------------------------------------------------
75 // ------------------------------------------------------------------------
78 * @param type the event type
79 * @param id the experiment id
80 * @param traces the experiment set of traces
82 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
) {
83 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
, null);
87 * Constructor of experiment taking type, path, traces and resource
94 * the experiment set of traces
96 * the resource associated to the experiment
98 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
, IResource resource
) {
99 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
, resource
);
104 * @param type the event type
105 * @param path the experiment path
106 * @param traces the experiment set of traces
107 * @param indexPageSize the experiment index page size
109 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
) {
110 this(type
, path
, traces
, indexPageSize
, null);
114 * Full constructor of an experiment, taking the type, path, traces,
115 * indexPageSize and resource
120 * the experiment path
122 * the experiment set of traces
123 * @param indexPageSize
124 * the experiment index page size
126 * the resource associated to the experiment
128 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
, IResource resource
) {
129 setCacheSize(indexPageSize
);
130 setStreamingInterval(0);
131 setIndexer(new TmfCheckpointIndexer(this, indexPageSize
));
134 super.initialize(resource
, path
, type
);
135 } catch (TmfTraceException e
) {
143 * Clears the experiment
146 public synchronized void dispose() {
148 // Clean up the index if applicable
149 if (getIndexer() != null) {
150 getIndexer().dispose();
153 if (fTraces
!= null) {
154 for (final ITmfTrace trace
: fTraces
) {
163 * @param signal the clear view signal
167 public void handleClearExperimentSignal(TmfClearExperimentSignal signal
) {
171 // ------------------------------------------------------------------------
172 // ITmfTrace - Initializers
173 // ------------------------------------------------------------------------
176 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class)
179 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> type
) {
183 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
186 public boolean validate(final IProject project
, final String path
) {
190 // ------------------------------------------------------------------------
192 // ------------------------------------------------------------------------
195 * Get the list of traces. Handle with care...
197 * @return the experiment traces
199 public ITmfTrace
[] getTraces() {
204 * Returns the timestamp of the event at the requested index. If none,
207 * @param index the event index (rank)
208 * @return the corresponding event timestamp
210 public ITmfTimestamp
getTimestamp(final int index
) {
211 final ITmfContext context
= seekEvent(index
);
212 final ITmfEvent event
= getNext(context
);
214 return (event
!= null) ? event
.getTimestamp() : null;
218 * Set the file to be used for bookmarks on this experiment
220 * @param file the bookmarks file
222 public void setBookmarksFile(final IFile file
) {
223 fBookmarksFile
= file
;
227 * Get the file used for bookmarks on this experiment
229 * @return the bookmarks file or null if none is set
231 public IFile
getBookmarksFile() {
232 return fBookmarksFile
;
235 // ------------------------------------------------------------------------
236 // Request management
237 // ------------------------------------------------------------------------
243 public synchronized ITmfContext
armRequest(final ITmfDataRequest request
) {
245 // Make sure we have something to read from
246 if (fTraces
== null) {
250 if (request
instanceof ITmfEventRequest
251 && !TmfTimestamp
.BIG_BANG
.equals(((ITmfEventRequest
) request
).getRange().getStartTime())
252 && request
.getIndex() == 0)
254 final ITmfContext context
= seekEvent(((ITmfEventRequest
) request
).getRange().getStartTime());
255 ((ITmfEventRequest
) request
).setStartIndex((int) context
.getRank());
260 return seekEvent(request
.getIndex());
263 // ------------------------------------------------------------------------
264 // ITmfTrace trace positioning
265 // ------------------------------------------------------------------------
269 * Returns a brand new context based on the location provided and
270 * initializes the event queues
272 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
275 public synchronized ITmfContext
seekEvent(final ITmfLocation location
) {
276 // Validate the location
277 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
278 return null; // Throw an exception?
280 // Make sure we have something to read from
281 if (fTraces
== null) {
285 // Initialize the location array if necessary
286 TmfLocationArray locationArray
= ((location
== null) ?
287 new TmfLocationArray(fTraces
.length
) :
288 ((TmfExperimentLocation
) location
).getLocationInfo());
290 ITmfLocation
[] locations
= locationArray
.getLocations();
291 long[] ranks
= locationArray
.getRanks();
293 // Create and populate the context's traces contexts
294 final TmfExperimentContext context
= new TmfExperimentContext(fTraces
.length
);
296 // Position the traces
298 for (int i
= 0; i
< fTraces
.length
; i
++) {
299 // Get the relevant trace attributes
300 final ITmfContext traceContext
= fTraces
[i
].seekEvent(locations
[i
]);
301 context
.getContexts()[i
] = traceContext
;
302 traceContext
.setRank(ranks
[i
]);
303 locations
[i
] = traceContext
.getLocation(); // update location after seek
304 context
.getEvents()[i
] = fTraces
[i
].getNext(traceContext
);
309 context
.setLocation(new TmfExperimentLocation(new TmfLocationArray(locations
, ranks
)));
310 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
311 context
.setRank(rank
);
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(Math
.round(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
) {
336 TmfLocationArray locationArray
= ((TmfExperimentLocation
) location
).getLocationInfo();
337 for (int i
= 0; i
< locationArray
.size(); i
++) {
338 rank
+= locationArray
.getRank(i
);
340 return (double) rank
/ getNbEvents();
346 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentLocation()
349 public ITmfLocation
getCurrentLocation() {
354 // ------------------------------------------------------------------------
355 // ITmfTrace trace positioning
356 // ------------------------------------------------------------------------
359 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser#parseEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
362 public synchronized ITmfEvent
parseEvent(final ITmfContext context
) {
363 final ITmfContext tmpContext
= seekEvent(context
.getLocation());
364 final ITmfEvent event
= getNext(tmpContext
);
369 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#getNext(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
372 public synchronized ITmfEvent
getNext(ITmfContext context
) {
374 // Validate the context
375 if (!(context
instanceof TmfExperimentContext
)) {
376 return null; // Throw an exception?
379 // Make sure that we have something to read from
380 if (fTraces
== null) {
384 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
386 // If an event was consumed previously, first get the next one from that trace
387 final int lastTrace
= expContext
.getLastTrace();
388 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
389 final ITmfContext traceContext
= expContext
.getContexts()[lastTrace
];
390 expContext
.getEvents()[lastTrace
] = fTraces
[lastTrace
].getNext(traceContext
);
391 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
394 // Scan the candidate events and identify the "next" trace to read from
395 int trace
= TmfExperimentContext
.NO_TRACE
;
396 ITmfTimestamp timestamp
= TmfTimestamp
.BIG_CRUNCH
;
397 for (int i
= 0; i
< fTraces
.length
; i
++) {
398 final ITmfEvent event
= expContext
.getEvents()[i
];
399 if (event
!= null && event
.getTimestamp() != null) {
400 final ITmfTimestamp otherTS
= event
.getTimestamp();
401 if (otherTS
.compareTo(timestamp
, true) < 0) {
408 ITmfEvent event
= null;
409 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
410 event
= expContext
.getEvents()[trace
];
412 updateAttributes(expContext
, event
.getTimestamp());
413 expContext
.increaseRank();
414 expContext
.setLastTrace(trace
);
415 final ITmfContext traceContext
= expContext
.getContexts()[trace
];
417 // Update the experiment location
418 TmfLocationArray locationArray
= new TmfLocationArray(
419 ((TmfExperimentLocation
) expContext
.getLocation()).getLocationInfo(),
420 trace
, traceContext
.getLocation(), traceContext
.getRank());
421 expContext
.setLocation(new TmfExperimentLocation(locationArray
));
431 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#getInitialRangeOffset()
437 public ITmfTimestamp
getInitialRangeOffset() {
438 if ((fTraces
== null) || (fTraces
.length
== 0)) {
439 return super.getInitialRangeOffset();
442 ITmfTimestamp initTs
= TmfTimestamp
.BIG_CRUNCH
;
443 for (int i
= 0; i
< fTraces
.length
; i
++) {
444 ITmfTimestamp ts
= fTraces
[i
].getInitialRangeOffset();
445 if (ts
.compareTo(initTs
) < 0) {
453 * @see java.lang.Object#toString()
456 @SuppressWarnings("nls")
457 public synchronized 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
);
479 final TmfTimeRange timeRange
= new TmfTimeRange(event
.getTimestamp(), TmfTimestamp
.BIG_CRUNCH
);
480 final TmfTraceRangeUpdatedSignal signal
= new TmfTraceRangeUpdatedSignal(this, this, timeRange
);
482 // Broadcast in separate thread to prevent deadlock
492 final Thread thread
= new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
493 private ITmfTimestamp safeTimestamp
= null;
494 private ITmfTimestamp lastSafeTimestamp
= null;
495 private TmfTimeRange timeRange
= null;
499 while (!executorIsShutdown()) {
500 if (!getIndexer().isIndexing()) {
501 ITmfTimestamp startTimestamp
= TmfTimestamp
.BIG_CRUNCH
;
502 ITmfTimestamp endTimestamp
= TmfTimestamp
.BIG_BANG
;
503 for (final ITmfTrace trace
: fTraces
) {
504 if (trace
.getStartTime().compareTo(startTimestamp
) < 0) {
505 startTimestamp
= trace
.getStartTime();
507 if (trace
.getStreamingInterval() != 0 && trace
.getEndTime().compareTo(endTimestamp
) > 0) {
508 endTimestamp
= trace
.getEndTime();
511 if (safeTimestamp
!= null && (lastSafeTimestamp
== null || safeTimestamp
.compareTo(lastSafeTimestamp
, false) > 0)) {
512 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
513 lastSafeTimestamp
= safeTimestamp
;
517 safeTimestamp
= endTimestamp
;
518 if (timeRange
!= null) {
519 final TmfTraceRangeUpdatedSignal signal
=
520 new TmfTraceRangeUpdatedSignal(TmfExperiment
.this, TmfExperiment
.this, timeRange
);
525 Thread
.sleep(getStreamingInterval());
526 } catch (final InterruptedException e
) {
536 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
539 public long getStreamingInterval() {
541 for (final ITmfTrace trace
: fTraces
) {
542 interval
= Math
.max(interval
, trace
.getStreamingInterval());
547 // ------------------------------------------------------------------------
549 // ------------------------------------------------------------------------
552 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#traceOpened(org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal)
556 public void traceOpened(TmfTraceOpenedSignal signal
) {
557 if (signal
.getTrace() == this) {
558 initializeStreamingMonitor();