1 /*******************************************************************************
2 * Copyright (c) 2009, 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
.core
.runtime
.IStatus
;
22 import org
.eclipse
.core
.runtime
.Status
;
23 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfExperimentContext
;
24 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfExperimentLocation
;
25 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.trace
.TmfLocationArray
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TmfTraceException
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfDataRequest
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfEventRequest
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceRangeUpdatedSignal
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.indexer
.checkpoint
.TmfCheckpointIndexer
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.location
.ITmfLocation
;
40 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
41 * that are part of a tracing experiment.
44 * @author Francois Chouinard
46 public class TmfExperiment
extends TmfTrace
implements ITmfEventParser
{
48 // ------------------------------------------------------------------------
50 // ------------------------------------------------------------------------
53 * The default index page size
55 public static final int DEFAULT_INDEX_PAGE_SIZE
= 5000;
57 // ------------------------------------------------------------------------
59 // ------------------------------------------------------------------------
62 * The set of traces that constitute the experiment
64 protected ITmfTrace
[] fTraces
;
67 * The set of traces that constitute the experiment
69 private boolean fInitialized
= false;
72 * The experiment bookmarks file
74 private IFile fBookmarksFile
;
76 // ------------------------------------------------------------------------
78 // ------------------------------------------------------------------------
81 * @param type the event type
82 * @param id the experiment id
83 * @param traces the experiment set of traces
85 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
) {
86 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
, null);
90 * Constructor of experiment taking type, path, traces and resource
97 * the experiment set of traces
99 * the resource associated to the experiment
101 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String id
, final ITmfTrace
[] traces
, IResource resource
) {
102 this(type
, id
, traces
, DEFAULT_INDEX_PAGE_SIZE
, resource
);
107 * @param type the event type
108 * @param path the experiment path
109 * @param traces the experiment set of traces
110 * @param indexPageSize the experiment index page size
112 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
) {
113 this(type
, path
, traces
, indexPageSize
, null);
117 * Full constructor of an experiment, taking the type, path, traces,
118 * indexPageSize and resource
123 * the experiment path
125 * the experiment set of traces
126 * @param indexPageSize
127 * the experiment index page size
129 * the resource associated to the experiment
131 public TmfExperiment(final Class
<?
extends ITmfEvent
> type
, final String path
, final ITmfTrace
[] traces
, final int indexPageSize
, IResource resource
) {
132 setCacheSize(indexPageSize
);
133 setStreamingInterval(0);
134 setIndexer(new TmfCheckpointIndexer(this, indexPageSize
));
137 super.initialize(resource
, path
, type
);
138 } catch (TmfTraceException e
) {
146 * Clears the experiment
149 public synchronized void dispose() {
151 // Clean up the index if applicable
152 if (getIndexer() != null) {
153 getIndexer().dispose();
156 if (fTraces
!= null) {
157 for (final ITmfTrace trace
: fTraces
) {
165 // ------------------------------------------------------------------------
166 // ITmfTrace - Initializers
167 // ------------------------------------------------------------------------
170 public void initTrace(final IResource resource
, final String path
, final Class
<?
extends ITmfEvent
> type
) {
177 public IStatus
validate(final IProject project
, final String path
) {
178 return Status
.OK_STATUS
;
181 // ------------------------------------------------------------------------
183 // ------------------------------------------------------------------------
186 * Get the traces contained in this experiment.
188 * @return The array of contained traces
190 public ITmfTrace
[] getTraces() {
195 * Returns the timestamp of the event at the requested index. If none,
198 * @param index the event index (rank)
199 * @return the corresponding event timestamp
202 public ITmfTimestamp
getTimestamp(final int index
) {
203 final ITmfContext context
= seekEvent(index
);
204 final ITmfEvent event
= getNext(context
);
206 return (event
!= null) ? event
.getTimestamp() : null;
210 * Set the file to be used for bookmarks on this experiment
212 * @param file the bookmarks file
214 public void setBookmarksFile(final IFile file
) {
215 fBookmarksFile
= file
;
219 * Get the file used for bookmarks on this experiment
221 * @return the bookmarks file or null if none is set
223 public IFile
getBookmarksFile() {
224 return fBookmarksFile
;
227 // ------------------------------------------------------------------------
228 // Request management
229 // ------------------------------------------------------------------------
235 public synchronized ITmfContext
armRequest(final ITmfDataRequest request
) {
237 // Make sure we have something to read from
238 if (fTraces
== null) {
242 if (request
instanceof ITmfEventRequest
243 && !TmfTimestamp
.BIG_BANG
.equals(((ITmfEventRequest
) request
).getRange().getStartTime())
244 && request
.getIndex() == 0)
246 final ITmfContext context
= seekEvent(((ITmfEventRequest
) request
).getRange().getStartTime());
247 ((ITmfEventRequest
) request
).setStartIndex((int) context
.getRank());
252 return seekEvent(request
.getIndex());
255 // ------------------------------------------------------------------------
256 // ITmfTrace trace positioning
257 // ------------------------------------------------------------------------
263 public synchronized ITmfContext
seekEvent(final ITmfLocation location
) {
264 // Validate the location
265 if (location
!= null && !(location
instanceof TmfExperimentLocation
)) {
266 return null; // Throw an exception?
268 // Make sure we have something to read from
269 if (fTraces
== null) {
273 // Initialize the location array if necessary
274 TmfLocationArray locationArray
= ((location
== null) ?
275 new TmfLocationArray(fTraces
.length
) :
276 ((TmfExperimentLocation
) location
).getLocationInfo());
278 ITmfLocation
[] locations
= locationArray
.getLocations();
279 long[] ranks
= locationArray
.getRanks();
281 // Create and populate the context's traces contexts
282 final TmfExperimentContext context
= new TmfExperimentContext(fTraces
.length
);
284 // Position the traces
286 for (int i
= 0; i
< fTraces
.length
; i
++) {
287 // Get the relevant trace attributes
288 final ITmfContext traceContext
= fTraces
[i
].seekEvent(locations
[i
]);
289 context
.getContexts()[i
] = traceContext
;
290 traceContext
.setRank(ranks
[i
]);
291 locations
[i
] = traceContext
.getLocation(); // update location after seek
292 context
.getEvents()[i
] = fTraces
[i
].getNext(traceContext
);
297 context
.setLocation(new TmfExperimentLocation(new TmfLocationArray(locations
, ranks
)));
298 context
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
299 context
.setRank(rank
);
304 // ------------------------------------------------------------------------
305 // ITmfTrace - SeekEvent operations (returning a trace context)
306 // ------------------------------------------------------------------------
309 public ITmfContext
seekEvent(final double ratio
) {
310 final ITmfContext context
= seekEvent(Math
.round(ratio
* getNbEvents()));
318 public double getLocationRatio(final ITmfLocation location
) {
319 if (location
instanceof TmfExperimentLocation
) {
321 TmfLocationArray locationArray
= ((TmfExperimentLocation
) location
).getLocationInfo();
322 for (int i
= 0; i
< locationArray
.size(); i
++) {
323 rank
+= locationArray
.getRank(i
);
325 return (double) rank
/ getNbEvents();
334 public ITmfLocation
getCurrentLocation() {
339 // ------------------------------------------------------------------------
340 // ITmfTrace trace positioning
341 // ------------------------------------------------------------------------
344 public synchronized ITmfEvent
parseEvent(final ITmfContext context
) {
345 final ITmfContext tmpContext
= seekEvent(context
.getLocation());
346 final ITmfEvent event
= getNext(tmpContext
);
351 public synchronized ITmfEvent
getNext(ITmfContext context
) {
353 // Validate the context
354 if (!(context
instanceof TmfExperimentContext
)) {
355 return null; // Throw an exception?
358 // Make sure that we have something to read from
359 if (fTraces
== null) {
363 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
365 // If an event was consumed previously, first get the next one from that trace
366 final int lastTrace
= expContext
.getLastTrace();
367 if (lastTrace
!= TmfExperimentContext
.NO_TRACE
) {
368 final ITmfContext traceContext
= expContext
.getContexts()[lastTrace
];
369 expContext
.getEvents()[lastTrace
] = fTraces
[lastTrace
].getNext(traceContext
);
370 expContext
.setLastTrace(TmfExperimentContext
.NO_TRACE
);
373 // Scan the candidate events and identify the "next" trace to read from
374 int trace
= TmfExperimentContext
.NO_TRACE
;
375 ITmfTimestamp timestamp
= TmfTimestamp
.BIG_CRUNCH
;
376 for (int i
= 0; i
< fTraces
.length
; i
++) {
377 final ITmfEvent event
= expContext
.getEvents()[i
];
378 if (event
!= null && event
.getTimestamp() != null) {
379 final ITmfTimestamp otherTS
= event
.getTimestamp();
380 if (otherTS
.compareTo(timestamp
, true) < 0) {
387 ITmfEvent event
= null;
388 if (trace
!= TmfExperimentContext
.NO_TRACE
) {
389 event
= expContext
.getEvents()[trace
];
391 updateAttributes(expContext
, event
.getTimestamp());
392 expContext
.increaseRank();
393 expContext
.setLastTrace(trace
);
394 final ITmfContext traceContext
= expContext
.getContexts()[trace
];
396 // Update the experiment location
397 TmfLocationArray locationArray
= new TmfLocationArray(
398 ((TmfExperimentLocation
) expContext
.getLocation()).getLocationInfo(),
399 trace
, traceContext
.getLocation(), traceContext
.getRank());
400 expContext
.setLocation(new TmfExperimentLocation(locationArray
));
413 public ITmfTimestamp
getInitialRangeOffset() {
414 if ((fTraces
== null) || (fTraces
.length
== 0)) {
415 return super.getInitialRangeOffset();
418 ITmfTimestamp initTs
= TmfTimestamp
.BIG_CRUNCH
;
419 for (int i
= 0; i
< fTraces
.length
; i
++) {
420 ITmfTimestamp ts
= fTraces
[i
].getInitialRangeOffset();
421 if (ts
.compareTo(initTs
) < 0) {
429 @SuppressWarnings("nls")
430 public synchronized String
toString() {
431 return "[TmfExperiment (" + getName() + ")]";
434 // ------------------------------------------------------------------------
436 // ------------------------------------------------------------------------
438 private synchronized void initializeStreamingMonitor() {
445 if (getStreamingInterval() == 0) {
446 final ITmfContext context
= seekEvent(0);
447 final ITmfEvent event
= getNext(context
);
452 final TmfTimeRange timeRange
= new TmfTimeRange(event
.getTimestamp(), TmfTimestamp
.BIG_CRUNCH
);
453 final TmfTraceRangeUpdatedSignal signal
= new TmfTraceRangeUpdatedSignal(this, this, timeRange
);
455 // Broadcast in separate thread to prevent deadlock
465 final Thread thread
= new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
466 private ITmfTimestamp safeTimestamp
= null;
467 private ITmfTimestamp lastSafeTimestamp
= null;
468 private TmfTimeRange timeRange
= null;
472 while (!executorIsShutdown()) {
473 if (!getIndexer().isIndexing()) {
474 ITmfTimestamp startTimestamp
= TmfTimestamp
.BIG_CRUNCH
;
475 ITmfTimestamp endTimestamp
= TmfTimestamp
.BIG_BANG
;
476 for (final ITmfTrace trace
: fTraces
) {
477 if (trace
.getStartTime().compareTo(startTimestamp
) < 0) {
478 startTimestamp
= trace
.getStartTime();
480 if (trace
.getStreamingInterval() != 0 && trace
.getEndTime().compareTo(endTimestamp
) > 0) {
481 endTimestamp
= trace
.getEndTime();
484 if (safeTimestamp
!= null && (lastSafeTimestamp
== null || safeTimestamp
.compareTo(lastSafeTimestamp
, false) > 0)) {
485 timeRange
= new TmfTimeRange(startTimestamp
, safeTimestamp
);
486 lastSafeTimestamp
= safeTimestamp
;
490 safeTimestamp
= endTimestamp
;
491 if (timeRange
!= null) {
492 final TmfTraceRangeUpdatedSignal signal
=
493 new TmfTraceRangeUpdatedSignal(TmfExperiment
.this, TmfExperiment
.this, timeRange
);
498 Thread
.sleep(getStreamingInterval());
499 } catch (final InterruptedException e
) {
509 public long getStreamingInterval() {
511 for (final ITmfTrace trace
: fTraces
) {
512 interval
= Math
.max(interval
, trace
.getStreamingInterval());
517 // ------------------------------------------------------------------------
519 // ------------------------------------------------------------------------
523 public void traceOpened(TmfTraceOpenedSignal signal
) {
524 if (signal
.getTrace() == this) {
525 initializeStreamingMonitor();